第三章 通信协议基础:Modbus协议详解

说到工业通信,Modbus是个绕不开的话题。我入行那会儿,第一个接触的协议就是它。说实话,这玩意儿虽然老,但真管用。你想想看,一个1980年代诞生的协议,到现在还在大量使用,本身就说明问题。

3.1 Modbus协议的前世今生

Modbus是Modicon公司(现在叫施耐德电气)搞出来的。最初是为了让PLC和智能设备之间能说上话。我记得第一次在项目里用Modbus时,心里还犯嘀咕:这么简单的协议,能行吗?后来发现,正是因为它简单,才活得这么久。

核心特点:

  • 主从架构(Master/Slave)—— 一个主站,多个从站
  • 简单可靠 —— 报文结构清晰,调试方便
  • 开放免费 —— 不用交授权费,谁都能用
  • 硬件适应性强 —— 串口、网口都能跑

3.2 RTU与TCP模式的区别

Modbus有两种主流传输模式:RTU和TCP。很多新手搞不清区别,我刚开始也迷糊过。说白了,RTU走串口,TCP走网口。

3.2.1 Modbus RTU

RTU模式是二进制传输,效率高。我在一个水处理项目里用过,现场全是RS485总线,几十个仪表挂在一根线上。嗯,这里要注意:RTU模式有严格的时序要求。

RTU关键参数:

  • 报文间隔:3.5个字符时间(不能多不能少)
  • 校验方式:CRC16(循环冗余校验)
  • 典型波特率:9600、19200、38400
  • 数据格式:1位起始位 + 8位数据位 + 1位停止位(无校验或奇偶校验)

我曾经踩过一个坑:现场设备响应慢,我以为是协议问题,查了半天。结果发现是波特率设错了,从站和主站对不上。从那以后,我调试Modbus RTU的第一件事就是确认波特率。

3.2.2 Modbus TCP

TCP模式就简单多了。它基于以太网,用502端口。报文里没有CRC校验,因为TCP/IP协议栈已经帮你做了。我个人习惯在SCADA系统里优先用TCP,调试方便,不用纠结时序问题。

RTU vs TCP 快速对比:

对比项 RTU TCP
物理层 RS232/RS485 以太网
传输距离 约1200米(RS485) 100米(可扩展)
校验方式 CRC16 TCP/IP自带
从站数量 最多247个 理论上无限制
实时性 较高(取决于波特率) 受网络影响

3.3 数据模型详解

Modbus定义了四种数据对象。我刚开始学的时候,总觉得这四种东西容易搞混。其实你只要记住:位和字,读和写,四个组合就出来了。

3.3.1 线圈(Coils)—— 可读可写的位

线圈就是开关量输出。比如控制一个继电器、启动一台电机。功能码是01(读线圈)和05(写单个线圈)、15(写多个线圈)。

// 读取线圈示例(功能码01)
请求:01 01 00 00 00 0A BC CD
      |  |  |     |     |
      从站地址 功能码 起始地址 数量(10个) CRC

响应:01 01 02 03 00 B8 34
      |  |  |  |     |
      从站地址 功能码 字节数 线圈状态 CRC

实际项目经验:我在一个自动化产线里,用线圈控制气缸的伸缩。注意:线圈地址从0开始,但很多PLC的组态软件从1开始显示。这个偏移量坑过不少人。

3.3.2 离散输入(Discrete Inputs)—— 只读的位

离散输入就是开关量输入。比如读取一个限位开关的状态、一个按钮是否按下。功能码是02。

说白了,线圈和离散输入的区别就一句话:线圈你能控制,离散输入你只能看

3.3.3 保持寄存器(Holding Registers)—— 可读可写的字

保持寄存器是16位的,可以读写。这是最常用的数据对象。比如设定温度值、PID参数、运行频率等。功能码是03(读)和06(写单个)、16(写多个)。

// 读取保持寄存器示例(功能码03)
请求:01 03 00 64 00 02 C5 F6
      |  |  |     |     |
      从站地址 功能码 起始地址(100) 数量(2个) CRC

响应:01 03 04 00 0A 00 14 7A 5B
      |  |  |  |     |
      从站地址 功能码 字节数 数据(10和20) CRC

我的习惯:在SCADA系统中,所有需要下发的参数都放在保持寄存器里。比如设定温度、报警阈值等。这样上位机可以随时修改,下位机也能实时响应。

3.3.4 输入寄存器(Input Registers)—— 只读的字

输入寄存器也是16位的,但只能读不能写。通常用来存放传感器采集的数据,比如温度值、压力值、流量值。功能码是04。

你想想看,为什么要有只读的寄存器?因为有些数据是现场采集的,你不能让上位机随便改。比如一个温度传感器的读数,改了就没意义了。

地址映射注意事项:

  • Modbus协议中地址从0开始
  • 很多设备手册从1开始描述
  • 比如手册说"保持寄存器40001",实际协议地址是0
  • 这个偏移量问题,我见过太多人栽跟头了

3.4 实战经验总结

做了这么多年SCADA,我总结了几条Modbus的实战经验:

  1. 先确认物理连接—— 串口的话,A/B线别接反;网口的话,IP地址要通
  2. 用调试工具先测—— 我习惯用Modscan或Modpoll,先确认设备能正常响应
  3. 注意超时设置—— RTU模式超时建议设500ms以上,TCP可以短一些
  4. 批量读写效率高—— 尽量用功能码03/16一次读写多个寄存器,别一个一个来
  5. 异常码要处理—— 设备返回异常码时,别忽略,那是它在告诉你问题

一句话总结:Modbus不复杂,但细节决定成败。把四种数据对象搞清楚,RTU和TCP选对,你的SCADA系统就成功了一半。

下一章,我会带你实际搭建一个Modbus通信的测试环境。到时候咱们手把手操作,把今天讲的理论用起来。