1. 为什么你需要DMA+USART来做Modbus从机?
如果你正在用STM32做工业数据采集或者小型控制器,大概率会碰到Modbus协议。这个协议在工控领域太常见了,PLC、传感器、变频器都在用。传统的做法,你可能用串口中断来收数据,一个字节一个字节地收,收完一帧再解析、处理、回复。这样做当然没问题,项目也能跑起来。
但实际跑起来,问题就来了。当你的主循环里还有其他任务要处理,比如采集模拟量、控制IO、刷新屏幕,串口中断频繁进来,CPU就得不停地“接电话”,处理完中断再回去干别的活。如果通信数据量稍微大一点,或者波特率高了,CPU就会显得很“忙”,甚至可能因为处理中断不及时而丢数据。我早期做项目就踩过这个坑,设备偶尔会“卡”一下,查了半天才发现是串口中断处理占用了太多时间。
这时候,DMA(直接内存访问)就该上场了。你可以把它想象成一个“专职快递员”。以前,串口收到一个字节,就要喊CPU(老板)来取件,老板手头正忙也得放下,跑来拿这个字节,再跑回去。有了DMA这个快递员,串口收到数据,直接告诉DMA:“货到了,放那边仓库(内存)。” DMA就默默地把数据从串口搬运到你指定的内存数组里,搬完了或者发现一段时间没新货了(空闲中断),才通知CPU一声:“老板,货齐了,您来处理吧。”
这样一来,CPU被解放了,它只需要在DMA通知“货已备好”时,去处理整包数据。通信的实时性和系统的整体响应能力都大大提升。特别是对于Modbus从机这种需要及时响应主机查询的场景,用DMA接收,再把回复也用DMA发出去,整个通信过程对CPU的打扰降到最低,你的主程序可以更流畅地运行其他逻辑。
所以,STM32CubeMX + DMA + USART这个组合,核心目标就是:搭建一个不堵车、不卡顿、让CPU省心的Modbus从机通信通道。CubeMX帮我们搞定复杂的底层配置,我们专注于协议逻辑,开发效率和质量都能提高不少。
2. 动手之前:核心概念快速扫盲
在开始配置和写代码之前,我们花几分钟把几个核心概念理清楚,这样后面操作起来心里更有底。
2.1 USART:数据的马路
USART(通用同步异步收发器)就是STM32和外界“说话”的嘴巴和耳朵。我们这里用的是异步模式,也是最常用的串口。
你需要关注几个关键参数,它们就像马路的交通规则:
- 波特率:通信速度,比如9600、115200。主从设备必须一致,不然就是“鸡同鸭讲”。
- 数据位:通常8位,代表一个字节。
- 停止位:通常1位,表示一帧数据的结束。
- 校验位:可选,用于简单的错误检测,比如奇校验或偶校验。Modbus RTU通常用无校验(None),因为它有更可靠的CRC校验。
在Modbus RTU模式下,我们通常设置:波特率(如9600)、8位数据位、无校验、1位停止位。这条“马路”的规则就定好了。
2.2 DMA:不知疲倦的搬运工
DMA是本文的“明星外设”。它独立于CPU,可以在内存和外设(比如USART的数据寄存器)之间直接搬运数据。
有几个关键点需要理解:
- 通道(Channel):DMA有多个通道,每个通道可以服务于一个特定的外设。比如,STM32F103的USART1_RX(接收)可能固定使用DMA1的通道5,USART1_TX(发送)使用通道4。这在CubeMX里选择时是固定的,我们记住对应关系就行。
- 传输方向:内存到外设(发送),或者外设到内存(接收)。
- 传输模式:
- 普通模式(Normal):DMA搬运指定数量的数据后,就停止工作,需要软件重新启动。就像快递员送完一单就下班了,下次有货得再叫他。
- 循环模式(Circular):DMA搬运完指定数量数据后,自动从头开始循环搬运。适合持续不断的数据流。但要注意,如果和发送共用DMA资源,可能会冲突,所以我们接收常用“普通模式+空闲中断后重启”的策略,更可控。
- 中断:DMA搬运完成一半、全部完成、或者发生错误时,可以产生中断通知CPU。我们主要用“传输完成中断”。
2.3 Modbus RTU从机协议:我们要说的“语言”
Modbus RTU是一种二进制协议,数据帧紧凑。一个典型的查询帧结构如下:
| 字段 | 设备地址 | 功能码 | 数据域 | CRC校验 |
|---|---|---|---|---|
| 长度 | 1字节 | 1字节 | N字节 | 2字节 |
作为从机,我们的工作就是:监听总线上的数据帧,判断地址是不是找我(设备地址),如果是,就解析功能码和数据,执行相应操作(读或写寄存器),然后组织一个响应帧发回去。
本教程我们实现最常用的两个功能码:
- 0x03 (读保持寄存器):主机用来读取我们设备里的数据。比如读取温度、压力值。
- 0x06 (写单个寄存器):主机用来修改我们设备里的一个参数。比如设定一个目标温度。
协议里最“麻烦”但必不可少的是CRC16校验。它用来确保数据在传输过程中没有出错。发送方计算整个数据帧(除CRC本身)的CRC值,附在帧尾;接收方收到后重新计算CRC,与帧尾的CRC比对,一致才认为帧有效。文末会提供一个现成可靠的CRC计算函数。
3. 使用STM32CubeMX进行图形化配置
理论说再多不如动手。现在打开STM32CubeMX,我们一步步把硬件底层配置好。这里以STM32F103系列为例,其他系列大同小异。
3.1 创建工程与时钟配置
首先,选择你的芯片型号(例如STM32F103ZE)。在Pinout & Configuration界面,第一步是配置时钟树(Clock Configuration)。对于串口通信,一个稳定的时钟源是关键。通常我们使用外部高速时钟(HSE),然后通过PLL倍频到系统主频(比如72MHz)。CubeMX可以一键生成最优时钟配置,你只需要在RCC选项里使能HSE,然后在时钟树界面点击“HCLK”,输入目标频率(如72),软件会自动计算并配置好PLL参数。
3.2 配置USART1
在左侧Connectivity中找到USART1。
- 模式选择:选择
Asynchronous(异步通信)。 - 基本参数:
Baud Rate: 设置为你的Modbus网络速率,例如9600。Word Length:8 Bits。Parity


72

被折叠的 条评论
为什么被折叠?



