4. Modbus RTU帧结构与串行链路参数配置
Modbus RTU 是农业设备通信中最常见的串行协议形式,温室控制器、水肥一体机、土壤墒情采集器、变频水泵和电表大多以 RS-485 半双工方式运行 RTU。调试时“通信不上”的原因,往往不是设备坏了,而是帧结构理解偏差或串口参数不一致。本节把一帧 RTU 报文拆开看,再把串口参数、帧间隔和 CRC 校验串起来,形成可落地的配置与排查思路。
一、RTU 帧的四个组成部分
一帧标准 RTU 报文由地址域、功能码、数据域和 CRC 校验四段构成,帧内字节之间没有起始符和结束符,帧的边界完全依靠总线上的静默时间(3.5 个字符时间)来界定。这是 RTU 与 ASCII 模式最本质的区别,也是现场最容易忽略的一点。
- 地址域(1 字节):取值 1~247 表示从站地址,0 为广播地址(从站执行但不回应),248~255 保留。农业现场常把同一棚区的传感器编为连续地址,便于轮询。
- 功能码(1 字节):03 读保持寄存器、04 读输入寄存器、06 写单个寄存器、16(0x10)写多个寄存器、01/02 读线圈与离散输入。从站正常应答时功能码最高位为 0;若出错,会把功能码最高位置 1(如 0x83),并在数据域返回异常码。
- 数据域(N 字节):随功能码变化。以 03 为例,请求帧数据域为“起始寄存器地址高字节、低字节 + 寄存器数量高字节、低字节”;应答帧数据域为“字节数 + 各寄存器值”。
- CRC 校验(2 字节):CRC-16/MODBUS,低字节在前、高字节在后,覆盖地址到数据域的全部字节。
以读取从站地址 1、起始寄存器 0x0000、数量 2 为例,请求帧为:01 03 00 00 00 02 C4 0B。其中 C4 0B 是 CRC 计算结果,注意发送顺序是低字节 C4 在前。若从站返回 01 03 04 00 64 00 C8 ...,表示两个寄存器值分别为 100 和 200(示例数据,用于说明字节序与解析方式)。
二、串口参数必须“四对齐”
RS-485 链路上,主站与每个从站的波特率、数据位、停止位、校验位必须完全一致,任何一项不同都会表现为乱码、CRC 错误或完全无响应。农业现场常见组合是 9600 bps、8 数据位、无校验、1 停止位(8N1),部分电表和水泵变频器使用 8E1(偶校验)。配置时建议先在主站侧固定参数,再逐台核对从站铭牌或参数菜单,不要凭经验假设。
需要特别区分两个“校验”:串口参数中的奇偶校验是 UART 硬件对每个字符做的位级校验,只能发现单比特错误;而 RTU 帧尾的 CRC 是对整帧字节序列做的校验,能发现绝大多数传输错误。两者同时存在、互不替代。调试时若串口助手显示“收到数据但 CRC 错”,说明波特率、数据位、停止位基本正确,问题更可能出在校验位设置、线路干扰或帧边界判断上。
三、帧间隔与超时的实际取值
RTU 规定帧内字符间隔不得超过 1.5 个字符时间,否则接收方会丢弃该帧;帧与帧之间至少静默 3.5 个字符时间。字符时间按“起始位 + 数据位 + 校验位 + 停止位”的总位数计算,8N1 为 11 位。以 9600 bps 为例,单字符约 1.146 ms,3.5 字符约 4.0 ms;19200 bps 时约 2.0 ms。主站软件通常自动处理帧间隔,但在自行编写轮询程序或使用某些 PLC 自由口通信时,必须显式保证发送完成后等待足够静默再发下一帧。
应答超时是主站等待从站回复的最长时间,应大于“从站内部处理时间 + 应答帧传输时间”。工程上常取 300~1000 ms,重试 2~3 次。超时设得过短,慢速设备(如带继电器输出的水肥机)会被误判为离线;设得过长,一台故障从站会拖慢整个轮询周期。建议先用串口助手手动发一帧,观察实际应答延迟,再据此设定。
四、CRC 校验原理与手算方法
Modbus CRC 采用 CRC-16/MODBUS:初始值 0xFFFF,多项式 0xA001(即 0x8005 的反向表示),输入输出均反射,结果不取反。计算步骤为:把 CRC 寄存器置 0xFFFF;对每个待校验字节与 CRC 低字节异或,然后右移 8 次,每次若最低位为 1 则异或 0xA001;全部字节处理完后,寄存器值即为 CRC,发送时低字节在前。
// CRC-16/MODBUS 计算(C 语言示意)
uint16_t crc16_modbus(const uint8_t *buf, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= buf[i];
for (uint8_t b = 0; b < 8; b++) {
if (crc & 0x0001) crc = (crc >> 1) ^ 0xA001;
else crc >>= 1;
}
}
return crc; // 发送时先低字节、后高字节
}
以请求帧前 6 字节 01 03 00 00 00 02 计算,得到 CRC 为 0x0BC4,因此发送序列为 01 03 00 00 00 02 C4 0B。接收方对“地址到数据域 + 收到的 CRC”整体再算一次,若结果为 0 则校验通过。现场排查时,可用串口助手把收到的完整帧(含 CRC)输入 CRC 计算工具,结果为 0 说明帧完整;不为 0 则优先怀疑波特率偏差、校验位设置或线路干扰。
把帧结构、串口参数、帧间隔和 CRC 四件事对齐后,Modbus RTU 的调试就有了清晰的判断链条:先看物理层与参数是否一致,再看帧边界与超时是否合理,最后用 CRC 结果确认帧完整性。后续的寄存器读写与异常码处理,都建立在这一层稳定通信的基础之上。