3、通信协议基础:RS485/RS232物理层、Modbus RTU协议帧结构、功能码详解(01/02/03/04/05/06/15/16)

各位同行,大家好。今天我们来聊聊通信协议的基础。这部分内容,说白了就是主站和从站之间「对话」的规矩。你想想看,两个人说话得用同一种语言,设备之间也一样。RS485、RS232 是物理层的「嘴巴」和「耳朵」,而 Modbus RTU 则是它们说的「语言」。我这些年调试过的项目,十有八九都离不开这套东西。咱们一个一个来拆解。

3.1 物理层:RS232 与 RS485 的区别

先说说物理层。RS232 和 RS485,这是两种最常用的串行通信标准。别看它们长得像(都是 DB9 接头),脾气可完全不一样。

RS232: 这是老前辈了。点对点通信,一根线发,一根线收,再加一根地线。传输距离短,也就 15 米左右,速率也不高。我最早做设备调试时,用的就是 RS232 连 PLC。那时候笔记本还带串口,现在嘛,都得用 USB 转串口线了。

RS485: 这才是工业现场的主力。它用差分信号传输,抗干扰能力强。最牛的是支持多站通信——一条总线上可以挂 32 个、甚至 128 个从站。传输距离能到 1200 米。嗯,这里要注意:距离长了,速率就得降下来。比如 9600bps 时跑 1000 米没问题,但你要是跑到 115200bps,能跑 100 米就算不错了。

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

特性 RS232 RS485
传输方式 单端(不平衡) 差分(平衡)
最大距离 约 15 米 约 1200 米
最大节点数 1 对 1 32 个(标准),可扩展
抗干扰能力
典型速率 115200 bps 以内 10 Mbps 以内
信号线 TX, RX, GND A, B, GND
我的经验: 现场布线时,RS485 的 A/B 线一定要双绞,屏蔽层单端接地。我曾经在一个项目里,就因为没做双绞,结果 200 米外的从站数据老是丢包。后来换了双绞屏蔽线,问题立马解决。别小看这点细节。

3.2 Modbus RTU 协议帧结构

物理层搞定了,接下来就是协议层。Modbus RTU 是目前工业上用得最广的协议之一。它的报文结构很简洁,我给大家拆开看:

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

就这么简单。每个部分都有讲究:

  • 地址码: 从站地址,范围 1-247。0 是广播地址,所有从站都收,但不回复。
  • 功能码: 告诉从站要干什么。读线圈、读寄存器、写线圈……后面细说。
  • 数据区: 具体参数。比如读哪个寄存器、读几个、写什么值。
  • CRC 校验: 循环冗余校验。保证数据在传输过程中没被干扰。我见过有人偷懒不校验,结果现场一有变频器启动,数据就乱套了。

举个例子,主站要读取地址为 01 的从站,从寄存器 0000 开始读 2 个寄存器:

主站发送:01 03 00 00 00 02 C4 0B
从站回复:01 03 04 00 0A 00 14 XX XX

你看,主站发的是:地址 01,功能码 03(读保持寄存器),起始地址 0000,数量 0002,CRC 校验 C40B。从站回复:地址 01,功能码 03,数据长度 04(4 个字节),数据 000A(10)和 0014(20),最后是 CRC。

避坑指南: 我曾经遇到过一个问题——从站回复的数据长度和主站期望的不一致。后来发现是 CRC 计算错了。记住,CRC 是低字节在前,高字节在后。很多新手在这里栽跟头。

3.3 功能码详解

功能码是 Modbus 协议的核心。我挑最常用的 8 个功能码来讲。这些你调试时几乎天天碰到。

3.3.1 位操作功能码(01、02、05、15)

01 - 读线圈状态: 读取从站的数字量输出(DO)。比如 PLC 控制了一个继电器,你想知道它现在通没通,就用 01 功能码。

02 - 读离散输入状态: 读取从站的数字量输入(DI)。比如一个按钮按下了没有,或者一个限位开关触发了没有。

05 - 写单个线圈: 控制一个数字量输出。比如让一个继电器吸合或断开。数据区:0xFF00 表示 ON,0x0000 表示 OFF。

15 - 写多个线圈: 一次控制多个数字量输出。比如你要同时启动 8 个指示灯,用 15 功能码一次搞定。

我个人的习惯: 调试时先用 01 功能码读一遍所有线圈状态,确认从站响应正常。然后再用 05 或 15 去写。这样出了问题,能快速定位是主站发错了,还是从站没执行。

3.3.2 字操作功能码(03、04、06、16)

03 - 读保持寄存器: 这是最常用的功能码。读取从站的模拟量输出或参数设置值。比如变频器的频率设定值、PID 的给定值。

04 - 读输入寄存器: 读取从站的模拟量输入。比如温度传感器、压力变送器的实时数值。

06 - 写单个寄存器: 设置一个寄存器的值。比如给变频器写一个目标频率。

16 - 写多个寄存器: 一次写多个连续的寄存器。比如你要更新 PID 的三个参数(P、I、D),用 16 功能码一次搞定,效率高很多。

我给大家整理了一个速查表:

功能码 名称 操作对象 典型用途
01 读线圈 DO 读取继电器状态
02 读离散输入 DI 读取按钮、限位开关
03 读保持寄存器 AO / 参数 读取变频器频率
04 读输入寄存器 AI 读取温度、压力值
05 写单个线圈 DO 控制单个继电器
06 写单个寄存器 AO / 参数 设置目标频率
15 写多个线圈 DO 批量控制指示灯
16 写多个寄存器 AO / 参数 批量更新 PID 参数
注意: 功能码 05 和 15 写线圈时,数据区必须是 0xFF00 或 0x0000。写其他值,从站会返回异常码。我见过有人写 0x0100,结果从站没反应,查了半天才发现是数据格式不对。

3.4 知识体系结构图

下面这张图,把本章的核心逻辑串起来了。从物理层到协议层,再到功能码的应用,一目了然。

Modbus RTU 通信协议知识体系 物理层 RS232 RS485 差分信号 / 双绞线 Modbus RTU 协议帧 地址码 (1B) 功能码 (1B) 数据区 (N B) CRC 校验 (2B) 功能码详解 位操作 01 - 读线圈状态 02 - 读离散输入 05 - 写单个线圈 15 - 写多个线圈 字操作 03 - 读保持寄存器 04 - 读输入寄存器 06 - 写单个寄存器 16 - 写多个寄存器

这张图把整个知识体系串起来了。从底层的 RS232/RS485 物理层,到中间的 Modbus RTU 协议帧结构,再到上层的 8 个功能码。你调试时,脑子里要有这张图。遇到问题,先定位是物理层的问题(比如线没接好、干扰大),还是协议层的问题(比如地址配错了、CRC 算错了),还是功能码用错了。

总结一下: 物理层选 RS485 还是 RS232,看距离和节点数。协议帧结构要烂熟于心,尤其是 CRC 校验。功能码 8 个,分清楚位操作和字操作。调试时,先用 01/02 读状态,再用 03/04 读数据,最后用 05/06/15/16 写控制。这个顺序,能帮你快速定位问题。

好了,这一章就到这里。内容不多,但都是干货。你把这些吃透了,后面讲主从站协同调试时,就会轻松很多。

专注资料整理