RS485 双串口通信 + LCD 实时显示(DMA版)

目录

  • 一、前言
  • [二、DMA 通信核心原理简述](#二、DMA 通信核心原理简述)
  • [三、CubeMX 的 DMA 串口配置](#三、CubeMX 的 DMA 串口配置)
  • [四、FreeRTOS DMA 收发任务代码开发](#四、FreeRTOS DMA 收发任务代码开发)
  • 五、总结
  • 六、结尾

一、前言

前文我们已经完成了串口 RS485 通信的查询方式中断方式 开发,两种方式各有适配场景。本次笔记将在此基础上,讲解串口通信的第三种实现方案 ------DMA 方式。串口的收发数据始终依靠 TDR 发送寄存器、RDR 接收寄存器完成数据中转,无论数据量多少都需经这两个寄存器经手;而 DMA 相当于独立的「硬件搬运工」,可自主完成寄存器与内存之间的数据搬运,全程无需 CPU 参与,能最大化解放 CPU 资源,是串口大数量、高频次数据传输的最优方案,本次依旧基于 FreeRTOS 多任务完成功能开发,保持功能逻辑不变。

二、DMA 通信核心原理简述

DMA(直接存储器访问)的核心作用,是在外设寄存器内存地址之间建立独立的数据传输通道,无需 CPU 的指令干预,自主完成数据的读写搬运。

对于串口通信而言:发送时,DMA 将内存中的数据搬运至串口 TDR 发送寄存器;接收时,DMA 将串口 RDR 接收寄存器的数据搬运至内存,整个传输过程 CPU 可完全脱离,仅在传输完成 / 异常时触发少量响应逻辑,大幅降低 CPU 的资源占用率。

三、CubeMX 的 DMA 串口配置

CubeMX 中有 DMA 功能的专属配置页面,本次开发沿用之前的串口 2 作为发送端、串口 4 作为接收端,为两路串口分别配置独立的 DMA 通道,其余串口、中断、FreeRTOS 相关配置均与上一篇中断版保持一致,具体 DMA 配置如下:

  1. 配置Channel0 作为串口 2 的 DMA 通道,触发方式选择UART2_TX,数据传输方向为内存到外设,源地址设置为每次递增 1 字节。
  1. 配置Channel1 作为串口 4 的 DMA 通道,触发方式选择UART4_RX,数据传输方向为外设到内存,目的地址设置为每次递增 1 字节。

四、FreeRTOS DMA 收发任务代码开发

DMA 方式的串口开发,在代码层面的逻辑与中断方式几乎完全一致,核心改动仅为将中断收发启动函数替换为 DMA 收发启动函数,依旧沿用此前编写的完成等待函数做传输状态判断与超时控制;当接收出现超时异常时,调用专用函数停止对应串口的 DMA 传输,规避异常占用,完整的任务代码如下:

c 复制代码
// 串口2 DMA发送任务:周期发送自增字节数据
static void CH1_UART2_TxTaskFunction(void *pvParameters)
{
	uint8_t c = 0;
	while(1)
	{
		HAL_UART_Transmit_DMA(&huart2, &c, 1); // 启动串口2 DMA发送1字节
		wait_uart2_tx_cplt(100);                // 等待DMA发送完成,超时100ms
		vTaskDelay(1000);                       // 延时1秒,固定周期发送
		c++;                                    // 发送数据自增
	}
};

// 串口4 DMA接收任务:接收数据并实时显示至LCD
static void CH2_UART4_RxTaskFunction(void *pvParameters)
{
	uint8_t c = 0;
	int cnt = 0;
	char buf[100];
	HAL_StatusTypeDef err;
	while(1)
	{
		err = HAL_UART_Receive_DMA(&huart4, &c, 1); // 启动串口4 DMA接收1字节
		if(wait_uart4_rx_cplt(1000) == 0)           // 等待DMA接收完成,超时1000ms
		{
			// 接收成功,格式化数据并LCD显示
			sprintf(buf, "Recv Data : 0x%02x, Cnt : %d", c, cnt++);
			Draw_String(0, 0, buf, 0x0000ff00, 0);
		}
		else
		{
			HAL_UART_DMAStop(&huart4); // 接收超时,停止串口4的DMA传输
		}
	}
};

由此能清晰看出,串口的 DMA 传输与中断传输,在业务代码的实现逻辑上本质一致,只是底层的硬件数据传输方式不同。

五、总结

  1. 串口通信有查询、中断、DMA 三种实现方式,核心数据中转均依赖 TDR/RDR 寄存器;
  2. DMA 为硬件独立搬运数据,无需 CPU 参与,相比中断更能解放 CPU 资源,传输效率更高;
  3. DMA 版代码逻辑与中断版高度复用,仅替换收发启动函数,开发适配成本低;
  4. DMA 传输需做好超时异常处理,通过停止 DMA 规避硬件资源异常占用;
  5. 三种方式各有优势:查询简单、中断省资源、DMA 效率最优,按需选型即可。

六、结尾

本次完成了串口 RS485 通信三种实现方式的闭环学习,从查询到中断再到 DMA,是逐步优化 CPU 资源利用、提升传输效率的过程,也是嵌入式开发的核心优化思路。三种串口通信方式的开发逻辑可通用至各类外设,是嵌入式必备的基础能力。感谢各位的阅读,持续关注本系列,后续将带来更多项目实战的干货复盘与技术优化!

相关推荐
凯尔萨厮12 分钟前
Maven(Windows下载安装)
笔记·maven
wdfk_prog14 分钟前
[Linux]学习笔记系列 -- [drivers][input]serio
linux·笔记·学习
BackCatK Chen1 小时前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
菩提小狗1 小时前
小迪安全2023-2024|第5天:基础入门-反弹SHELL&不回显带外&正反向连接&防火墙出入站&文件下载_笔记|web安全|渗透测试|
笔记·安全·web安全
_OP_CHEN1 小时前
【Linux系统编程】(二十八)深入 ELF 文件原理:从目标文件到程序加载的完整揭秘
linux·操作系统·编译·c/c++·目标文件·elf文件
Wentao Sun2 小时前
致敬软件创业者2026
笔记·程序人生
ZH15455891312 小时前
Flutter for OpenHarmony Python学习助手实战:GUI桌面应用开发的实现
python·学习·flutter
程序员良许2 小时前
三极管推挽输出电路分析
后端·嵌入式
编程小白20263 小时前
从 C++ 基础到效率翻倍:Qt 开发环境搭建与Windows 神级快捷键指南
开发语言·c++·windows·qt·学习
学历真的很重要3 小时前
【系统架构师】第二章 操作系统知识 - 第二部分:进程与线程(补充版)
学习·职场和发展·系统架构·系统架构师