【GD32F303红枫派使用手册】第十六节 USART-DMA串口收发实验

16.1 实验内容

通过本实验主要学习以下内容:

  • 串口DMA工作原理
  • 使用DMA进行串口收发

16.2 实验原理

16.2.1 串口DMA工作原理

在前面ADC章节中,我们介绍了DMA的工作原理,这里就不多做介绍。从GD32F303用户手册中可以查到,各串口的TX和RX分别对应DMA的不同通道,比如USART0的TX对应DMA0的通道3,而RX对应DMA0的通道4。

当需要使用DMA发送时,需要配置DMA工作为内存到外设的模式,DMA目标地址需要设置为串口的数据寄存器,当DMA使能后,一旦串口的TBE(发送空)标志位为1,则DMA自动从内存中搬运数据到串口数据寄存器中。

当需要使用DMA接受时,需要配置DMA工作为外设到内存的模式,DMA的源地址需要设置为串口的数据寄存器,当DMA使能,一旦串口收到一个字节数据,RBNE(接受非空)标志位为1,则DMA自动将数据寄存器中的数据搬运到内存中。

16.2.2 串口寄存器介绍

串口有几个非常重要的寄存器需要读者理解,这里单独用一个章节来介绍。

数据寄存器(USART_DATA)

该寄存器虽然只有一个,但内部是映射为发送和接受两个寄存器。

发送时,除了发送数据寄存器,还有一个移位寄存器,当数据写入数据寄存器中,移位寄存器空闲的情况下,数据从数据寄存器中转移到移位寄存器,移位寄存器按照低bit——高bit的顺序将数据移位到IO口上。

接收时,接收到的数据保存在数据寄存器中,CPU或DMA可以从该寄存器中读接收到的数据。

状态寄存器0(USART_STAT0  )

我们需要特别理解TBE、TC、RBNE、IDLE、OREE这几位。

  1. TBE(发送空):这个位置“1”表示现在可以往数据寄存器中写数据了,当移位寄存器空闲时,写入到数据寄存器中的数据则会转移到移位寄存器中,串口开始对外发送数据;
  1. TC(发送完成):发送数据时,当数据寄存器和移位寄存器都为空时,表示所有的数据都已经完成了,则TC置“1”,所以当连续发数据时,最后一个字节从移位寄存器中发送完,TC才会置起。
  1. RBNE(接受非空):当串口接受到一个字节数据,RBNE置“1”,此时CPU可以去数据寄存器中取数据,当使用了DMA接受,DMA自动将数据寄存器中数据搬走,当数据寄存器数据被读走/搬走,RBNE位自动清“0”;
  1. IDLE(空闲):该标志位用于检测接受空闲,当串口接受最后一个字节后,再往后一个字节时间内,没有接受到新的数据,则该位置“1”;

IDLE一般用于串口DMA接受中,DMA接受中,MCU无法知道发送方的数据个数,所以可以通过判断IDLE位(或IDLE中断)来判断发送方一帧数据发送结束了。

  1. OREE(溢出错误):当RBNE置位的情况,又接收到一个字节数据,则OREE位置“1”。

16.3 硬件设计

本实验使用DMA进行串口发送和接收,仍然使用USB转UART接口,硬件设计见上一章。

16.4 代码解析

16.4.1 串口DMA发送函数

在driver_uart.c中定义了串口DMA发送函数driver_uart_dma_transmit:

C
Drv_Err driver_uart_dma_transmit(typdef_uart_struct *uartx,uint8_t *pbuff,uint16_t length)
{Drv_Err uart_state=DRV_ERROR;uint32_t timeout = driver_tick;    while(uartx->uart_control.Com_Flag.Bits.SendState==1){if((timeout+UART_TIMEOUT_MS) <= driver_tick) {              uartx->uart_control.Com_Flag.Bits.SendState=0;return DRV_ERROR;        } }      uartx->uart_control.Com_Flag.Bits.SendSucess=0;uartx->uart_control.Com_Flag.Bits.SendState=1;    uartx->uart_control.p_Send=pbuff;uartx->uart_control.SendSize=length;uartx->uart_control.SendCount=0;    uart_state=driver_dma_flag_wait_timeout(uartx->uart_tx_dma,DMA_FLAG_FTF,SET);     usart_dma_transmit_config(uartx->uart_x,USART_DENT_DISABLE);    driver_dma_start(uartx->uart_tx_dma,pbuff,length);    usart_flag_clear(uartx->uart_x,USART_FLAG_TC);    usart_dma_transmit_config(uartx->uart_x,USART_DENT_ENABLE);    usart_interrupt_enable(uartx->uart_x,USART_INT_TC);return uart_state;    
}

 16.4.2 串口DMA接收函数

在driver_uart.c中定义了串口DMA接收函数driver_uart_dma_receive:

C
Drv_Err driver_uart_dma_receive(typdef_uart_struct *uartx,uint8_t *pbuff,uint16_t length)
{Drv_Err uart_state=DRV_SUCCESS; uint32_t timeout = driver_tick; while(uartx->uart_control.Com_Flag.Bits.RecState==1){if((timeout+UART_TIMEOUT_MS) <= driver_tick) {              uartx->uart_control.Com_Flag.Bits.RecState=0;return DRV_ERROR;        } }    uartx->uart_control.Com_Flag.Bits.RecSuccess=0;uartx->uart_control.Com_Flag.Bits.RecState=1;uartx->uart_control.p_Rec=pbuff;uartx->uart_control.RecSize=length;uartx->uart_control.RecCount=0;       usart_dma_receive_config(uartx->uart_x,USART_DENR_DISABLE);    driver_dma_start(uartx->uart_rx_dma,pbuff,length);USART_STAT0(uartx->uart_x);usart_data_receive(uartx->uart_x);usart_interrupt_flag_clear(uartx->uart_x,USART_INT_FLAG_IDLE);    usart_interrupt_enable(uartx->uart_x,USART_INT_IDLE);        usart_dma_receive_config(uartx->uart_x,USART_DENR_ENABLE);  return uart_state;     
}

16.4.3 main函数实现

以下为main函数代码:

C
int main(void)
{delay_init(); //初始化UART为DMA模式,注册接受完成(IDLE)回调函数BOARD_UART.uart_mode_tx=MODE_DMA;BOARD_UART.uart_mode_rx=MODE_DMA;BOARD_UART.uart_idle_callback=user_receive_complete_callback;       bsp_uart_init(&BOARD_UART);nvic_irq_enable(USART0_IRQn,2,0); delay_ms(1000);printf("uart dma mode sends and receives loopback packets of indefinite length.\r\n"); //配置UART接受,最长100bytedriver_uart_dma_receive(&BOARD_UART,uart_rec_buff,100);while (1){//查询到接受完成回调函数标志if(uart_receive_complete_flag==SET){uart_receive_complete_flag=RESET;//发送刚接受到的数据driver_uart_dma_transmit(&BOARD_UART,uart_send_buff,uart_receive_count);             }}
}

 本例程main函数首先进行了延时函数初始化,再初始化UART为DMA模式,接着配置串口BOARD_UART,开启串口中断NVIC,这里使用到了IDLE中断,用来接受不定长数据,然后配置串口DMA接受,最长100个字节,所以我们可以给串口发送100个字节以下长度的数据。在while(1)循环中循环查询uart_receive_complete_flag标志位,当该标志位为“SET”时,表示IDLE中断被触发,一帧数据接受完,最后将接收到的帧数据通过DMA发送方式原封不动发送到串口上。

16.4.4 中断函数

在bsp_uart.c中定义了串口中断处理函数

C
void USART0_IRQHandler(void)
{driver_uart_int_handler(&BOARD_UART);
}

在driver_uart.c中定义了driver_uart_int_handler函数:

