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。计算步骤是这样的:

  1. 预置一个 16 位寄存器,全部填 1(即 0xFFFF)
  2. 取第一个字节,与寄存器的低 8 位异或
  3. 右移一位,高位补 0。如果移出的最低位是 1,则与多项式 0xA001 异或
  4. 重复步骤 3,直到处理完 8 位
  5. 处理下一个字节,重复步骤 2-4
  6. 所有字节处理完后,寄存器取反,得到 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 报文的核心逻辑串起来。你一看就明白:

Modbus RTU 报文结构知识体系 RTU 报文结构 帧格式 CRC 校验计算 异常响应码 地址码 功能码 数据区 CRC 校验 多项式 0x8005 异或 0xA001 取反后发送 功能码 | 0x80 异常码 01-06 核心:帧结构 + 校验 + 异常处理,三者缺一不可

这张图把咱们今天讲的内容全串起来了。你记住,排查 RTU 通信故障,就按这个思路来:先看帧格式对不对,再看 CRC 算没算对,最后看异常码说了啥。三步走完,90% 的问题都能定位。


公众号:蓝海资料掘金营,微信deep3321