3. Modbus RTU协议详解:帧结构、主从通信与实战功能码

大家好,我是老张。今天咱们来啃Modbus RTU协议这块硬骨头。说实话,这协议在工业现场太常见了,从PLC到变频器,从温控表到智能仪表,几乎都在用。我个人习惯把Modbus RTU比作工业通信的“普通话”——虽然不花哨,但大家都听得懂。

核心要点:Modbus RTU是一种主从式、半双工的串行通信协议。它简单、可靠、成本低,是工业自动化领域应用最广泛的协议之一。

3.1 帧结构:四个关键部分

一个完整的Modbus RTU报文帧,说白了就四个部分:地址码、功能码、数据区、CRC校验。我刚开始接触时总觉得这结构太简单,后来才发现,越简单的东西越不容易出错。

字段 长度 说明
地址码 1字节 从站地址,范围1-247,0为广播地址
功能码 1字节 指示操作类型,如03读保持寄存器
数据区 N字节 包含起始地址、寄存器数量、数据值等
CRC校验 2字节 循环冗余校验,低字节在前

3.2 地址码:给每个设备一个身份证

地址码是1个字节,范围1到247。0是广播地址,所有从站都会接收但不回复。248到255是保留地址,别乱用。

避坑指南:我曾经在一个项目中,把两个温控器都设成了地址1。结果主站发指令时,两个设备同时响应,数据全乱套了。排查了整整半天才发现是地址冲突。所以我的建议是:设备地址一定要在项目文档里登记清楚,最好用标签贴在设备上。

3.3 功能码:告诉设备要干什么

功能码就1个字节,但含义丰富。常用的功能码就那么几个:

  • 03 (0x03):读保持寄存器。最常用的功能码,读取多个寄存器的值。
  • 06 (0x06):写单个寄存器。写一个16位数据到指定寄存器。
  • 16 (0x10):写多个寄存器。一次写多个连续寄存器。

你想想看,现场90%以上的Modbus通信,其实就靠这三个功能码撑着。其他的像01、02、04、05、15这些,虽然也有用,但频率低得多。

3.4 数据区:真正的信息载体

数据区是帧结构中最灵活的部分。以03功能码为例,数据区包含:

  • 起始地址(2字节):要读取的第一个寄存器地址。注意,Modbus地址是从0开始的,但很多设备手册里写的是从1开始的地址。嗯,这里要注意:手册里的地址通常要减1才是协议里的地址。
  • 寄存器数量(2字节):连续读取的寄存器个数。最大125个,因为一帧报文不能太长。

举个例子,要读取从站地址1的寄存器40001到40003(手册地址),实际协议地址是0x0000到0x0002,数量是3。报文是这样的:

请求:01 03 00 00 00 03 05 CB
响应:01 03 06 00 01 00 02 00 03 3A 9B

响应报文里,06表示后面有6个字节数据(3个寄存器,每个2字节),00 01、00 02、00 03就是三个寄存器的值。

3.5 CRC校验:数据完整性的守护神

CRC校验是Modbus RTU的“防错机制”。它用2个字节,对整个报文(地址码+功能码+数据区)进行校验。计算方法是CRC-16/MODBUS,多项式是0x8005。

我个人习惯用查表法计算CRC,速度快,适合嵌入式系统。现场通信时,如果CRC校验不过,从站会直接丢弃报文,不会回复。我曾经遇到过一台变频器,通信时好时坏,最后发现是CRC计算芯片坏了,换了块板子就好了。

小技巧:调试时可以用串口助手抓报文,手动计算CRC来验证。网上有很多在线CRC计算工具,很方便。

3.6 主从站通信机制:一问一答

Modbus RTU是典型的主从通信。主站(通常是PLC或上位机)发起请求,从站(传感器、执行器等)响应。同一时刻只能有一个主站,多个从站。

通信流程是这样的:

  1. 主站发送请求帧,包含目标从站地址、功能码、数据。
  2. 所有从站都收到这个帧,但只有地址匹配的那个从站会处理。
  3. 从站执行操作,然后发送响应帧给主站。
  4. 主站收到响应,解析数据,完成一次通信。

