3、报文结构解析:RTU帧格式、CRC校验计算、异常响应码解读
好,咱们直接切入正题。Modbus RTU 报文,说白了就是设备之间交流的「黑话」。你要是听不懂这个黑话,设备坏了你都不知道它为啥罢工。我干了这么多年现场调试,至少有一半的通信故障,归根结底都是报文格式没搞对。
3.1 RTU 帧格式:一个字节都不能错
RTU 帧的结构其实很简单,就四个部分:地址码、功能码、数据区、CRC 校验。我习惯把它记成「谁找我、找我干啥、带什么话、对不对」。咱们拆开看:
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| 地址码 | 1 | 从站地址,范围 1-247。0 是广播地址 |
| 功能码 | 1 | 告诉从站要干啥,比如读线圈(01)、读寄存器(03) |
| 数据区 | N | 具体参数,长度可变 |
| CRC 校验 | 2 | 低字节在前,高字节在后 |
这里有个坑,我刚开始做项目时踩过——帧间隔时间。RTU 要求帧与帧之间至少要有 3.5 个字符时间的静默期。什么意思?就是发完一帧后,总线必须安静一会儿,才能发下一帧。我曾经遇到一个项目,PLC 和变频器通信老是丢包,查了两天,最后发现是上位机发包间隔太短,变频器还没处理完上一帧,下一帧就怼过来了。嗯,调了个定时器参数就解决了。
关键点:RTU 帧没有起始位和停止位,靠时间间隔来区分帧边界。3.5 字符时间的静默期是硬性要求,别偷懒。
3.2 CRC 校验计算:手算一遍就懂了
CRC 校验,说白了就是给报文算个「指纹」。发送方算一遍,接收方再算一遍,两个指纹对得上,说明数据没被篡改。我见过不少工程师直接用现成的库函数,一旦算不对就抓瞎。其实原理不复杂,咱们走一遍流程。
Modbus RTU 用的是 CRC-16,多项式是 0x8005。计算步骤是这样的:
- 预置一个 16 位寄存器,全部填 1(即 0xFFFF)
- 取第一个字节,与寄存器的低 8 位异或
- 右移一位,高位补 0。如果移出的最低位是 1,则与多项式
0xA001异或 - 重复步骤 3,直到处理完 8 位
- 处理下一个字节,重复步骤 2-4
- 所有字节处理完后,寄存器取反,得到 CRC 值
你想想看,这其实就是个循环冗余校验,没什么神秘的。我给大家写个 C 语言的实现,你在单片机上也能跑:
// CRC-16 计算函数
uint16_t crc16_modbus(uint8_t *data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
个人经验:调试时可以用 Modbus Poll 或串口助手抓包,手动算一遍 CRC 对比。我习惯在代码里加个调试开关,把每次计算的 CRC 值打印出来,这样定位问题快很多。
3.3 异常响应码解读:设备在跟你说「不」
设备不会无缘无故不理你。当从站收到一个它处理不了的请求时,会返回异常响应。格式很简单:地址码 + (功能码 | 0x80) + 异常码 + CRC。注意看,功能码的最高位被置 1 了,这就是异常响应的标志。
常见的异常码就那几个,我列个表,你对照着看:
| 异常码 | 名称 | 含义 |
|---|---|---|
| 01 | 非法功能码 | 从站不支持这个功能,比如你让一个温控器去读线圈 |
| 02 | 非法数据地址 | 你访问的寄存器地址不存在,比如地址越界了 |
| 03 | 非法数据值 | 数据值超出范围,比如你让电机转速设为 10000,但它最大只支持 3000 |
| 04 | 从站设备故障 | 从站内部出问题了,硬件故障或逻辑错误 |
| 05 | 确认 | 从站已收到请求,但需要时间处理,稍后再问 |
| 06 | 从站忙 | 从站正在处理其他任务,没空理你 |
我曾经遇到一个案例,现场有个变频器老是返回异常码 02。我查了半天地址表,发现是上位机把寄存器地址写错了——它用的是 40001 这种 PLC 地址,但 Modbus 报文里应该用 0x0000 这种协议地址。说白了,就是地址映射没搞清楚。
避坑指南:异常码 04 和 06 最容易让人头疼。04 通常是硬件问题,比如电源不稳、晶振坏了。06 则可能是从站程序卡死了,或者通信负载太高。我建议你在从站代码里加个看门狗,超时了就复位,能省不少事。
3.4 知识体系总览
说了这么多,咱们用一张图把 RTU 报文的核心逻辑串起来。你一看就明白:
这张图把咱们今天讲的内容全串起来了。你记住,排查 RTU 通信故障,就按这个思路来:先看帧格式对不对,再看 CRC 算没算对,最后看异常码说了啥。三步走完,90% 的问题都能定位。
公众号:蓝海资料掘金营,微信deep3321