1. Modbus协议基础:从一根线到工业通信的基石

各位同学,咱们今天聊聊Modbus协议。说实话,这玩意儿在工业现场太常见了。我入行那会儿,第一个项目就是拿Modbus RTU去控制一台西门子变频器。当时啥也不懂,就记得调试时死活连不上,最后发现是终端电阻没焊上……嗯,这些坑咱们今天一并讲清楚。

1.1 Modbus协议发展史:一个老协议凭什么活到现在?

Modbus是1979年由Modicon公司(就是现在的施耐德电气)发明的。你想想看,都快半个世纪了,它还在用。为什么?说白了就三个字:简单、开放、够用

我个人的理解是,Modbus的成功不在于技术多先进,而在于它把通信这件事做到了极致简单。当年PLC刚出来,大家需要一种通用的方式让PLC和变频器、仪表、传感器对话。Modbus就是那个“通用语言”。

后来Modbus TCP/IP版本在1999年推出,算是给这个老协议续了命。现在你去工厂看看,新设备基本都支持Modbus TCP,但老设备还是RTU居多。我在一个水泥厂改造项目里,就遇到过2002年产的变频器,只认RTU模式——没办法,只能老老实实写RTU代码。

关键时间节点:

  • 1979年:Modbus诞生,串行通信为主
  • 1999年:Modbus TCP/IP标准发布
  • 2004年:成为国家标准GB/T 19582
  • 现在:全球最广泛使用的工业通信协议之一

1.2 RTU与ASCII模式:两种“方言”的区别

Modbus串行通信有两种模式:RTU和ASCII。很多初学者搞不清,我当年也迷糊过。其实区别很简单——数据怎么打包

RTU模式(远程终端单元)

RTU用二进制传输,效率高。一个字节就是8位,直接发。比如你要发一个数值100,RTU模式下就是0x64(十六进制)。

我习惯用RTU,因为速度快。在9600波特率下,RTU每秒能传大约120个数据包,ASCII只能传60个左右。现场设备多的时候,这个差距就很明显了。

ASCII模式

ASCII模式把每个字节拆成两个ASCII字符发。比如0x64,ASCII模式要发'6'和'4'两个字符(0x36和0x34)。数据量翻倍,速度自然慢。

那为什么还要用ASCII?嗯,这里有个坑——ASCII模式允许字符间有长达1秒的间隔。RTU要求数据包必须连续发送,间隔不能超过3.5个字符时间。有些老设备或者无线通信链路不稳定,RTU容易超时,ASCII反而更可靠。

对比项 RTU模式 ASCII模式
数据编码 二进制(8位) ASCII字符(16位)
传输效率 低(约RTU的一半)
错误校验 CRC-16 LRC(纵向冗余校验)
字符间隔 ≤1.5字符时间 ≤1秒
适用场景 高速、稳定链路 低速、不稳定链路

我的建议:新项目优先用RTU。如果遇到通信不稳定,再考虑切ASCII。我曾经在一个光伏电站项目里,因为现场电磁干扰严重,RTU老是CRC校验失败,最后换成ASCII才稳定下来。

1.3 物理层接口:RS-232与RS-485

Modbus跑在串行链路上,最常见的就是RS-232和RS-485。这两个接口差别很大,选错了项目就麻烦了。

RS-232:点对点,距离短

RS-232就是电脑上那个老式串口(DB9接口)。它只能连两个设备,一主一从。距离最多15米,速度也就115200bps到头了。

我记得刚工作时,用RS-232连一个温控器,线长了点(大概20米),数据就开始乱码。后来才知道RS-232的抗干扰能力很差,电压信号(±12V)在长距离传输时衰减严重。

RS-485:多点通信,距离远

RS-485才是工业现场的主力。它用差分信号传输,抗干扰能力强。距离能到1200米,速度最高10Mbps(短距离时)。

最关键的是,RS-485支持多点连接。一条总线上可以挂32个设备(标准负载),用中继器还能扩展。我在一个污水处理厂项目里,一条RS-485总线上挂了18台变频器、6个流量计、4个液位计,跑得稳稳的。

避坑指南:RS-485总线两端必须加120Ω终端电阻。我曾经在一个项目里忘了加,结果总线反射严重,数据包频繁出错。排查了两天才找到原因——嗯,从那以后我每次布线都先检查终端电阻。

1.4 主从架构原理:谁说话,谁听话?

Modbus是典型的主从架构。说白了就是一个主站,多个从站。主站发命令,从站响应。从站之间不能直接通信。

主站通常是PLC、工控机或者你的电脑。从站就是变频器、仪表、传感器这些设备。

通信过程很简单:

  1. 主站发请求帧(包含从站地址、功能码、数据、校验)
  2. 所有从站都收到这个帧,但只有地址匹配的那个从站会响应
  3. 从站回复响应帧(包含地址、功能码、数据、校验)
  4. 主站收到响应,处理数据

你想想看,如果主站发了个请求,从站没响应怎么办?嗯,Modbus协议里没有自动重试机制。所以我们在写程序时,一定要自己实现超时重试。我一般设置3次重试,每次超时500ms。如果3次都失败,就报错并记录日志。

一个典型的Modbus RTU请求帧(读保持寄存器):

从站地址: 0x01
功能码:   0x03 (读保持寄存器)
起始地址: 0x00 0x64 (100)
寄存器数量: 0x00 0x02 (2个)
CRC校验:  0x04 0x0A

这个请求的意思是:让地址为1的从站,从地址100开始,读取2个寄存器的值。

从站响应帧格式类似,只是数据部分换成了实际数值。比如返回0x00 0xC8(200)和0x00 0xFA(250),就表示两个寄存器的值分别是200和250。

个人经验:调试Modbus通信时,我习惯先用串口助手抓包。看看主站发了什么,从站回了什么。如果从站没响应,先检查地址对不对,再查波特率和校验方式。90%的问题都出在这三个地方。

好了,这一章的内容就这些。Modbus协议基础是后面所有章节的基石。你把这些搞懂了,后面写代码、调参数就会顺手很多。下一章咱们聊聊Modbus功能码详解——说白了就是主站能对从站做哪些操作。到时候我会拿变频器做例子,手把手教你怎么读写参数。