基于stm32的UART高效接收DMA+IDLE编程示例

2024-04-22 04:04

本文主要是介绍基于stm32的UART高效接收DMA+IDLE编程示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 基于stm32的UART高效接收DMA+IDLE编程示例
    • 实验目的
    • 场景使用原理图
    • UART的三种编程方式
    • IDLE
    • 程序设计
    • 串口配置
    • 配置中断
    • 配置DMA
    • 代码片段
    • 本文中使用的测试工程

基于stm32的UART高效接收DMA+IDLE编程示例

本文目标:基于stm32_h5的freertos编程示例

按照本文的描述,应该可以在对应的硬件上通实验并举一反三。

先决条件:拥有C语言基础,装有编译和集成的开发环境,比如:Keil uVision5

使用外设:USART1、USART1、GPIO、SysTick

HAL库版本:STM32H5xx HAL Driver version number 1.1.0

STMCubeMX版本:6.10.0

Keil uVision5版本:V5.38.0.0

实验目的

记录项目学习,学习在项目中进行的UART编程,体验串口的高效接收,设计一个实验,实现串口的接收。

场景使用原理图

在我的应用场景中,原理图的内容如下:

在这里插入图片描述

我将J4的接口的进行接线,这样就可以设计出一个串口发送,一个串口进行接收的实验。

UART的三种编程方式

结合 UART 硬件结构,有 3 种编程方法:

① 查询方式:

​ 要发送数据时,先把数据写入 TDR 寄存器,然后判断 TDR 为空再返回。当然也可以先判断 TDR 为空,再写入。要读取数据时,先判断 RDR 非空,再读取 RDR 得到数据。

② 中断方式:

​ 使用中断方式,效率更高,并且可以在接收数据时避免数据丢失。要发送数据时,使能“TXE”中断(发送寄存器空中断)。在 TXE 中断处理函数里,从程序的发送 buffer 里取出一个数据,写入 TDR。等再次发生 TXE 中断时,再从程序的发送buffer 里取出下一个数据写入 TDR。

对于接收数据,在一开始就使能“RXNE”中断(接收寄存器非空)。这样,UART 接收到一个数据就会触发中断,在中断程序里读取 RDR 得到数据,存入程序的接收 buffer。当程序向读取串口数据时,它直接读取接收 buffer 即可。这里涉及的“发送 buffer”、“接收 buffer”,特别适合使用“环形 buffer”。

③ DMA 方式:

​ 使用中断方式时,在传输、接收数据时,会发生中断,还需要 CPU 执行中断处理函数。有另外一种方法:DMA(Direct Memory Access),它可以直接在 2 个设备之间传递数据,无需 CPU 参与。

在这里插入图片描述

设置好 DMA(源、目的、地址增减方向、每次读取数据的长度、读取次数)后,DMA 就会自动地在 SRAM 和 UART 之间传递数据:

① 发送时:DMA 从 SRAM 得到数据,写入 UART 的 TDR 寄存器

② 接收时:DMA 从 UART 的 RDR 寄存器得到数据,写到 SRAM 去

③ 指定的数据传输完毕后,触发 DMA 中断;在数据传输过程中,没有中断,CPU 无需处理。

涉及使用的HAL库API如下:

//查询方式:
//发送:
HAL_UART_Transmit
//接收: 
HAL_UART_Receive//中断方式:
//发送:
HAL_UART_Transmit_IT
HAL_UART_TxCpltCallback 
//接收: 
HAL_UART_Receive_IT
HAL_UART_RxCpltCallback//DMA方式:
//发送:
HAL_UART_Transmit_DMA
HAL_UART_TxHalfCpltCallback
HAL_UART_TxCpltCallback
//接收: 
HAL_UART_Receive_DMA
HAL_UART_RxHalfCpltCallback
HAL_UART_RxCpltCallback// 错误
HAL_UART_ErrorCallback
HAL_UART_ErrorCallback

IDLE

IDLE,空闲的定义是:总线上在一个字节的时间内没有再接收到数据。UART 的 IDLE 中断何时发生?RxD 引脚一开始就是空闲的啊,难道 IDLE 中断一直产生?不是的。当我们使能 IDLE 中断后,它并不会立刻产生,而是:至少收到 1 个数据后,发现在一个字节的时间里,都没有接收到新数据,才会产生 IDLE 中断。我们使用 DMA 接收数据时,确实可以提高 CPU 的效率,但是“无法预知要接收多少数据”,而我们想尽快处理接收到的数据。怎么办?比如我想读取 100 字节的数据,但是接收到 60 字节后对方就不再发送数据了,怎么办?我们怎么判断数据传输中止了?可以使用IDLE 中断。在这种情况下,DMA 传输结束的条件有 3:

