GD32F103/303串口+空闲中断连续接收数据

发布时间:2022-08-19 12:29

头文件

#ifndef _UART_H_
#define _UART_H_

#include "stdint.h"
#include "gd32f30x.h"
#define CACHE_NUM 128



//数据接收处理函数
typedef void (*recv_hanled)(uint8_t *data, uint16_t len);

typedef struct
{

    uint32_t usart_periph;			//外设名称
    uint32_t dma_periph;				//dma 外设
    dma_channel_enum dma_channelx;//dma外设通道
    uint8_t dma_nvic_irq; 			//dma中断号
    uint8_t uart_nvic_irq;			//串口中断号
    uint8_t dma_or_idle;				//传输完成标记和收到一帧数据标记dm
    uint16_t data_num;					//已经接收到的数据量
    uint8_t uart_rx_buffers[CACHE_NUM];//接收数据缓冲区
    recv_hanled hanled_fun;			//数据接收处理函数
} uart_dam_t;


//初始化串口涉及的时钟和gpio gpio USART/UART
void bsp_uart_gpio_rcu_init(uint32_t usart_periph);

/*基本初始化函数*/
void bsp_uart_usart_base_init(uint32_t usart_periph);

//串口相关自定义结构初始化
uart_dam_t * init_uart_dma_struct(uint32_t usart_periph);

//使能串口中断
void bsp_uart_enable_uart_interrupt(uart_dam_t *puart_dma);

//dma 外设初始化
int bsp_uart_dma_nvic_init(uart_dam_t *puart_dma);

//注册一个处理函数
int bsp_uart_register_handle(uart_dam_t *puart_dma, recv_hanled hanled_fun);

循环调用函数,处理串口信息
void bsp_uart_dma_procees(uint32_t tick);
#endif

源文件

#include "uart.h"
#include "stdio.h"
#include "gd32f30x.h"




//每个串口外设一个自定义结构

uart_dam_t uart0_dma;
uart_dam_t uart1_dma;
uart_dam_t uart2_dma;
uart_dam_t uart3_dma;

//接收到的数据个数
volatile uint16_t uart_rxcount[5];
//串口空闲或缓冲器慢标志
volatile uint8_t idle_or_full = 0;

/* 重定向printf函数 */
int fputc(int ch, FILE *f)
{
    int cnt = 1000;
    usart_data_transmit(USART0, (uint8_t)ch);

    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE) && cnt--);


    usart_data_transmit(USART1, (uint8_t)ch);
    cnt = 1000;

    while(RESET == usart_flag_get(USART1, USART_FLAG_TBE) && cnt--);

    return ch;
}
//初始化自定义结构体
uart_dam_t * init_uart_dma_struct(uint32_t usart_periph)
{
		//UART0 DMA0-CH4
		//UART1 DMA0-CH5
		//UART2-DMA0-CH2
		//UART3-DMA1-CH2


    uart_dam_t *puart_dma = NULL;


    if(usart_periph == USART0)
    {
        puart_dma = &uart0_dma;
        puart_dma->dma_periph = DMA0;
        puart_dma->dma_channelx = DMA_CH4;
        puart_dma->dma_nvic_irq = DMA0_Channel4_IRQn;
        puart_dma->uart_nvic_irq = USART0_IRQn;
    }
    else if(usart_periph == USART1)
    {
        puart_dma = &uart1_dma;
        puart_dma->dma_periph = DMA0;
        puart_dma->dma_channelx = DMA_CH5;
        puart_dma->dma_nvic_irq = DMA0_Channel5_IRQn;
        puart_dma->uart_nvic_irq = USART1_IRQn;
    }
    else if(usart_periph == USART2)
    {
        puart_dma = &uart2_dma;
        puart_dma->dma_periph = DMA0;
        puart_dma->dma_channelx = DMA_CH2;
        puart_dma->dma_nvic_irq = DMA0_Channel2_IRQn;
        puart_dma->uart_nvic_irq = USART2_IRQn;
    }
    else if(usart_periph == UART3)
    {
        puart_dma = &uart3_dma;
        puart_dma->dma_periph = DMA1;
        puart_dma->dma_channelx = DMA_CH2;
        puart_dma->dma_nvic_irq = DMA0_Channel2_IRQn;
        puart_dma->uart_nvic_irq = UART3_IRQn;
    }

    puart_dma->usart_periph = usart_periph;
    return puart_dma;
}


/*!
    \brief      初始化串口涉及的时钟和gpio gpio USART/UART
    \param[in]  usart_periph: USARTx(x=0,1,2)/UARTx(x=3,4)
    \param[out] none
    \retval     none
*/

