头文件
#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|GD32F405RGT6串口收发--DMA--中断(固件库)
- GD32|GD32F303调试小记(一)之USART(接收中断、接收空闲中断+DMA、发送DMA)
- stm32的两种固件下载模式(JTAG和SWD)
- 嵌入式开发|STM32人脸识别系统设计(程序代码+论文)
- STM32的简单应用|DHT11 温湿度传感器
- 单片机|STM32/KEIL/MDK 查看 FLASH 和 RAM 使用情况
- STM32开发笔记|Keil编译后生成bin文件占用内部Flash的大小,RAM,ROM,Code,RO-data,RW-data,ZI-data
- STM32|Keil/MDK(1)(查看STM32的RAM和ROM使用情况)
- LINUX|【正点原子Linux连载】第五十八章 Linux INPUT子系统实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0