C
Drv_Err driver_uart_int_handler(typdef_uart_struct *uartx)
{   Drv_Err uart_state=DRV_SUCCESS;    if(usart_interrupt_flag_get(uartx->uart_x,USART_INT_FLAG_RBNE)!=RESET){if(uartx->uart_control.RecCount < uartx->uart_control.RecSize){uartx->uart_control.p_Rec[uartx->uart_control.RecCount]=usart_data_receive(uartx->uart_x); uartx->uart_control.RecCount++;            }else{usart_data_receive(uartx->uart_x);uart_state=DRV_ERROR;//err 溢出}if(uartx->uart_rbne_callback!=NULL){uartx->uart_rbne_callback(uartx);}        //callbackif(uartx->uart_control.RecCount == uartx->uart_control.RecSize){uartx->uart_control.Com_Flag.Bits.RecSuccess=1;            uartx->uart_control.Com_Flag.Bits.RecState=0; uartx->uart_control.RecCount=0;            }        }       if(usart_interrupt_flag_get(uartx->uart_x,USART_INT_FLAG_IDLE)!=RESET){usart_interrupt_flag_clear(uartx->uart_x,USART_INT_FLAG_IDLE);USART_STAT0(uartx->uart_x);USART_DATA(uartx->uart_x);if( (uartx->uart_mode_rx==MODE_INT && uartx->uart_control.RecCount>0) \||(uartx->uart_mode_rx==MODE_DMA && dma_transfer_number_get(uartx->uart_rx_dma->dmax,uartx->uart_rx_dma->dma_chx)!=uartx->uart_control.RecSize)){uartx->uart_control.Com_Flag.Bits.RecSuccess=1;uartx->uart_control.Com_Flag.Bits.RecState=0;              if(uartx->uart_mode_rx==MODE_DMA){uartx->uart_control.RecCount=uartx->uart_control.RecSize-dma_transfer_number_get(uartx->uart_rx_dma->dmax,uartx->uart_rx_dma->dma_chx);            }//callback            if(uartx->uart_idle_callback!=NULL){uartx->uart_idle_callback(uartx);}                                }        } if(usart_interrupt_flag_get(uartx->uart_x,USART_INT_FLAG_TBE)!=RESET){usart_data_transmit(uartx->uart_x,uartx->uart_control.p_Send[uartx->uart_control.SendCount]);uartx->uart_control.SendCount++;if(uartx->uart_tbe_callback!=NULL){uartx->uart_tbe_callback(uartx);} if(uartx->uart_control.SendCount >= uartx->uart_control.SendSize){uartx->uart_control.SendCount=0;            usart_interrupt_disable(uartx->uart_x, USART_INT_TBE);usart_interrupt_enable(uartx->uart_x, USART_INT_TC);}} if(usart_interrupt_flag_get(uartx->uart_x,USART_INT_FLAG_TC)!=RESET){usart_interrupt_disable(uartx->uart_x, USART_INT_TC);          usart_flag_clear(uartx->uart_x,USART_FLAG_TC);  if( !(uartx->uart_mode_rx==MODE_DMA && dma_transfer_number_get(uartx->uart_tx_dma->dmax,uartx->uart_tx_dma->dma_chx)!=0) ){    uartx->uart_control.Com_Flag.Bits.SendSucess=1;            uartx->uart_control.Com_Flag.Bits.SendState=0; if(uartx->uart_tc_callback!=NULL){uartx->uart_tc_callback(uartx);}         uartx->uart_control.SendCount=0; }}  if(usart_flag_get(uartx->uart_x,USART_FLAG_ORERR)==SET){usart_flag_clear(uartx->uart_x,USART_FLAG_ORERR);        USART_STAT0(uartx->uart_x);USART_DATA(uartx->uart_x);uart_state=DRV_ERROR;}return uart_state;     }

16.5 实验结果

使用USB-TypeC线,连接电脑和板上USB to UART口后,使用串口调试助手发送一帧数据到MCU,MCU会将这帧数据回发到串口调试助手中。

 

由聚沃科技原创,来源于【红枫派开发板】第十六讲 USART-DMA串口收发实验 - 苏州聚沃电子科技有限公司 (gd32bbs.com) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1452038.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

四轴飞行器、无人机(STM32、NRF24L01)

一、简介 此电路由STM32为主控芯片&#xff0c;NRF24L01、MPU6050为辅,当接受到信号时&#xff0c;处理对应的指令。 二、实物图 三、部分代码 void FlightPidControl(float dt) { volatile static uint8_t statusWAITING_1; switch(status) { case WAITING_1: //等待解锁 if…

波卡近期活动一览| Polkadot Decoded 2024 重磅来袭,300 万 DOT 将用于 DeFi 增长

Polkadot 生态近期活动精彩纷呈&#xff0c;线上线下火热进行中&#xff01;此外&#xff0c;Polkadot 2.0 的关键升级即将到来&#xff0c;Gavin Wood 博士也将在最新访谈节目中分享更多关于波卡的未来发展蓝图。波卡 DAO 通过提案&#xff0c;分配 300 万 DOT 支持 DeFi 生态…

12.容器间的互联(--link 是单方向的!!!)

容器间的互联&#xff08;–link 是单方向的&#xff01;&#xff01;&#xff01;&#xff09; –link意思就是链接容器进行通信 用法&#xff1a;--link 容器名字:随意设置别名&#xff1b;例如&#xff1a;--link nginx:nginx 注释&#xff1a;同一个容器中&#xff0c;可…

动态功能连接评估方法的变异性

摘要 背景&#xff1a;动态功能连接(dFC)已成为理解大脑功能的一种重要测量指标。虽然已经开发了各种各样的方法来评估dFC&#xff0c;但目前尚不清楚方法的选择会如何影响结果。在这里&#xff0c;本研究旨在考察常用dFC方法的结果变异性。 方法&#xff1a;本研究在Python中…

公司面试题总结(六)

31.说一说 webpack 的构建流程是什么&#xff1f; ⚫ 初始化流程&#xff1a; ◼ 从配置文件和 Shell 语句中读取与合并参数 ◼ 初始化需要使用的插件和配置插件等执行环境所需要的参数 ⚫ 编译构建流程&#xff1a; ◼ 从 Entry 发出&#xff0c;针对每个 Module 串行…

仙侠手游【天道情缘】修复版服务端+GM后台+详细教程

下载地址&#xff1a;仙侠手游【天道情缘】修复版服务端GM后台详细教程

【立体几何】如何使用两个正方体(特殊骰子)摆出所有日期1~31

问题 如何使用两个正方体(特殊骰子)摆出所有日期? 解答 下标列举了所有日期 日期十位数个位数011号正方体&#xff1a;02号正方体&#xff1a;02号正方体&#xff1a;11号正方体&#xff1a;1021号正方体&#xff1a;02号正方体&#xff1a;02号正方体&#xff1a;21号正方…

Facebook:数字时代的文化交流平台

在当今信息爆炸的数字时代&#xff0c;Facebook已经成为了一个不可或缺的社交媒体平台&#xff0c;不仅在个人生活中起到了联系社交的作用&#xff0c;更在全球范围内促进了文化交流和理解。本文将深入探讨Facebook作为文化交流平台的重要性&#xff0c;并分析其在数字时代如何…

从零手写实现 nginx-17-nginx.conf 全局的默认配置

前言 大家好&#xff0c;我是老马。很高兴遇到你。 我们为 java 开发者实现了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何处理的&#xff0c;可以参考我的另一个项目&#xff1a; 手写从零实现简易版 tomcat minicat 手写 nginx 系列 …

开源医疗大模型Llama3-Aloe-8B-Alpha,性能超越 MedAlpaca 和 PMC-LLaMA

前言 近年来&#xff0c;大型语言模型 (LLM) 在医疗领域展现出巨大潜力&#xff0c;能够帮助医生和研究人员更快地获取信息、分析数据&#xff0c;并提高医疗服务效率。然而&#xff0c;目前市场上大多数医疗 LLM 都是闭源模型&#xff0c;限制了其在学术研究和应用领域的推广…

OpenGL3.3_C++_Windows(10)

最终演示 ​ demo演示 Assimp模型渲染 模型导入库Assimp&#xff1a;导入很多种不同的模型文件格式&#xff0c;加载至Assimp的通用数据结构&#xff08;树形&#xff09;中&#xff0c;不论导入的是什么种类的文件格式&#xff0c;用同一种方式访问我们需要的数据。 Assimp库…

【Java】多态、final关键字、抽象类、抽象方法

多态(Polymorphism) 【1】多态跟属性无关&#xff0c;多态指的是方法的多态&#xff0c;而不是属性的多态。 【2】案例代入&#xff1a; public class Animal {//父类&#xff1a;动物&#xff1a; public void shout(){ System.out.println("我是小动物&am…

JAVA-CopyOnWrite并发集合

文章目录 JAVA并发集合1_实现原理2_什么是CopyOnWrite?3_CopyOnWriteArrayList的原理4_CopyOnWriteArraySet5_使用场景6_总结 JAVA并发集合 从Java5开始&#xff0c;Java在java.util.concurrent包下提供了大量支持高效并发访问的集合类&#xff0c;它们既能包装良好的访问性能…

无人机的发展

朋友们&#xff0c;你们知道吗&#xff1f;无人机的发展之路可谓是科技界的一股清流&#xff0c;风头正劲啊&#xff01;从最初简单的遥控飞机到现在各种智能功能的加持&#xff0c;无人机真是越来越神奇了&#xff01; 首先&#xff0c;无人机在航拍领域大放异彩&#xff01;无…

ETL可视化工具 DataX -- 简介( 一)

引言 DataX 系列文章&#xff1a; ETL可视化工具 DataX – 安装部署 ( 二) 1.1 DataX 1.1.1 Data X概览 DataX 是阿里云DataWorks数据集成的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServ…

ChatGPT 提示词技巧一本速通

一、基本术语 概念 定义 案例 提示词 prompt 向AI模型提出的问题或者指示&#xff0c;告诉它我们希望得到什么样的回答或结果&#xff0c;是与模型互动的主要形式。 任务&#xff1a;生成一封电子邮件邀请。 提示词&#xff1a;请帮我写一封邀请同事参加下周五团队建设活…

Vue引入element-plus-04

我们这次开发是使用vue的脚手架来进行开发,前面我们已经使用过最原生的方式去编写我们的vue的语法,从今天开始就使用vue的脚手架,但是前提是你需要用于node的环境 在我们开始之前&#xff0c;我们至少需要有node npm是什么&#xff1f; npm是一个强大的包管理工具&#xff0c;它…

Stable Diffusion【应用篇】【艺术写真】:粘土风之后陶瓷风登场,来看看如何整合AI艺术写真吧

在国外的APP Remini引爆了粘土滤镜后&#xff0c;接着Remini又推出了瓷娃娃滤镜。相当粘土滤镜&#xff0c;个人更喜欢瓷娃娃滤镜&#xff0c;因为陶瓷工艺更符合东方艺术审美。 下面我们就来看看陶瓷特效在AI写真方面的应用。话不多说&#xff0c;我们直接开整。 关于粘土整…

基于BERT微调+模板填充快速实现文本转DSL查询语句

前言 Text2SQL是指将自然语言转化为类SQL查询语句&#xff0c;使得用户的查询文本可以直接实现和数据库交互&#xff0c;本文介绍一种以BERT为基础模型&#xff0c;通过模板填充来实现的Text2SQL算法和产品化。 内容摘要 Text2SQL任务说明模板填充的思路条件列选择子模型搭建…

TCGAbiolinks包学习

TCGAbiolinks 写在前面学习目的GDCquery GDCdownload GDC prepare中间遇到的报错下载蛋白质数据 写在前面 由于别人提醒我TCGA的数据可以利用TCGAbiolinks下载并处理&#xff0c;所以我决定阅读该包手册&#xff0c;主要是该包应该是有更新的&#xff0c;我看手册进行更新了&…