void bsp_uart_gpio_rcu_init(uint32_t usart_periph)
{
    /*********************串口0********************/
    if(usart_periph == USART0)
    {
        /* 使能串口时钟 */
        rcu_periph_clock_enable(RCU_USART0);
        /* 使能gpio时钟 */
        rcu_periph_clock_enable(RCU_GPIOA);

        /* gpio IO 初始化发送引脚 */
        gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
        /* 初始化接收引脚 */
        gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    }
    /*********************串口0********************/

    /*********************串口1********************/
    else if(usart_periph == USART1)
    {
        /* 使能串口时钟 */
        rcu_periph_clock_enable(RCU_USART1);

        /* 使能gpio时钟 */
        rcu_periph_clock_enable(RCU_GPIOA);

        /* gpio IO 初始化发送引脚 */
        gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
        /* 初始化接收引脚 */
        gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
    }
    /*********************串口1********************/

    /*********************串口2********************/
    else if(usart_periph == USART2)
    {
        /* 使能串口时钟 */
        rcu_periph_clock_enable(RCU_USART2);

        /* 使能gpio时钟 */
        rcu_periph_clock_enable(RCU_GPIOB);

        /* gpio IO 初始化发送引脚 */
        gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
        /* 初始化接收引脚 */
        gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

    }
    /*********************串口2********************/

    /*********************串口3********************/
    else if(usart_periph == UART3)
    {
        /* 使能串口时钟 */
        rcu_periph_clock_enable(RCU_UART3);

        /* 使能gpio时钟 */
        rcu_periph_clock_enable(RCU_GPIOC);

        /* gpio IO 初始化发送引脚 */
        gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
        /* 初始化接收引脚 */
        gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

    }
    /*********************串口3********************/

    /*********************串口4********************/
    else if(usart_periph == UART4)
    {
        /* 使能串口时钟 */
        rcu_periph_clock_enable(RCU_UART4);
    }

    /*********************串口4********************/

}

