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

头文件

#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-CH2uart_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 \retvalnone */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:是否使用连续模式 */ intbsp_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 */ voidbsp_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); }}

【GD32|GD32F103/303串口+空闲中断连续接收数据】GD32|GD32F103/303串口+空闲中断连续接收数据
文章图片
# 测试图
GD32|GD32F103/303串口+空闲中断连续接收数据
文章图片

    推荐阅读