GD32F103串口DMA收发

这两年做嵌入式开发太难了,芯片缺货导致方案不断改改改,之前一直没用过国产MCU,从去年开始也渐渐了解了一下国产MCU。原理大同小异,资料相对来说确实少一点,生态也没那么完善。 这个系列打算把项目过程中的一些经验分享给大家,也作为自己的一个成长记录。如果能给路过的各位带来切实收获,请各位不吝点赞,给作者资以鼓励;如果文章中有错误,也请各位不吝指正,共同学习,共同进步!


串口DMA收发

废话不多说,直接上干货,我用的MCU是GD32F103CBT6,串口使用USART0,对应的GPIO是PA9和PA10。

1.串口IO初始化

代码如下:

static void usart_config(uint32_t baudval)
{rcu_periph_clock_enable(RCU_GPIOA);    //enable GPIO clock, PA9/PA10rcu_periph_clock_enable(RCU_AF);rcu_periph_clock_enable(RCU_USART0);   //enable USART clockgpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);   //PA9--TX0gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);  //PA10--RX0//USART0: 115200usart_deinit(USART0);usart_baudrate_set(USART0, baudval);usart_word_length_set(USART0, USART_WL_8BIT);usart_stop_bit_set(USART0, USART_STB_1BIT);usart_parity_config(USART0, USART_PM_NONE);usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);usart_receive_config(USART0, USART_RECEIVE_ENABLE);usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);usart_enable(USART0);
}

此处串口波特率采用传参方式在初始化串口时传入,实际使用时我用的串口波特率为115200。

2.DMA初始化

关于DMA通道映射详见UserManual 9.4.9 DMA请求映射及DMA各通道请求表。此处一定要仔细,不能搞错,我们使用的是USART0,由表中可知USART_TX对应的是Channel 3,USART_RX对应的是Channel 4。


代码如下:

uint8_t rxbuffer[2]= {'o','k'};
uint8_t txbuffer[10] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};#define USART0_DATA_ADDRESS    ((uint32_t)&USART_DATA(USART0))static void usart_dma_config(void)
{dma_parameter_struct dma_init_struct;/* enable DMA0 clock */rcu_periph_clock_enable(RCU_DMA0);/* deinitialize DMA channel3(USART0 tx) */dma_deinit(DMA0, DMA_CH3);dma_struct_para_init(&dma_init_struct);dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;dma_init_struct.memory_addr = NULL;dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;dma_init_struct.number = ARRAYNUM(txbuffer);dma_init_struct.periph_addr = USART0_DATA_ADDRESS;dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;dma_init(DMA0, DMA_CH3, &dma_init_struct);/* deinitialize DMA channel4 (USART0 rx) */dma_deinit(DMA0, DMA_CH4);dma_struct_para_init(&dma_init_struct);dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;dma_init_struct.memory_addr = (uint32_t)rxbuffer;dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;dma_init_struct.number = ARRAYNUM(rxbuffer);;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_init(DMA0, DMA_CH4, &dma_init_struct);/* configure DMA mode */dma_circulation_disable(DMA0, DMA_CH3);dma_memory_to_memory_disable(DMA0, DMA_CH3);dma_circulation_enable(DMA0, DMA_CH4);dma_memory_to_memory_disable(DMA0, DMA_CH4);/* USART DMA0 enable for reception */usart_dma_receive_config(USART0, USART_DENR_ENABLE);/* enable DMA0 channel4 transfer complete interrupt */dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);/* enable DMA0 channel4 */dma_channel_enable(DMA0, DMA_CH4);/* USART DMA0 enable for transmission */usart_dma_transmit_config(USART0, USART_DENT_ENABLE);/* enable DMA0 channel3 transfer complete interrupt */
//    dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);
//    /* disable DMA0 channel3 */
//    dma_channel_disable(DMA0, DMA_CH3);
}

3. 中断配置

串口接收采用中断方式,所以需要配置中断。
串口发送需要在主函数里根据项目实际需求进行发送,故不采用中断方式。

代码如下:

static void nvic_config(void)
{nvic_priority_group_set(NVIC_PRIGROUP_PRE3_SUB1);nvic_irq_enable(DMA0_Channel4_IRQn, 0, 1);
}