/*基本初始化函数*/
void bsp_uart_usart_base_init(uint32_t usart_periph)
{
    //外设的gpio初始化和时钟初始化
    bsp_uart_gpio_rcu_init(usart_periph);

    /* USART configure 串口参数初始化 */
    usart_deinit(usart_periph);
    //设置波特率
    usart_baudrate_set(usart_periph, 115200U);
    //设置数据长度
    usart_word_length_set(usart_periph, USART_WL_8BIT);
    //设置停止位
    usart_stop_bit_set(usart_periph, USART_STB_1BIT);
    //设置检验位
    usart_parity_config(usart_periph, USART_PM_NONE);
    //硬件流管理 都关闭
    usart_hardware_flow_rts_config(usart_periph, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(usart_periph, USART_CTS_DISABLE);
    //串口接收使能
    usart_receive_config(usart_periph, USART_RECEIVE_ENABLE);
    //串口发送使能
    usart_transmit_config(usart_periph, USART_TRANSMIT_ENABLE);
    //使能串口
    usart_enable(usart_periph);
}


/*
	使能串口中断
*/
void bsp_uart_enable_uart_interrupt(uart_dam_t *puart_dma)
{
    /*中断管理器使能,并分配优先级*/

    nvic_irq_enable(puart_dma->uart_nvic_irq, 1, 1);

    /*清除中断标志*/
    usart_interrupt_flag_clear(puart_dma->usart_periph, USART_INT_FLAG_IDLE);
    /* 使能串口中断 */
    usart_interrupt_enable(puart_dma->usart_periph, USART_INT_IDLE);//空闲中断
}



/*
	功能:DMA 中断接收数据,uart5 不可以使用dma传输数据
	hope_len:希望接收的数据个数
	circulation:是否使用连续模式
*/
int  bsp_uart_dma_nvic_init(uart_dam_t *puart_dma)
{
    dma_parameter_struct dma_init_struct;

    if(puart_dma == NULL)
    {
        return 0;
    }

    /* enable DMA0 clock 使能DMA0 的时钟*/
    if(puart_dma->usart_periph == USART0 ||
            puart_dma->usart_periph == USART1 ||
            puart_dma->usart_periph == USART2)
    {
        rcu_periph_clock_enable(RCU_DMA0);
    }
    else if(puart_dma->usart_periph == UART3)
    {
        rcu_periph_clock_enable(RCU_DMA1);
    }

    //中断管理器开启通道中断
    nvic_irq_enable(puart_dma->dma_nvic_irq, 0, 1);
    // 复位代码指定通道
    dma_deinit(puart_dma->dma_periph, puart_dma->dma_channelx);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY; //外设到内存
    dma_init_struct.memory_addr = (uint32_t)puart_dma->uart_rx_buffers;	//接收缓冲区开始地址
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//内存地址自动增长
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;//数据长度8bit
    dma_init_struct.number = CACHE_NUM;//缓冲区大小
#define USART0_DATA_ADDRESS      ((uint32_t)&USART_DATA(USART0))
    dma_init_struct.periph_addr = USART0_DATA_ADDRESS;//外设寄存器地址
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//外设寄存器地址不自动增加
    dma_init_struct.memory_width = DMA_PERIPHERAL_WIDTH_8BIT;//外输数据宽度
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;//DMA优先级
    dma_init(puart_dma->dma_periph, puart_dma->dma_channelx, &dma_init_struct);
    dma_circulation_enable(puart_dma->dma_periph, puart_dma->dma_channelx);//连续传输

    //数据传输方式不是内存到内存
    dma_memory_to_memory_disable(puart_dma->dma_periph, puart_dma->dma_channelx);

    /* USART DMA0 串口0DMA 数据接收使能 */
    usart_dma_receive_config(puart_dma->usart_periph, USART_DENR_ENABLE);
    /* enable DMA0 串口0 DMA 接收完成中断使能 */
    dma_interrupt_enable(puart_dma->dma_periph, puart_dma->dma_channelx, DMA_INT_FTF);
    /* enable DMA0 启用指定的DMA通道*/
    dma_channel_enable(puart_dma->dma_periph, puart_dma->dma_channelx);
    return 1;
}

/*
	禁止中断和DMA
*/
void  bsp_uart0_init_idle_it_disable()
{
    //禁止中断
    nvic_irq_disable(USART0_IRQn);
    usart_interrupt_disable(USART0, USART_INT_IDLE);//空闲中断
    //禁止DMA
    dma_channel_disable(DMA0, DMA_CH4);

}

/*
	串口0中断处理函数
*/
void USART0_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart0_dma;

    if(RESET != usart_interrupt_flag_get(p_uart_dma->usart_periph, USART_INT_FLAG_IDLE))
    {
        usart_data_receive(p_uart_dma->usart_periph);


        p_uart_dma->data_num = CACHE_NUM - dma_transfer_number_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

        p_uart_dma->dma_or_idle = 1;
        //重新使能dma,重新计算剩余未传输数量
        dma_channel_disable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);
        DMA_CHCNT(p_uart_dma->dma_periph, p_uart_dma->dma_channelx) = CACHE_NUM;
        dma_channel_enable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

    }
}
/*
	串口3中断处理函数
*/
void USART1_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart1_dma;

    if(RESET != usart_interrupt_flag_get(p_uart_dma->usart_periph, USART_INT_FLAG_IDLE))
    {
        usart_data_receive(p_uart_dma->usart_periph);


        p_uart_dma->data_num = CACHE_NUM - dma_transfer_number_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

        p_uart_dma->dma_or_idle = 1;
        //重新使能dma,重新计算剩余未传输数量
        dma_channel_disable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);
        DMA_CHCNT(p_uart_dma->dma_periph, p_uart_dma->dma_channelx) = CACHE_NUM;
        dma_channel_enable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

    }
}
/*
	串口2中断处理函数
*/
void USART2_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart2_dma;

    if(RESET != usart_interrupt_flag_get(p_uart_dma->usart_periph, USART_INT_FLAG_IDLE))
    {
        usart_data_receive(p_uart_dma->usart_periph);


        p_uart_dma->data_num = CACHE_NUM - dma_transfer_number_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

        p_uart_dma->dma_or_idle = 1;
        //重新使能dma,重新计算剩余未传输数量
        dma_channel_disable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);
        DMA_CHCNT(p_uart_dma->dma_periph, p_uart_dma->dma_channelx) = CACHE_NUM;
        dma_channel_enable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

    }
}
/*
	串口3中断处理函数
*/
void UART3_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart3_dma;

    if(RESET != usart_interrupt_flag_get(p_uart_dma->usart_periph, USART_INT_FLAG_IDLE))
    {
        usart_data_receive(p_uart_dma->usart_periph);


        p_uart_dma->data_num = CACHE_NUM - dma_transfer_number_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

        p_uart_dma->dma_or_idle = 1;
        //重新使能dma,重新计算剩余未传输数量
        dma_channel_disable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);
        DMA_CHCNT(p_uart_dma->dma_periph, p_uart_dma->dma_channelx) = CACHE_NUM;
        dma_channel_enable(p_uart_dma->dma_periph, p_uart_dma->dma_channelx);

    }
}
/*串口0dma*/
void DMA0_Channel4_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart0_dma;

    //获取中断标记并判断否是置位
    if(dma_interrupt_flag_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_FTF))
    {
        //清除dma中断标记
        dma_interrupt_flag_clear(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_G);
        p_uart_dma->dma_or_idle = SET;
    }

}
/*串口1 dma*/
void DMA0_Channel5_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart1_dma;

    //获取中断标记并判断否是置位
    if(dma_interrupt_flag_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_FTF))
    {
        //清除dma中断标记
        dma_interrupt_flag_clear(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_G);
        p_uart_dma->dma_or_idle = SET;
    }

}
/*串口2 dma*/
void DMA0_Channel2_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart2_dma;

    //获取中断标记并判断否是置位
    if(dma_interrupt_flag_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_FTF))
    {
        //清除dma中断标记
        dma_interrupt_flag_clear(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_G);
        p_uart_dma->dma_or_idle = SET;
    }

}
/*串口3 dma*/
void DMA1_Channel2_IRQHandler(void)
{
    uart_dam_t *p_uart_dma = &uart3_dma;

    //获取中断标记并判断否是置位
    if(dma_interrupt_flag_get(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_FTF))
    {
        //清除dma中断标记
        dma_interrupt_flag_clear(p_uart_dma->dma_periph, p_uart_dma->dma_channelx, DMA_INT_FLAG_G);
        p_uart_dma->dma_or_idle = SET;
    }

}

