3. 串行通信协议:Modbus 家族详解

各位同学,今天咱们来聊聊Modbus。说实话,这玩意儿在工控圈子里,就跟咱们吃饭用筷子一样普遍。我做了十几年变电站自动化,几乎每个项目都离不开它。Modbus之所以能活这么久,说白了就是——简单、可靠、够用。

Modbus其实是个大家族,主要有三个兄弟:RTU、ASCII和TCP。咱们一个一个来盘。

3.1 Modbus RTU 协议帧结构

RTU是我用得最多的,也是现场最主流的。它的帧结构长这样:

| 地址码(1字节) | 功能码(1字节) | 数据区(N字节) | CRC校验(2字节) |

嗯,就这么简单。我给大家拆开讲讲:

  • 地址码:从站地址,范围1-247。0是广播地址,所有设备都得听。
  • 功能码:告诉从站你要干啥。比如03是读寄存器,06是写单个寄存器。
  • 数据区:具体的数据内容,长度可变。
  • CRC校验:16位循环冗余校验,保证数据没被干扰。
我的经验:现场调试时,CRC算错是最常见的坑。我建议你手边常备一个CRC计算器,或者直接用调试软件自动算。别问我怎么知道的——我曾经在变电站现场对着示波器看了两个小时,最后发现是CRC算反了字节序。

RTU的传输是二进制格式,效率高。但有个硬性要求:报文之间必须有3.5个字符时间的间隔。为什么?这是为了区分两条不同的报文。你想想看,如果连续发数据,从站怎么知道哪一段是一条完整的报文?

3.2 Modbus ASCII 协议

ASCII版本,说白了就是把RTU的二进制数据转成ASCII字符来传。每个字节拆成两个十六进制字符,比如0x1A就变成'1'和'A'两个字符。

它的帧结构多了个开头和结尾:

| ':' (0x3A) | 地址码(2字符) | 功能码(2字符) | 数据区(2N字符) | LRC校验(2字符) | CR/LF |

你可能会问:明明RTU效率更高,为什么还要用ASCII?

我遇到过这种情况:有些老旧设备或者通信链路质量很差,RTU的二进制数据容易出错。ASCII虽然慢,但每个字符都是可见的,调试起来方便。而且它的校验方式是LRC(纵向冗余校验),比CRC简单。

注意:ASCII的传输效率只有RTU的一半左右。同样的数据量,ASCII要传两倍的字符。在变电站这种对实时性有要求的场景,我个人不太推荐用ASCII,除非万不得已。

3.3 Modbus TCP 协议

TCP版本,就是把Modbus封装在TCP/IP协议里。它的帧结构变了:

| MBAP头(7字节) | 功能码(1字节) | 数据区(N字节) |

MBAP头包含:事务处理标识符(2字节)、协议标识符(2字节)、长度(2字节)、单元标识符(1字节)。

这里有个关键点:TCP版本没有CRC校验了。为什么?因为TCP/IP协议栈自己会做校验,你再做一遍就是画蛇添足。嗯,设计者考虑得很周到。

我在做变电站远程监控时,经常用Modbus TCP。只要网络通,就能读到数据。但要注意一点:TCP是面向连接的,如果网络断了,你得自己处理重连逻辑。我曾经有个项目,就因为没处理好重连,导致后台画面卡死——从那以后,我写的每个TCP客户端都加了心跳和自动重连。

3.4 功能码详解

功能码是Modbus的核心。我整理了一张表,大家收藏好:

功能码 名称 作用 我常用的场景
01 读线圈状态 读取DO输出 读取断路器分合位
02 读离散输入 读取DI输入 读取刀闸位置信号
03 读保持寄存器 读取模拟量/参数 读取电压、电流、功率
04 读输入寄存器 读取只读模拟量 读取温度、湿度传感器
05 写单个线圈 控制单个DO 遥控分合闸
06 写单个寄存器 设置单个参数 修改定值、设置阈值
15 写多个线圈 批量控制DO 批量投切电容器组
16 写多个寄存器 批量设置参数 批量下装保护定值

功能码03和06是我用得最多的。03用来读遥测数据,06用来写遥调指令。举个例子:

// 读从站地址01,从寄存器地址0x0000开始,读2个寄存器
请求:01 03 00 00 00 02 C4 0B
响应:01 03 04 00 01 00 02 79 CB
// 响应数据:寄存器0x0000=0x0001,寄存器0x0001=0x0002
避坑指南:我曾经遇到过一个问题:读回来的数据死活不对。查了半天,发现是寄存器地址偏移了。有些设备寄存器地址从0开始,有些从1开始。你写代码时一定要确认清楚,不然数据全乱套。

3.5 知识体系总览

下面这张图,是我自己画的Modbus知识体系。你看一眼,心里就有数了:

Modbus 协议知识体系 Modbus RTU 二进制传输 CRC16校验 3.5字符间隔 Modbus ASCII ASCII字符传输 LRC校验 ':'开头 CR/LF结尾 Modbus TCP TCP/IP封装 MBAP头(7字节) 无CRC校验 功能码:01 02 03 04 05 06 15 16 三种协议共用同一套功能码体系 区别仅在于传输层封装和校验方式

你看这张图就明白了:三种协议虽然传输方式不同,但功能码是通用的。你学会了RTU,ASCII和TCP基本就是换个壳子。

我的建议:初学者先把RTU吃透。现场90%的设备都支持RTU。等你把RTU玩熟了,ASCII和TCP自然就通了。我当年就是这么过来的——先啃硬骨头,后面就轻松了。

好了,Modbus这块就讲到这里。记住一句话:Modbus不复杂,复杂的是现场的各种坑。多动手、多调试,慢慢就有感觉了。


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