4. 协议层帧结构分析:RTU、ASCII与TCP报文格式
各位工程师朋友,咱们今天聊聊Modbus的帧结构。说实话,搞通信诊断这么多年,我见过太多人拿着示波器对着波形发呆——明明物理层没问题,数据就是解析不出来。问题出在哪?多半是协议层没搞明白。
我个人习惯把协议层比作“信封”。你写好了信(数据),总得知道怎么装进信封、贴什么邮票、写什么地址吧?Modbus的帧结构,就是这套规则。
4.1 RTU帧格式:最常用的“二进制信封”
RTU模式,说白了就是纯二进制传输。每个字节8位,效率高,速度快。我90%的项目都用它。
一个完整的RTU帧长这样:
| 地址码 | 功能码 | 数据区 | CRC校验 |
| 1字节 | 1字节 | N字节 | 2字节 |
地址码(1字节):范围0x00-0xF7。0x00是广播地址,所有从站都得收,但不回复。0xF8-0xFF保留,别乱用。我在现场见过有人把地址设成0xFF,结果从站死活不响应——嗯,地址冲突了。
功能码(1字节):告诉从站你要干啥。常用的就那几个:
| 功能码 | 含义 | 我常用的场景 |
|---|---|---|
| 0x01 | 读线圈 | 读取继电器状态 |
| 0x03 | 读保持寄存器 | 读取传感器数值 |
| 0x06 | 写单个寄存器 | 设定PID参数 |
| 0x10 | 写多个寄存器 | 批量下发配置 |
数据区(N字节):根据功能码不同,长度可变。比如读寄存器时,这里放起始地址和数量;写寄存器时,放地址、数量和具体数值。
CRC校验(2字节):这是RTU的“防伪标签”。算法是CRC-16/MODBUS,多项式0x8005。我建议你直接用现成的查表法,别自己手算——我当年手算过一次,算完发现少了个0,折腾了俩小时。
避坑指南:我曾经遇到一个案例,从站偶尔回复错误。查了半天,发现是CRC计算时高低字节顺序搞反了。RTU的CRC是低字节在前,高字节在后。这点很多新手会栽跟头。
4.2 ASCII帧格式:可读但低效的“文本信封”
ASCII模式,每个字节拆成两个ASCII字符发送。比如0x1A,发的是'1'和'A'(0x31、0x41)。好处是肉眼能看,坏处是效率砍半。
帧结构:
| 起始符 | 地址码 | 功能码 | 数据区 | LRC校验 | 结束符 |
| 1字符 | 2字符 | 2字符 | 2N字符 | 2字符 | 2字符 |
起始符:固定0x3A(':')。
结束符:0x0D 0x0A(回车换行)。
LRC校验:纵向冗余校验,比CRC简单多了。就是把所有字节加起来,取补码。
说实话,我现在很少用ASCII模式。只有在调试初期,或者跟一些老设备对接时才会碰到。有一次在化工厂,PLC死活连不上,我让现场把模式切到ASCII,用串口助手一看报文——原来是地址码发成了小写字母。ASCII模式下,地址码必须是大写十六进制字符。
我的建议:除非设备只支持ASCII,否则一律用RTU。ASCII的LRC校验太弱,抗干扰能力差。你想想看,工厂里电机一启动,电磁干扰上来,ASCII帧很容易被破坏。
4.3 TCP报文格式:没有校验的“网络信封”
Modbus TCP,说白了就是把RTU帧去掉CRC,套上TCP/IP的头。因为TCP本身已经保证了可靠传输,CRC就多余了。
报文结构:
| MBAP头 | 功能码 | 数据区 |
| 7字节 | 1字节 | N字节 |
MBAP头(7字节):
| 字段 | 长度 | 说明 |
|---|---|---|
| 事务标识符 | 2字节 | 用于匹配请求和响应 |
| 协议标识符 | 2字节 | 固定0x0000 |
| 长度 | 2字节 | 后续字节数 |
| 单元标识符 | 1字节 | 相当于RTU的地址码 |
这里有个坑:单元标识符在TCP里其实没啥用,因为TCP连接已经唯一确定了设备。但很多网关设备会用它来路由到背后的串口设备。我遇到过一台网关,单元标识符设成0xFF就转发,设成其他值就丢弃——折腾了我一上午才试出来。
注意:Modbus TCP的默认端口是502。很多IT管理员会封这个端口,觉得不安全。我建议你跟网络部门提前沟通好,或者改用端口映射。别等到现场才发现连不上。
4.4 三种帧格式对比
我整理了一张表,方便你快速对比:
| 特性 | RTU | ASCII | TCP |
|---|---|---|---|
| 传输效率 | 高 | 低(减半) | 高 |
| 校验方式 | CRC-16 | LRC | TCP校验 |
| 可读性 | 差 | 好 | 差 |
| 适用场景 | 串口通信 | 调试/老设备 | 以太网 |
| 帧间隔 | 3.5字符时间 | 1秒超时 | 无 |
4.5 帧结构知识体系图
下面这张图,是我自己总结的帧结构分析思路。你照着这个流程走,基本不会漏掉关键点。
这张图的核心逻辑很简单:先确认物理层,再选模式,然后按对应格式解析,最后验证校验。我每次排查通信故障,都是按这个顺序来。你照着做,至少能解决80%的问题。
调试小技巧:如果你手头没有专业分析仪,可以用串口助手抓原始数据。RTU模式下,看到连续两个字节跟前面数据对不上,那多半就是CRC。ASCII模式下,看到冒号开头、回车换行结尾,基本没跑。TCP的话,用Wireshark抓包,过滤条件设成"modbus"就行。
好了,帧结构这块就聊到这儿。记住一句话:协议层的问题,90%出在校验和地址上。下次你遇到通信故障,先别急着怀疑硬件,拿示波器或者抓包工具看看帧结构对不对。很多时候,问题就出在你以为“肯定没问题”的地方。