4. 串口初始化

代码如下:

void bsp_usart_init()
{   usart_config(BAUDRATE);nvic_config();usart_dma_config();
}

5. 串口发送函数和printf支持实现

代码如下:

void usart0_dma_send(uint8_t *buffer,uint16_t len)
{dma_channel_disable(DMA0, DMA_CH3);dma_memory_address_config(DMA0, DMA_CH3,(uint32_t)buffer);//设置要发送数据的内存地址dma_transfer_number_config(DMA0, DMA_CH3, len);//一共发送多少个数据dma_channel_enable(DMA0, DMA_CH3);
}int fputc(int ch, FILE *f)
{usart_data_transmit(USART0, (uint8_t)ch);while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));return ch;
}

6. 头文件中的宏定义和函数声明如下

代码如下:

#define BAUDRATE 115200U
//#define BAUDRATE  9600U
#define ARRAYNUM(arr_name)     (uint32_t)(sizeof(arr_name) / sizeof(*(arr_name)))void bsp_usart_init(void);void usart0_dma_send(uint8_t *buffer,uint16_t len);int fputc(int ch, FILE *f);

7. 中断处理

串口接收中断里只需要清对应标志位即可。

void DMA0_Channel4_IRQHandler(void)
{if(dma_interrupt_flag_get(DMA0, DMA_CH4, DMA_INT_FLAG_FTF)){     dma_interrupt_flag_clear(DMA0, DMA_CH4, DMA_INT_FLAG_G);}
}

8. 主函数

主函数里我们采用定时器+计数方式实现1s发送一次txbuffer的数据,当上位机发送数据给串口,数据通过DMA直接存到rxbuffer中。

extern uint8_t txbuffer[10];
extern uint8_t rxbuffer[2];
int main(void){    bsp_usart_init();SysTick_Init();bsp_wdg_init();  volatile uint8_t usartSend_taskTime = 0;for(;;)    {   if(g_u8_taskTimer >= 10)        {               g_u8_taskTimer = g_u8_taskTimer - 10;                  bsp_wdg_feed();         task_10msCycle();       usartSend_taskTime++;if(usartSend_taskTime >= 100){usart0_dma_send(txbuffer, (uint16_t)ARRAYNUM(txbuffer));
//              printf("\n\r%s\n\r", rxbuffer);usartSend_taskTime -=100;         }               }   }
}

9. 执行结果

rxbuffer和txbuffer中初始数据如下:

uint8_t rxbuffer[2]= {'o','k'};
uint8_t txbuffer[10] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};

上位机接收的串口数据:

rxbuff初始数据:

上位机发送字符"lk"后rxbuffer也随之改变:

至此,整个串口DMA收发测试成功。


总结

使用DMA进行数据传输的好处毋庸置疑,可以大大减少CPU的负担,CPU效率也会大大提升。

由上面步骤可知,串口用DMA收发主要分以下几步:

1)串口初始化

2)DMA初始化

3)中断配置

4)发送和接收数据