/*注册一个处理函数*/
int bsp_uart_register_handle(uart_dam_t *puart_dma, recv_hanled hanled_fun)
{

    puart_dma->hanled_fun = hanled_fun;
}

//循环调用函数用于处理各个串口数据
void bsp_uart_dma_procees(uint32_t tick)
{
    if(uart0_dma.dma_or_idle)
    {
        uart_dam_t *puart_dma = &uart0_dma;
        puart_dma->dma_or_idle = 0;
        puart_dma->hanled_fun(puart_dma->uart_rx_buffers, puart_dma->data_num);
        puart_dma->data_num = 0;
    }
    else if(uart1_dma.dma_or_idle)
    {
        uart_dam_t *puart_dma = &uart1_dma;
        puart_dma->dma_or_idle = 0;
        puart_dma->hanled_fun(puart_dma->uart_rx_buffers, puart_dma->data_num);
        puart_dma->data_num = 0;
    }

    if(uart2_dma.dma_or_idle)
    {
        uart_dam_t *puart_dma = &uart2_dma;
        puart_dma->dma_or_idle = 0;
        puart_dma->hanled_fun(puart_dma->uart_rx_buffers, puart_dma->data_num);
        puart_dma->data_num = 0;
    }

    if(uart3_dma.dma_or_idle)
    {
        uart_dam_t *puart_dma = &uart3_dma;
        puart_dma->dma_or_idle = 0;
        puart_dma->hanled_fun(puart_dma->uart_rx_buffers, puart_dma->data_num);
        puart_dma->data_num = 0;
    }

}

测试

#include "gd32f30x.h"
#include "gd32f303_sys.h"
#include "systick.h"
#include "uart.h"
#include "stdio.h"
#include "adc.h"
#include "button.h"
#include "bsp_gpio.h"
#include "at24cxx.h"

void uart0_recv_hanled(uint8_t *data, uint16_t len)
{
    printf("read len = %d:", len);

    for(int i = 0; i < len; i++)
    {
        printf("%02x ", (int)data[i]);
    }

    printf("\r\n");
}
/*!
	主函数:
*/

int main(void)
{


    /* 配置系统时钟 */
    systick_config();
    //设置中断分组
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
    /* gpio时钟使能*/

    // 配置MCU调试下载使用swd方式,同时将pb3 和PB4 作为普通gpio
    rcu_periph_clock_enable(RCU_AF);
    gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
    //gpio
    bsp_gpio_init();
    //串口初始化
    bsp_uart_gpio_rcu_init(USART0);
    bsp_uart_usart_base_init(USART0);
    //下边是串口的数据接收使用dma方式需要调用和函数
    uart_dam_t *uart_dma = init_uart_dma_struct(USART0);
    bsp_uart_enable_uart_interrupt(uart_dma);
    bsp_uart_dma_nvic_init(uart_dma);
    bsp_uart_register_handle(uart_dma, uart0_recv_hanled);

    // bsp_at24c02_init();
    printf("hello gd32\r\n");
    //初始化ADC
//    adc_init();
//    init_btn();

    BEEP = 0;

    while(1)
    {
        if(tick % 500 == 0)
        {
            LED0 = !LED0;
            LED1 = !LED1;
            LED2 = !LED2;
        }

        //循环调用
        bsp_uart_dma_procees(tick);


    }

}

GD32F103/303串口+空闲中断连续接收数据_第1张图片# 测试图
GD32F103/303串口+空闲中断连续接收数据_第2张图片

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号