2. Modbus协议基础(上):物理层与串口通信、RTU与ASCII帧格式、功能码分类与地址映射
各位同学,咱们今天聊聊Modbus协议的基础。说实话,Modbus这玩意儿在工业现场太常见了,几乎每个做嵌入式通信的工程师都绕不开它。我最早接触Modbus是在一个温湿度监控项目里,当时被各种帧格式搞得晕头转向,后来踩了不少坑才慢慢摸清楚门道。
这一节我们重点讲三块内容:物理层怎么搭、报文怎么封装、功能码怎么用。嗯,都是硬骨头,但啃下来之后你会发现,Modbus其实没那么神秘。
2.1 物理层与串口通信
Modbus最常用的物理层就是RS-485和RS-232。我个人习惯在工业现场首选RS-485,为什么?因为它支持多点通信,抗干扰能力强,传输距离能到1200米。你想想看,一个车间里几十个传感器,用RS-485一条总线就能搞定,多省事。
RS-232呢?适合短距离、一对一通信。我在调试一个老款PLC时遇到过,它的串口就是RS-232,距离一超过15米数据就开始乱码。后来我换成了RS-485转接器,问题才解决。
串口参数这块,Modbus默认是:
- 波特率:9600 bps(常用,也有19200、38400)
- 数据位:8位
- 校验位:无校验(或偶校验)
- 停止位:1位(或2位)
物理层接线也有讲究。RS-485是差分信号,A线和B线不能接反。我见过有人把A和B焊反了,结果通信时好时坏,还以为是协议栈有问题。其实说白了,就是线序搞错了。
2.2 RTU与ASCII帧格式
Modbus有两种帧格式:RTU和ASCII。RTU是二进制传输,效率高;ASCII是文本传输,可读性强但效率低。我建议在大多数嵌入式项目里用RTU,因为它的数据密度大,适合带宽有限的串口链路。
RTU帧格式:
| 地址码 | 功能码 | 数据区 | CRC校验 |
| 1字节 | 1字节 | N字节 | 2字节 |
举个例子,读取从站地址0x01的保持寄存器,起始地址0x0000,读取2个寄存器:
请求帧:01 03 00 00 00 02 C4 0B
响应帧:01 03 04 00 0A 00 14 3A 9B
这里CRC校验是Modbus RTU的关键。我刚开始写协议栈时,CRC算法总是算不对,后来发现是多项式顺序搞反了。Modbus RTU用的是CRC-16,多项式0x8005,低位在前高位在后。嗯,这个细节很容易被忽略。
ASCII帧格式:
| 起始符 | 地址码 | 功能码 | 数据区 | LRC校验 | 结束符 |
| 1字节 | 2字符 | 2字符 | 可变 | 2字符 | 2字符 |
ASCII帧以冒号':'开头,以回车换行结束。每个字节拆成两个ASCII字符发送。比如地址0x01就变成'0'和'1'。LRC校验比CRC简单,就是所有字节累加后取补码。我在一个老旧设备上用过ASCII模式,因为那个设备的CPU太慢,算CRC会卡死。所以,如果你的MCU资源紧张,ASCII模式也是个备选方案。
2.3 功能码分类与地址映射
Modbus功能码分为三类:位操作、字操作和诊断操作。我整理了一个常用功能码表,你直接拿去用:
| 功能码 | 名称 | 操作对象 | 读写类型 |
|---|---|---|---|
| 0x01 | 读取线圈状态 | 位 | 只读 |
| 0x02 | 读取离散输入 | 位 | 只读 |
| 0x03 | 读取保持寄存器 | 字 | 读写 |
| 0x04 | 读取输入寄存器 | 字 | 只读 |
| 0x05 | 写单个线圈 | 位 | 只写 |
| 0x06 | 写单个寄存器 | 字 | 只写 |
| 0x0F | 写多个线圈 | 位 | 只写 |
| 0x10 | 写多个寄存器 | 字 | 只写 |
地址映射是协议栈移植中最容易出问题的地方。Modbus地址空间分为四个区:
- 线圈(Coil):地址范围00001-09999,对应功能码01、05、0F
- 离散输入(Discrete Input):地址范围10001-19999,对应功能码02
- 输入寄存器(Input Register):地址范围30001-39999,对应功能码04
- 保持寄存器(Holding Register):地址范围40001-49999,对应功能码03、06、10
注意,这里的地址是PLC世界的5位地址。但在嵌入式协议栈里,我们通常用0-based偏移地址。比如保持寄存器40001对应偏移地址0x0000。我见过有人直接把40001当成偏移地址传给协议栈,结果读出来的数据全是错的。所以,移植时一定要做地址转换。
2.4 知识体系结构图
下面这张图是我画的Modbus协议基础结构图,帮你理清本章的知识脉络:
这张图把本章的三个核心模块串起来了。物理层是基础,帧格式是规范,功能码是操作接口。你移植协议栈时,这三层必须逐一验证。我一般先测物理层通不通,再测帧格式对不对,最后才测功能码能不能用。顺序搞反了,排查问题会非常痛苦。
好了,这一节的内容就到这里。Modbus协议基础(上)主要讲了物理层、帧格式和功能码。下一节我们会深入协议栈的移植细节,包括状态机设计、超时处理和多从站管理。嗯,到时候再聊。
公众号:蓝海资料掘金营,微信deep3321