GD32F103串口DMA收发相关推荐

  1. 【华大测评】+串口DMA收发数据

    串口传输用中断实现的话,要频繁的进入中断函数,这样无疑增加MCU的负担,干扰正常程序的运行,对于一些实时性强的应用,如数字显示应用中,液晶屏显示可能受影响而不能正常显示.用DMA实现串口收发数据,进行 ...

  2. STM32F0系列串口DMA收发数据

    关于STM32F0系列串口DMA收发数据详解 这里用的库函数版本,芯片型号为stm32f030c8t6.在用到串口DMA时,要按以下几个步骤进行. 1.确定使用的串口号,这里,我用的是usart2,对 ...

  3. STM32 串口DMA收发(二)

    STM32 串口DMA收发数据 一.STM32 DMA简介与功能说明 1.STM32F4 DMA简介 DMA(Direct memory access),即直接存储器访问.用于在外设与存储器之间以及存 ...

  4. STM32 进阶教程 15 - 串口DMA收发

    前言 串口操作相信大家一定很熟悉,如果你已经会串口的收发数据,并可以灵活使用轮询及中断方式对串口进行数据收发,那么恭喜你,学完本节内容后,也将可以学会串口的更高级操作方式,DMA方式,DMA操作串口可 ...

  5. 【32单片机学习】(6)STM32串口+DMA收发不定长数据

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1.DMA介绍 2.串口接收数据 3.实验现象 1.实验电路图 2.串口收发不定长数据视频演示 3.OLED 显示接收数据 ...

  6. STM32的串口DMA收发以及双缓冲区的实现

    在使用STM32的UART的DMA功能总结如下: 首先上代码,这里采用STM32 的USART1作为Demo,RX的DMA为DMA1_Channel5,TX的DMA为DMA1_Channel4.初始化 ...

  7. GD32E230F6p6的串口DMA中断收发及printf

    GD32E230F6p6的串口DMA中断收发及printf 简介 一.初始化配置 选择DMA通道 头文件 串口&DMA初始化 二.串口DMA收发及printf DMA发送 DMA收发中断处理 ...

  8. STM32 串口DMA接收 Openmv / K210 整数、小数字符串数据 (基于HAL库)

    目录 前言 一.工程配置 二.串口DMA部分代码 1.源文件UART_DMA.c 2.头文件UART_DMA.h 3.stm32f1xx_it.c的修改 4.串口收发DMA测试 三.字符串数字提取代码 ...

  9. [基于STM32底盘控制与ROS上层导航小车制作] 第五节 实现STM32与ubuntu系统下的ROS串口DMA通信,传输底盘速度等信息

    系列文章目录 第一节 stm32电机驱动与编码器读取反馈 第二节 stm32电机pid控制 第三节 stm32线速度标定 第四节 stm32添加mpu6050得到angle角度 第五节 实现STM32 ...

  10. STM32H7xx 串口DMA发送接收(LL库)

    文章目录 1 前言 2 STM32H7实现 2.1 关键步骤 2.2 注意事项 3 代码仓库 1 前言   关于串口DMA收发实现,不同CPU其套路都是类似的,不同之处在于寄存器配置.依赖BSP库等差 ...

最新文章

  1. 10万视频,所有面部图像均获授权,Facebook创建大规模Deepfake数据集
  2. 【 C 】动态内存分配案例分析
  3. JavaScript学习笔记01【基础——简介、基础语法、运算符、特殊语法、流程控制语句】
  4. MySQL初始化zabbix_【Zabbix】CentOS6.9系统下部署Zabbix-server 3.0
  5. hibernate之工具类
  6. 扩展欧几里得求解ax+by=c的特殊解(模板)
  7. 深入理解Cache工作原理
  8. 用getBoundingClientRect()来获取页面元素的位置
  9. mysql 判断字段为null表示 false 其它为true_日拱一卒,MySQL数据库 常用SQL优化技巧 十一式...
  10. python3之后版本读取网页的内容
  11. 为什么main方法是public static void?
  12. CCF201512-3 画图(100分)
  13. OpenCV图像的编解码读取
  14. [转帖] bat方式遍历目录内的文件
  15. 项目中用了spring这些牛逼的开发技巧,经理请我吃饭了
  16. IAR for MSP430 关于添加自定义头文件的两种方法【转】
  17. 大数据之Zookeeper
  18. 视频自动生成字幕(免费版)
  19. 【二十二】 H.266/VVC | 选择最优的仿射AMVP候选项 | xEstimateAffineAMVP函数
  20. Nightmare Ⅱ(BFS)

热门文章

  1. linux系统鼠标主题下载,Ubuntu Linux鼠标主题:AlkanoMB
  2. 遗传算法matlab_遗传算法 (GA) 进行多参数拟合 【MATLAB】
  3. 开源微信商城java源码_微信小程序商城 带java后台源码
  4. 订餐系统oracle实训报告,网上订餐系统设计报告.doc
  5. navicat下载安装
  6. 坦克大战之继承的实现
  7. 期货跟单软件:大数据排名展示跟随
  8. PLSQL和ORACLE客户端安装
  9. 怎么查看和下载高清谷歌卫星地图
  10. 第6节 蒙特卡罗模拟计算欧式期权价格