4、Modbus ASCII帧结构:ASCII报文格式、LRC校验原理与计算、RTU与ASCII对比、何时选择ASCII

好,咱们今天聊聊Modbus的另一种传输模式——ASCII模式。

说实话,我在现场调试时,ASCII模式用得不算多。但每次用到它,都是因为RTU模式实在搞不定了。你想想看,一个系统里既有Modbus设备,又有各种打印终端、人机界面,字符集乱成一锅粥。这时候,ASCII模式就像个救火队员。

我个人习惯,把ASCII模式看作是RTU模式的“文本版”。它把每个字节拆成两个ASCII字符来发送。说白了,就是让数据变得“可读”了。

4.1 ASCII报文格式

ASCII帧的结构,跟RTU有点像,但细节上差别很大。咱们直接看格式:

起始符 | 地址码 | 功能码 | 数据区 | LRC校验码 | 结束符
  ':'   |  1字节 |  1字节 |  N字节  |   1字节   | CR+LF

嗯,这里要注意几个关键点:

  • 起始符:固定是冒号 ':'(0x3A)。这是帧开始的标志。
  • 地址码、功能码、数据区:这些字段的内容,每个字节都要拆成两个ASCII字符发送。比如地址0x11,就发送字符'1'和'1'(即0x31, 0x31)。
  • LRC校验码:1个字节,同样拆成两个ASCII字符。
  • 结束符:回车换行(0x0D, 0x0A)。

举个例子,我要读取地址为0x11的设备的保持寄存器,起始地址0x0000,读取2个寄存器。RTU模式下报文是:11 03 00 00 00 02 CRC。换成ASCII模式,就变成了:

: 11 03 00 00 00 02 LRC \r\n

注意,这里的1103等,都是ASCII字符。实际发送的是:3A 31 31 30 33 30 30 30 30 30 30 30 32 LRC 0D 0A

我在项目中遇到过,有人把ASCII帧里的地址码直接当二进制发,结果设备死活不响应。记住,ASCII模式下,所有数据字段都是字符,不是原始字节。

4.2 LRC校验原理与计算

LRC,全称是纵向冗余校验。它比CRC简单得多,但防护能力也弱一些。

计算原理:从地址码开始,到数据区的最后一个字节,所有字节做累加,然后取补码。

公式很简单:

LRC = ( (累加和) 取反 ) + 1

或者更直接:LRC = 0x100 - (累加和 & 0xFF)

咱们手算一下刚才的例子:

地址码: 0x11
功能码: 0x03
起始地址高: 0x00
起始地址低: 0x00
寄存器数高: 0x00
寄存器数低: 0x02

累加和 = 0x11 + 0x03 + 0x00 + 0x00 + 0x00 + 0x02 = 0x16
LRC = 0x100 - 0x16 = 0xEA

所以,完整的ASCII帧发送内容为:: 11 03 00 00 00 02 EA \r\n。注意,EA也要拆成字符'E'和'A'发送。

我的小技巧:写代码时,LRC计算可以用一个循环搞定。我习惯用C语言这样写:
unsigned char calcLRC(unsigned char *data, int len) {
    unsigned char sum = 0;
    for (int i = 0; i < len; i++) {
        sum += data[i];
    }
    return (unsigned char)(0x100 - sum);
}
注意,len是从地址码开始到数据区结束的长度,不包括起始符和结束符。
避坑指南:我曾经在调试一个老款PLC时,发现它把LRC校验码当作有符号数处理。结果0x80以上的值全算错。后来我改成用无符号字节累加,问题才解决。所以,写校验代码时,一定要确认数据类型。

4.3 RTU与ASCII对比

咱们直接上表格,一目了然:

对比项 RTU模式 ASCII模式
数据表示 二进制字节 ASCII字符(每个字节拆成2个字符)
帧长度 短(约是ASCII的一半) 长(约是RTU的两倍)
传输效率 高(同样波特率下,吞吐量更大) 低(同样波特率下,吞吐量减半)
校验方式 CRC-16(2字节,强校验) LRC(1字节,弱校验)
帧间隔 3.5字符时间(严格) 无严格时间要求(靠起始/结束符)
可读性 差(全是二进制,人眼难辨) 好(可以直接用串口助手看)
适用场景 高速、可靠、工业现场 低速、调试、字符环境

你想想看,RTU模式为什么效率高?因为它每个字节就是实实在在的数据。而ASCII模式,发一个字节的数据,要占用两个字符的时间。同样9600波特率,RTU能发更多数据包。

但ASCII模式有个RTU比不了的优势——它不怕帧间隔。RTU要求帧内字节间隔不能超过3.5个字符时间,否则就认为帧结束了。这在一些实时性不高的系统里,很容易出问题。ASCII模式靠':'CR+LF来定界,你就算中间停顿几秒钟,只要没收到结束符,设备就还在等。

4.4 何时选择ASCII

我个人经验,以下情况优先考虑ASCII模式:

  • 调试阶段:用串口助手直接看报文,ASCII模式一目了然。我调试新设备时,经常先用ASCII模式把通信调通,再切回RTU。
  • 与字符设备通信:比如某些老式打印机、字符终端、GPS接收器,它们只认ASCII字符。这时候用ASCII模式,兼容性最好。
  • 通信链路不可靠:如果线路干扰大,或者中间有转发设备会随意插入字符,RTU的3.5字符时间间隔很容易被破坏。ASCII模式靠帧头帧尾定界,抗干扰能力强一些。
  • 低速系统:比如1200波特率,RTU模式下的3.5字符时间间隔长达30多毫秒。如果主站轮询周期长,用ASCII模式反而更稳定。
我的建议:除非有特殊需求,否则默认用RTU模式。ASCII模式更像是个“备胎”,但在某些场景下,这个备胎能救命。

嗯,ASCII模式的内容就这些。它不复杂,但细节容易踩坑。记住核心:数据拆成字符发,LRC校验要算对,帧头帧尾不能丢。下次你遇到RTU搞不定的情况,不妨试试ASCII模式。

Modbus ASCII 帧结构知识体系 ASCII帧结构 报文格式 起始符 ':' (0x3A) 地址+功能+数据(ASCII) 结束符 CR+LF (0x0D 0x0A) LRC校验原理与计算 累加和 → 取反 → +1 LRC = 0x100 - (累加和 & 0xFF) 结果转ASCII字符发送 RTU vs ASCII 对比与选择 RTU:高效、CRC强校验、严格时序 ASCII:可读、LRC弱校验、无时序要求 选择:调试/字符设备/不可靠链路

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