如果从站没响应,主站通常会重试3次,超时时间一般设500ms到1s。我建议超时时间别设太短,有些老设备反应慢,容易误判为通信故障。

3.7 03功能码实战:读保持寄存器

03功能码是最常用的。比如我要读取一个温度传感器的当前值,寄存器地址是40001(协议地址0x0000)。

请求帧:

01 03 00 00 00 01 84 0A

解释:01是从站地址,03是功能码,00 00是起始地址,00 01是读取1个寄存器,84 0A是CRC校验。

响应帧:

01 03 02 01 2C B8 1B

解释:01是从站地址,03是功能码,02是数据长度(2字节),01 2C是寄存器值(十进制300,表示30.0℃),B8 1B是CRC校验。

3.8 06功能码实战:写单个寄存器

06功能码用于写单个寄存器。比如我要把变频器的频率设为50.0Hz,寄存器地址是40001(协议地址0x0000),值设为500(表示50.0Hz)。

请求帧:

01 06 00 00 01 F4 48 0A

解释:01是从站地址,06是功能码,00 00是寄存器地址,01 F4是写入值(十进制500),48 0A是CRC校验。

响应帧:

01 06 00 00 01 F4 48 0A

注意:06功能码的响应帧和请求帧完全一样,这叫“回显”。如果不一样,说明写失败了。

警告:写寄存器操作要谨慎!我曾经在调试时不小心写错了值,把变频器的最大频率设成了0Hz,结果电机直接停了。所以写操作前一定要确认数据正确,最好加个“写前确认”的逻辑。

3.9 16功能码实战:写多个寄存器

16功能码(0x10)用于一次写多个连续寄存器。比如我要同时设置变频器的频率和加减速时间,寄存器地址40001和40002。

请求帧:

01 10 00 00 00 02 04 01 F4 00 64 9A 1B

解释:01是从站地址,10是功能码,00 00是起始地址,00 02是写2个寄存器,04是后面数据长度(4字节),01 F4是第一个寄存器值(500,频率50.0Hz),00 64是第二个寄存器值(100,加速时间10.0秒),9A 1B是CRC校验。

响应帧:

01 10 00 00 00 02 41 C8

解释:响应帧只返回起始地址和寄存器数量,不返回具体数据。这样报文更短,效率更高。

3.10 知识体系总览

下面这张图是我自己画的,把Modbus RTU的核心知识点串起来了。你看一遍,心里就有谱了。

Modbus RTU协议知识体系 帧结构 • 地址码 (1字节, 1-247) • 功能码 (1字节, 03/06/16等) • 数据区 (N字节, 灵活可变) • CRC校验 (2字节, 低字节在前) 总长度: 最少8字节, 最多256字节 主从通信机制 • 主站发起请求 (一问) • 从站响应回复 (一答) • 地址匹配机制 • 超时重试 (3次, 500ms-1s) 半双工通信, 同一时刻只能一个主站 三大实战功能码 03 读保持寄存器 请求: 地址+03+起始地址+数量+CRC 响应: 地址+03+数据长度+数据+CRC 最多读125个寄存器 06 写单个寄存器 请求: 地址+06+寄存器地址+值+CRC 响应: 回显请求帧 (完全一致) 写前务必确认数据正确 16 写多个寄存器 请求: 地址+10+起始地址+数量+数据+CRC 响应: 地址+10+起始地址+数量+CRC 一次最多写123个寄存器 掌握帧结构 + 主从机制 + 三个功能码 = 搞定90%的Modbus RTU应用

好了,Modbus RTU的核心内容就这些。帧结构、主从通信、三个实战功能码,你只要把这几个点吃透了,现场调试基本不会卡壳。记住我一句话:协议是死的,人是活的。多动手抓报文,多分析异常情况,慢慢就熟练了。

老张的总结:Modbus RTU之所以能活这么多年,靠的就是简单可靠。别把它想得太复杂,它就是一套“谁说话、说什么、怎么确认”的规则。你按规则来,设备就听话。


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