① 接收完指定数量的数据了,比如收到了 100 字节的数据了,HAL_UART_RxCpltCallback被调用

② 总线空闲了:HAL_UARTEx_RxEventCallback 被调用

③ 发生了错误:HAL_UART_ErrorCallback 被调用

使用 IDLE 状态来接收的函数有:

//查询方式:
//接收: 
HAL_UARTEx_ReceiveToIdle
//回调函数:
//根据返回参数 RxLen 判断是否接收完毕,还是因为空闲而返回//中断方式:
//接收: 
HAL_UARTEx_ReceiveToIdle_IT
//回调函数:
完毕:HAL_UART_RxCpltCallback
因为空闲而中止:
HAL_UARTEx_RxEventCallback//DMA方式:
//接收: 
HAL_UARTEx_ReceiveToIdle_DMA
//回调函数:
传输一半:
HAL_UART_RxHalfCpltCallback
完毕:
HAL_UART_RxCpltCallback
因为空闲而中止:
HAL_UARTEx_RxEventCallback// 错误
HAL_UART_ErrorCallback

程序设计

① 使用 DMA+IDLE 中断的方式接收数据,它会把数据存入临时缓冲区;

② 在回调函数里:把临时缓冲器的数据写入队列,然后再次使能 DMA

③ APP读取队列:如果队列里没有数据则阻塞。

在这里插入图片描述

串口配置

打开配置工具,进行串口配置

在这里插入图片描述

在这里插入图片描述

配置中断

在这里插入图片描述

配置DMA

在这里插入图片描述

在这里插入图片描述

代码片段

按照上述的配置进行底层配置之后,我们写点代码,如下:

  xTaskCreate(CH1_UART2_TxTaskFunction, // 函数指针, 任务函数"ch1_uart2_tx_task",     // 任务的名字200,                      // 栈大小,单位为word,200表示800字节NULL,                     // 调用任务函数时传入的参数osPriorityNormal,         // 优先级NULL);                    // 任务句柄, 以后使用它来操作这个任务xTaskCreate(CH2_UART4_RxTaskFunction, // 函数指针, 任务函数"ch2_uart4_rx_task",      // 任务的名字200,                      // 栈大小,单位为word,200表示800字节NULL,                     // 调用任务函数时传入的参数osPriorityNormal,         // 优先级NULL);                    // 任务句柄, 以后使用它来操作这个任务

这里的创建的两个任务代码片段如下:

static void CH1_UART2_TxTaskFunction( void *pvParameters ) 
{uint8_t c = 0;while (1){// send dataHAL_UART_Transmit_DMA (&huart2, &c, 1);Wait_UART2_TxComplete(100);vTaskDelay(500);c++;}
}static void CH2_UART4_RxTaskFunction( void *pvParameters ) 
{uint8_t c = 0;int cnt = 0;char buf[100];HAL_StatusTypeDef err;UART4_Rx_Start();while (1){// receive dataerr = UART4_GetData(&c);if(err == 0){sprintf(buf, "Recv Data : 0x%02x, Cnt : %d", c, cnt++);Draw_String(0, 0, buf, 0x0000ff00, 0);}else{HAL_UART_DMAStop(&huart4);}}
}

其中开始发送和开始接收的代码片段:

int UART4_GetData(uint8_t *pData)
{xQueueReceive(g_xUART4_RX_Queue, pData, portMAX_DELAY);return 0;
}void UART4_Rx_Start(void)
{g_xUART4_RX_Queue = xQueueCreate(200, 1);HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
}

编译、烧写、运行,可以看到开发板的 LED 不断闪烁,LCD 上不断的有数据过来,实验设计成功。

在这里插入图片描述

工程实验成功,后续将会继续记录项目中的实验,感谢关注。

本文中使用的测试工程

https://download.csdn.net/download/weixin_44317448/89195002

这篇关于基于stm32的UART高效接收DMA+IDLE编程示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/924774

相关文章

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow