2. Modbus RTU协议核心机制解析
在矿山现场,PLC、智能分站、变频器、皮带保护装置之间大量使用RS-485总线上的Modbus RTU通信。很多接入失败并不是接线问题,而是对协议机制理解不到位:不知道一帧报文从哪里开始、到哪里结束,不知道从站为什么返回一个看似“错误”的功能码,也不知道CRC校验失败时该怀疑谁。本节把Modbus RTU的五个核心机制拆开讲清楚,为后续寄存器读写调试打基础。
一、主从架构:总线上只有一个“提问者”
Modbus RTU是典型的主从(Master/Slave)协议。总线上允许存在一个主站和最多247个从站(地址1~247,地址0为广播地址)。通信永远由主站发起:主站发出请求帧,被寻址的从站才应答;未被寻址的从站保持沉默。这意味着RS-485虽然物理上是半双工总线,但逻辑上不存在“从站主动上报”,现场若出现两个主站(例如PLC和调试软件同时在线),就会出现总线冲突、应答错乱。
从站地址是帧的第一个字节,也是从站判断“这帧是不是给我的”的唯一依据。矿山项目中常见做法是按设备类型分段编址,例如1~20给皮带保护分站、21~40给变频器、41~60给智能电表,便于后期排障时快速定位。广播地址0表示所有从站执行写操作但不应答,只适合少数场景,调试阶段不建议使用。
二、帧结构:靠“静默时间”划分边界
Modbus RTU帧没有起始符和结束符,它依靠总线上的静默间隔来界定一帧。规范要求:帧内字符间隔不超过1.5个字符时间,帧与帧之间至少3.5个字符时间。以9600 bit/s、8数据位、无校验、1停止位(即每字符11位)计算,一个字符时间约1.146 ms,3.5字符时间约4 ms。因此主站发完请求后必须留出足够静默,从站才能正确识别帧结束。
一帧标准请求由四部分组成:从站地址(1字节)、功能码(1字节)、数据域(N字节)、CRC校验(2字节,低字节在前)。以读取从站1的保持寄存器40001~40002为例,请求帧为:
01 03 00 00 00 02 C4 0B
│ │ │ │ └── CRC(低字节在前)
│ │ │ └──────── 寄存器数量 = 2
│ │ └────────────── 起始寄存器地址 = 0x0000
│ └───────────────── 功能码 03(读保持寄存器)
└──────────────────── 从站地址 1
从站正常应答为:01 03 04 XX XX YY YY CRC CRC,其中04表示后续数据字节数为4,即两个寄存器各2字节,高字节在前。注意寄存器地址在报文中是“偏移量”,40001对应偏移0,这是调试时最容易算错的地方。
三、功能码:用哪几个就够矿山现场用
功能码决定“做什么操作”。矿山设备接入中高频使用的其实只有四五个:01读线圈、02读离散输入、03读保持寄存器、04读输入寄存器、06写单个寄存器、16(0x10)写多个寄存器。功能码最高位为1时表示异常应答,例如03的异常形式是0x83。
选择功能码的关键是分清四类数据区:线圈和离散输入是位量(开关状态、报警触点),保持寄存器和输入寄存器是16位字量(频率给定、电流值、累计量)。很多仪表手册写“参数地址4xxxx”就是保持寄存器,用03读;写设定值用06或16。若用错功能码,从站通常返回异常码01(非法功能)。
四、CRC校验:逐位异或加移位的硬计算
CRC是RTU帧完整性的唯一保障。算法为:初值0xFFFF,对除CRC外的每个字节与CRC低字节异或,然后右移8次,每次若最低位为1则异或多项式0xA001。下面给出可直接用于调试脚本的C风格实现:
uint16_t crc16(uint8_t *buf, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= buf[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) { crc >>= 1; crc ^= 0xA001; }
else { crc >>= 1; }
}
}
return crc; // 发送时低字节在前
}
现场判断CRC是否正确的实用方法:用串口助手抓到的完整帧,去掉最后两字节重新计算,若结果与帧尾两字节(按低前高后拼成16位)一致则通过。CRC错误通常指向三类原因:波特率或校验位设置不一致导致采样错位、总线干扰、帧被截断。注意CRC只能发现错误,不能纠错,也不能替代地址和功能码的语义检查。
五、异常响应:从站“回话”说明它听懂了但做不了
当从站收到帧但无法执行时,会返回异常应答:功能码最高位置1,后跟1字节异常码,最后是CRC。常见异常码有:01非法功能、02非法数据地址、03非法数据值、04从站设备故障、06从站忙。例如请求读一个不存在的寄存器,可能收到 01 83 02 C0 F1,其中0x83即03|0x80,02表示地址非法。
需要区分三种“没反应”:从站完全无应答(地址错、接线断、波特率不符)、CRC错导致从站丢弃(干扰或参数不一致)、异常应答(通信正常但请求内容不合法)。前两种主站只能靠超时判断,第三种则能拿到明确原因,排障时应优先利用异常码缩小范围。
六、把机制落到调试动作上
理解上述机制后,现场接入可以形成一套固定动作:先用串口助手按设备手册的波特率、数据位、校验位、停止位连接,手动发送一帧03读寄存器请求,观察是否有应答;有应答则核对返回字节数与CRC;无应答则先确认从站地址和A/B线序,再确认3.5字符静默是否被调试软件破坏(部分USB转485模块在高速发送时字符间隔过大,会被从站判为帧结束)。若收到0x83类异常帧,直接按异常码定位是功能码用错还是地址越界,而不是盲目更换设备。
01 03 00 00 00 02 C4 0B,现场直接粘贴发送,可排除手工计算CRC带来的干扰,快速判断问题出在协议层还是物理层。需要强调的是,主从架构决定了“没有请求就没有数据”,帧结构决定了“静默时间也是协议的一部分”,功能码和地址共同决定“读哪里、写哪里”,CRC保证“收到的就是发出的”,异常响应则把“通信通但业务不通”的情况显式暴露出来。这五点串起来,才构成矿山Modbus RTU设备接入时可靠的判断依据。