3. Modbus RTU 基础:物理层(RS-485)、帧结构、功能码(03/06/16)、CRC校验

在变量施肥系统中,控制器与变频器、电磁阀、传感器之间的数据交换,最常用的底层协议就是 Modbus RTU。它运行在 RS-485 物理层之上,采用主从问答模式。理解其物理层特性、报文帧结构、核心功能码以及 CRC 校验机制,是进行多协议对接的第一步。

3.1 物理层:RS-485 标准

RS-485 是 Modbus RTU 最常用的物理层载体,特别适合工业现场的长距离、多节点通信。

特性 RS-485 参数 现场意义
传输方式 差分平衡传输(半双工) 抗共模干扰强,适合电机变频环境
最大节点数 32 个标准负载(加中继可扩展) 一台施肥控制器可挂多台设备
最大距离 1200 米(@ 100 kbps) 覆盖大田或温室控制柜到执行器
逻辑电平 A-B 电压差 > +200 mV 为 1;< -200 mV 为 0 与 TTL 电平不兼容,需转换芯片
终端电阻 120 Ω(线路两端各一个) 消除信号反射,保证数据完整性
现场布线要点: 使用双绞屏蔽线,屏蔽层单端接地;A/B 线不要接反;总线两端必须各并联一个 120 Ω 终端电阻,否则长距离通信会出现乱码或丢包。

3.2 Modbus RTU 帧结构

Modbus RTU 采用二进制编码,报文以连续的字节流形式在 RS-485 总线上传输。每一帧由以下四个部分组成:

  • 地址域(1 字节): 从站设备地址,范围 1~247,0 为广播地址。
  • 功能码(1 字节): 指示读/写操作类型,如 03、06、16。
  • 数据域(N 字节): 寄存器起始地址、数量或具体数值。
  • CRC 校验(2 字节): 低字节在前,高字节在后,用于检测传输错误。

帧之间的空闲间隔必须 ≥ 3.5 个字符时间,作为帧起始和结束的判定依据。

典型读请求帧示例(读 1 路寄存器):
从站地址: 0x01
功能码:   0x03
起始地址: 0x00 0x64  (100)
寄存器数: 0x00 0x01  (1)
CRC 校验: 0x84 0x0A
Modbus RTU 帧结构 地址域 1 字节 功能码 1 字节 数据域 N 字节(地址 + 数量 / 数值) CRC 校验 2 字节 帧间隔 ≥ 3.5 字符 帧间空闲 ≥ 3.5 字符时间,作为帧起始/结束判定 CRC 校验覆盖地址域 + 功能码 + 数据域

3.3 核心功能码:03 / 06 / 16

变量施肥系统中最常用的三个功能码,覆盖了读取传感器数值、写入单路执行器参数、批量设置多路参数三种场景。

功能码 名称 方向 典型用途
0x03 读保持寄存器 主站 → 从站(请求)
从站 → 主站(响应)
读取流量计瞬时流量、阀门开度反馈
0x06 写单个寄存器 主站 → 从站(写入)
从站 → 主站(回显)
设定变频器频率、电磁阀开度值
0x10 (16) 写多个寄存器 主站 → 从站(写入)
从站 → 主站(应答)
批量设置施肥配方参数(N/P/K 比例)
常见错误: 功能码 0x06 只能写 1 个寄存器(2 字节),如果试图用 0x06 写入超过 2 字节的数据,从站会返回异常码 0x86(非法数据值)。批量写入必须使用功能码 0x10。

3.4 CRC 校验原理与计算

Modbus RTU 使用 CRC-16 (Modbus 多项式) 进行帧校验,多项式为 0x8005,初始值为 0xFFFF。校验覆盖地址域、功能码和数据域,不包含帧间隔。

计算步骤:

  1. 将 16 位 CRC 寄存器初始化为 0xFFFF。
  2. 对每个字节与 CRC 寄存器低字节进行异或。
  3. 右移 1 位,若移出位为 1,则与多项式 0xA001(逆序)异或。
  4. 重复 8 次,处理完所有字节后,CRC 寄存器值即为校验码。
  5. 发送时 低字节在前,高字节在后。
C 语言 CRC 计算示例:
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;
}
CRC-16 (Modbus) 计算流程 CRC = 0xFFFF 对每个字节:CRC ^= data[i] 循环 8 次:右移 1 位,若移出 1 则 CRC ^= 0xA001 返回 CRC(低字节在前)

3.5 主从问答流程示例

以读取变频器当前频率(寄存器地址 100)为例,展示完整的主从交互过程:

方向 字节流(十六进制) 说明
主站 → 从站 01 03 00 64 00 01 84 0A 请求读取地址 01 的寄存器 100
从站 → 主站 01 03 02 0B B8 7A 3E 响应:数据长度 2 字节,频率值 0x0BB8 = 3000(对应 30.00 Hz)
调试技巧: 使用串口助手或 Modbus 调试工具(如 ModScan、Modbus Poll)发送原始报文,观察从站响应。如果收到异常码 0x83(功能码 03 的异常响应),说明地址或寄存器不存在;如果无响应,优先检查 RS-485 接线和终端电阻。