第2章:Modbus协议基础

各位同学好,我是老张。今天咱们聊聊Modbus协议的基础知识。说实话,我在工业自动化这行摸爬滚打十几年,Modbus是我见过最「长寿」的通信协议之一。你想想看,一个上世纪70年代末诞生的协议,到现在还在大量使用,这本身就说明了很多问题。

2.1 Modbus协议发展历史

Modbus是1979年由Modicon公司(就是现在的施耐德电气)发明的。当时的目的很简单——让PLC和智能设备之间能互相说话。我记得我第一次接触Modbus是在2008年,那时候刚入行,师傅扔给我一本Modbus协议手册,说:「把这个啃下来,你就能搞定80%的现场通信问题。」

嗯,这话还真不夸张。

Modbus的发展大致经历了这么几个阶段:

  • 1979年:Modicon发布Modbus协议,最初用于PLC通信
  • 1990年代:Modbus RTU/ASCII成为工业现场的事实标准
  • 2000年:Modbus TCP/IP发布,开始拥抱以太网
  • 2004年:Modbus组织成立,协议正式成为开放标准
  • 至今:Modbus依然是工业物联网的首选协议之一

核心观点:Modbus能活这么久,靠的就是「简单」二字。协议栈只有7层OSI模型中的3层,实现成本极低。我在项目中见过用8位单片机跑Modbus RTU的,照样稳得很。

2.2 Modbus RTU与Modbus TCP的区别

这个问题我几乎每次培训都会被问到。说白了,RTU和TCP就是Modbus的两种「马甲」——核心数据格式一样,但传输方式不同。

我给大家画个对比表,一目了然:

对比项 Modbus RTU Modbus TCP
物理层 RS-232/RS-485 以太网
传输速率 9.6kbps ~ 115.2kbps 10/100Mbps
最大节点数 32(RS-485) 理论上无限制
传输距离 1200米(RS-485) 100米(交换机可扩展)
地址范围 1~247 IP地址+单元标识符
校验方式 CRC16 TCP/IP协议栈自带
报文格式 地址+功能码+数据+CRC MBAP头+功能码+数据

实战经验:我个人习惯是:现场总线用RTU,跨系统通信用TCP。为什么?RTU在强电磁干扰环境下更稳定,而TCP方便远程调试。有一次我在一个钢厂项目里,RTU线缆从控制室拉到轧机旁边,1200米距离,一点问题没有。

这里有个关键区别大家要注意:RTU是主从架构,TCP是对等架构。什么意思?RTU模式下,只有主机能发起通信,从机只能被动响应。而TCP模式下,任何设备都可以主动发起请求。这个差异在实际项目中影响很大。

2.3 Modbus协议栈结构

Modbus协议栈其实很简单,就三层:

  1. 应用层:定义功能码和数据格式
  2. 数据链路层:处理报文封装和校验
  3. 物理层:负责电气信号传输

我画了一张结构图,大家看看就明白了:

Modbus协议栈结构 应用层 功能码(01~127)+ 数据格式(线圈、寄存器、离散输入等) 数据链路层 报文封装(地址域+功能码+数据+校验) 物理层 RS-232 / RS-485 / 以太网 OSI第7层 OSI第2层 OSI第1层

咱们重点说说应用层的功能码。这是Modbus最核心的部分,我给大家列几个常用的:

功能码 名称 操作对象 读写类型
01 (0x01) 读取线圈状态 DO(数字量输出) 只读
02 (0x02) 读取离散输入 DI(数字量输入) 只读
03 (0x03) 读取保持寄存器 AO(模拟量输出) 只读
04 (0x04) 读取输入寄存器 AI(模拟量输入) 只读
05 (0x05) 写单个线圈 DO 只写
06 (0x06) 写单个寄存器 AO 只写
15 (0x0F) 写多个线圈 DO 只写
16 (0x10) 写多个寄存器 AO 只写

避坑指南:我曾经在一个项目中,把功能码03和04搞混了。03读的是保持寄存器(可读可写),04读的是输入寄存器(只读)。当时调试了半天,数据死活不对。后来才发现是功能码用错了。大家记住:保持寄存器是「可写的」,输入寄存器是「只读的」。

再来说说数据格式。Modbus的数据模型分四种:

  • 线圈(Coil):1位,可读可写,对应DO
  • 离散输入(Discrete Input):1位,只读,对应DI
  • 输入寄存器(Input Register):16位,只读,对应AI
  • 保持寄存器(Holding Register):16位,可读可写,对应AO

这里有个小技巧:保持寄存器是Modbus通信中最常用的对象。为什么?因为它既能读又能写,而且16位的数据宽度足够表示大多数工业参数。我在做机器人通信接口时,90%的数据都放在保持寄存器里。

最后说说报文格式。RTU和TCP的报文结构略有不同:

// Modbus RTU报文格式
[从站地址(1字节)] [功能码(1字节)] [数据(N字节)] [CRC低字节] [CRC高字节]

// Modbus TCP报文格式
[事务标识符(2字节)] [协议标识符(2字节)] [长度(2字节)] [单元标识符(1字节)] [功能码(1字节)] [数据(N字节)]

你看,TCP报文比RTU多了个MBAP头(7字节)。这个头的作用是让TCP能识别不同的Modbus会话。嗯,这里要注意:TCP报文没有CRC校验,因为TCP/IP协议栈自己会处理数据完整性。

个人建议:刚开始学Modbus的同学,我建议先从RTU入手。为什么?RTU的报文结构更直观,而且调试工具多。等你把RTU搞明白了,TCP就是加了个头的事。我当年就是这么过来的。

好了,这一章的内容就到这里。Modbus协议看似简单,但里面的细节不少。下一章我们会动手写代码,用Python实现一个Modbus RTU通信接口。到时候大家就能体会到,理论知识和实战经验结合起来,才是真正的「会了」。


专注资料整理