4、Modbus ASCII协议详解:报文帧结构、LRC校验、与RTU的对比
好,咱们聊完了RTU,现在来说说Modbus ASCII。说实话,这个协议现在用得越来越少了。但我个人觉得,搞工控的人还是得懂它。为什么?因为有些老设备、或者某些特定场合(比如无线电、电话线通信),ASCII模式反而更稳。我前几年在一个水处理项目中就遇到过,现场干扰大得离谱,RTU死活收不到正确数据,最后换成ASCII模式才搞定。
4.1 什么是Modbus ASCII?
Modbus ASCII,说白了就是把数据用ASCII字符来传输。每个8位字节被拆成两个ASCII字符发送。比如一个字节 0x1A,在ASCII模式下就变成字符 '1' 和 'A' 发送出去。
你想想看,这样做的代价是什么?传输效率直接砍半。原来发1个字节的时间,现在要发2个字符。但好处也很明显——所有数据都是可见的ASCII字符,调试的时候用串口助手一看就明白,不用对着十六进制发愣。
核心特点:
- 每个字节拆成两个ASCII字符传输
- 报文有固定的起始和结束标记
- 校验方式用LRC(纵向冗余校验)
- 传输效率低,但抗干扰能力在某些场景下更好
4.2 报文帧结构
ASCII模式的报文帧结构和RTU差别很大。我刚开始学的时候老搞混,后来画了个对比表才记住。咱们直接看结构:
| 字段 | 长度 | 说明 |
|---|---|---|
| 起始符 | 1字符 | 固定为 ':' (0x3A) |
| 地址码 | 2字符 | 从站地址,如 '01' |
| 功能码 | 2字符 | 如 '03' 表示读保持寄存器 |
| 数据区 | 可变 | 实际数据,每个字节用两个ASCII字符表示 |
| LRC校验 | 2字符 | LRC校验值,两个ASCII字符 |
| 结束符 | 2字符 | '\r\n' (回车换行) |
举个例子,读取从站地址01的保持寄存器,起始地址0x0000,读取2个寄存器:
RTU模式(十六进制):
01 03 00 00 00 02 C4 0B
ASCII模式(字符串形式):
: 01 03 00 00 00 02 F7 \r \n
实际发送的ASCII字符:
':' '0' '1' '0' '3' '0' '0' '0' '0' '0' '0' '0' '2' 'F' '7' '\r' '\n'
看到了吗?RTU里一个字节 0x01,在ASCII里变成了两个字符 '0' 和 '1'。这就是效率低的原因。
我个人习惯:调试ASCII模式时,直接用串口助手看文本模式就行。RTU你得开十六进制显示,ASCII直接看字符串,一目了然。这也是它最大的优势——人类可读。
4.3 LRC校验详解
ASCII模式不用CRC,用LRC。LRC全称Longitudinal Redundancy Check,纵向冗余校验。算法比CRC简单得多。
计算步骤:
- 从地址码开始,到数据区结束,把所有字节累加
- 取累加和的补码(按位取反再加1)
- 只保留低8位
说白了就是:LRC = (0xFF - (累加和 & 0xFF)) + 1
咱们用上面的例子算一下:
累加字节:0x01, 0x03, 0x00, 0x00, 0x00, 0x02
累加和 = 0x01 + 0x03 + 0x00 + 0x00 + 0x00 + 0x02 = 0x06
取低8位:0x06
补码:0xFF - 0x06 + 1 = 0xFA
所以LRC = 0xFA,发送时变成字符 'F' 和 'A'
嗯,这里要注意:LRC校验的范围不包括起始符 ':' 和结束符 '\r\n'。只校验地址、功能码和数据区。
我曾经踩过的坑:有一次写ASCII从站程序,LRC算出来总是对不上。查了半天才发现,我把起始符 ':' 也算进校验范围了。记住,LRC只算 ':' 之后、'\r\n' 之前的内容。
4.4 与RTU的对比
咱们直接上对比表,这样最清楚:
| 对比项 | ASCII模式 | RTU模式 |
|---|---|---|
| 数据表示 | 每个字节用2个ASCII字符 | 直接发送二进制字节 |
| 传输效率 | 低,约RTU的一半 | 高 |
| 校验方式 | LRC(2字符) | CRC-16(2字节) |
| 报文分隔 | 有明确起始符 ':' 和结束符 '\r\n' |
靠3.5字符静默时间 |
| 调试难度 | 低,文本可见 | 高,需十六进制查看 |
| 抗干扰能力 | 某些场景下更好(字符可见,易纠错) | 一般 |
| 应用场景 | 老设备、无线通信、电话线 | 绝大多数工业现场 |
我个人的经验是:能用RTU就用RTU。效率高、占用带宽小、CRC校验也比LRC更可靠。但如果你遇到以下情况,可以考虑ASCII:
- 通信链路质量很差,经常丢数据
- 调试阶段,需要快速看报文内容
- 对接的老设备只支持ASCII模式
- 通过无线模块或电话线通信,数据包需要可见字符
避坑指南:我曾经在一个项目中,RTU模式在强电磁干扰下频繁出错。换成ASCII后,虽然速度慢了,但至少数据能收对了。为什么?因为ASCII模式下每个字节都是可见字符,接收端可以更容易地判断数据是否完整。而且有明确的起始和结束标记,不会像RTU那样因为静默时间判断不准而粘包。
4.5 实际应用建议
如果你现在要设计一个新系统,我建议:
- 默认选RTU,这是行业主流,几乎所有设备都支持
- 只有特殊需求才考虑ASCII,比如上面提到的那些场景
- 如果设备同时支持两种模式,优先用RTU,除非测试发现通信不稳定
- 注意波特率,ASCII模式因为效率低,建议用更高的波特率(比如19200以上)来弥补
好了,ASCII协议就讲这么多。下一章咱们聊聊RTU和ASCII之间的转换方案,以及怎么用硬件或软件实现网络桥接。到时候我会分享一个我实际做过的网关项目,挺有意思的。