2. Modbus协议原理与数据模型:Modbus起源、主从架构、四种数据模型(DI、DO、AI、AO)、功能码分类

各位同学,咱们今天聊聊Modbus。说实话,这玩意儿在工业现场太常见了。我做了十几年边缘计算,几乎每个项目都离不开它。你想想看,从PLC到变频器,从温控表到智能电表,Modbus就像工业界的“普通话”。不懂它,你根本没法跟设备对话。

2.1 Modbus的起源:一个“老古董”为何至今活跃?

Modbus是1979年由Modicon公司(就是现在的施耐德电气)发明的。那时候还没有以太网,串口通信是主流。我记得第一次接触Modbus是在一个老旧的水处理厂,那台PLC还是90年代的,但Modbus RTU跑得稳稳的。

为什么这个“老古董”到现在还没被淘汰?说白了,就三个字:简单、开放、可靠。Modbus协议帧结构非常简洁,一个请求帧也就几个字节。我在项目中见过最极端的案例——用一对双绞线,通过Modbus RTU拉了1200米,照样稳定通信。换成其他协议,早丢包丢到姥姥家了。

核心要点:Modbus是应用层协议,它不关心底层物理层是RS-232、RS-485还是以太网。这种分层设计让它能“活”到现在。

2.2 主从架构:谁说了算?

Modbus采用主从(Master/Slave)架构。嗯,这里要注意,现在有些文档改叫“客户端/服务器”了,但工业现场的老工程师还是习惯叫主从。

主从架构的规则很简单:

  • 主站(Master):只有一个,负责发起所有通信。它问,从站才能答。
  • 从站(Slave):可以有多个(最多247个),每个有唯一地址(1-247)。从站不能主动说话,只能等主站点名。

我曾经在一个项目中踩过坑。现场有台变频器,怎么都通信不上。查了半天,发现是有人把从站地址设成了0。Modbus规定地址0是广播地址,所有从站都会接收但不会回复。嗯,这个坑我记了好几年。

避坑指南:从站地址范围是1-247,地址0用于广播,248-255保留。我曾经见过有人把地址设成255,结果设备直接“装死”。

2.3 四种数据模型:DI、DO、AI、AO

Modbus把数据分成四种类型。这个分类很巧妙,你想想看,工业现场无非就是开关量和模拟量,输入和输出。Modbus用四个表格就把它们全装下了。

数据模型 对象类型 访问类型 数据大小 地址范围
DI(离散量输入) 只读开关量 只读 1 bit 10001-19999
DO(离散量输出/线圈) 读写开关量 读写 1 bit 00001-09999
AI(模拟量输入) 只读寄存器 只读 16 bit 30001-39999
AO(模拟量输出/保持寄存器) 读写寄存器 读写 16 bit 40001-49999

我个人习惯这样记:

  • DI:按钮、限位开关、光电传感器——只能读,不能写
  • DO:继电器、指示灯、电磁阀——能读也能写
  • AI:温度、压力、流量传感器——4-20mA或0-10V信号,只读
  • AO:变频器频率设定、阀门开度控制——能读也能写

实战技巧:很多新手搞混地址。记住一个口诀:“0开头是线圈,1开头是输入,3开头是AI,4开头是AO”。我在调试时经常用这个口诀快速定位问题。

2.4 功能码分类:Modbus的“指令集”

功能码就是Modbus的指令。主站发一个功能码,从站就知道要干什么。常用的功能码就那么几个,我列个表给你看:

功能码 名称 操作对象 说明
01 (0x01) 读线圈 DO 读取DO的状态(ON/OFF)
02 (0x02) 读离散量输入 DI 读取DI的状态
03 (0x03) 读保持寄存器 AO 最常用的功能码,读取AO数据
04 (0x04) 读输入寄存器 AI 读取AI数据
05 (0x05) 写单个线圈 DO 控制单个DO
06 (0x06) 写单个寄存器 AO 写入单个AO数据
15 (0x0F) 写多个线圈 DO 批量控制DO
16 (0x10) 写多个寄存器 AO 批量写入AO数据

为什么功能码这么重要?我给你举个例子。有一次我在调试一个边缘网关,读取温湿度数据时一直返回错误。后来发现,我把功能码03(读保持寄存器)用成了功能码04(读输入寄存器)。那台温湿度传感器用的是AI数据模型,只能用04读取。就这么一个码的区别,折腾了我两个小时。

记住:功能码03和04是最常用的。03读AO(保持寄存器),04读AI(输入寄存器)。搞反了,数据就读不出来。

2.5 一个完整的Modbus请求示例

光说不练假把式。咱们看一个实际的Modbus RTU请求帧。假设主站要读取从站地址为1的设备,从地址40001开始读2个保持寄存器:

请求帧(主站→从站):
01 03 00 00 00 02 C4 0B

解析:
01    - 从站地址
03    - 功能码(读保持寄存器)
00 00 - 起始地址(40001对应协议地址0x0000)
00 02 - 读取数量(2个寄存器)
C4 0B - CRC校验

响应帧(从站→主站):
01 03 04 00 0A 00 14 7A 9E

解析:
01    - 从站地址
03    - 功能码
04    - 数据字节数(2个寄存器=4字节)
00 0A - 第一个寄存器值(10)
00 14 - 第二个寄存器值(20)
7A 9E - CRC校验

你看,就这么简单。一个请求帧才8个字节,响应帧也才9个字节。这就是Modbus能在低速串口上跑得飞快的原因。

调试技巧:我建议你准备一个Modbus调试工具,比如ModScan或Modbus Poll。刚开始学的时候,用工具发几个功能码试试,看看设备怎么响应。比看文档管用多了。

2.6 边缘计算中的Modbus应用

在边缘计算场景下,Modbus通常扮演“数据采集”的角色。边缘网关作为Modbus主站,轮询各个从站设备,把数据采集上来,再通过MQTT或OPC UA上传到云端。

我个人习惯的做法是:

  1. 先搞清楚数据模型:哪些是DI,哪些是AI,哪些是AO。别搞混了。
  2. 规划地址映射:把Modbus地址映射到边缘网关的内部变量。
  3. 设置轮询周期:DI和DO可以快一点(100ms),AI和AO可以慢一点(1s)。
  4. 处理异常:从站掉线、超时、CRC错误,都要有处理机制。

重要提醒:Modbus RTU是半双工通信,主站发完请求后必须等待从站回复。如果从站没回复,主站不能立即发下一个请求。我见过有人把超时时间设成10ms,结果在长距离通信时频繁超时。建议至少设200ms以上。

好了,这一章的内容就到这里。Modbus协议原理其实不复杂,但细节很多。你只要把主从架构、四种数据模型、功能码分类这三个核心概念搞明白,后面实战部分就会轻松很多。下一章咱们聊聊Modbus RTU和Modbus TCP的区别,以及在实际项目中怎么选型。