SoftControl
💡 行业知识

Modbus RTU 与 TCP 怎么选:展厅与楼宇设备控制指南

SoftControl Team2026-08-2512 分钟阅读
ModbusModbus RTUModbus TCPRS485building control

中控工程师为什么会碰上 Modbus

你本来不想碰工业协议,但只要展厅里出现灯光继电器、窗帘电机、空调、电源时序器、环境传感器或 PLC,这些设备说的就是 Modbus。它是楼宇和工业设备的通用语,而它出现在中控工作里的位置很明确:中控系统需要碰楼宇设备的那一刻。

好消息是:Modbus 其实比多数投影机协议还简单。 它只干一件事——读写编号的寄存器。

RTU 与 TCP:同样的命令,两种外壳

这是最关键的一点:RTU 和 TCP 承载的命令载荷完全相同,区别只在外壳。

Modbus RTU  :  [从站ID][功能码][数据………][CRC低][CRC高]
Modbus TCP  :  [MBAP 头 7字节][功能码][数据………]

Modbus RTUModbus TCP
物理层RS-485(多数)、RS-232以太网
寻址帧内从站 ID 1–247IP 地址 + 单元 ID
校验CRC-16无——由 TCP 负责
端口无502
拓扑手拉手总线,单主站星型,多客户端
速率9600–115200 波特网络速率
距离RS-485 可达约 1200 米网络能到的地方

能用 TCP 就用 TCP。 不用算 CRC、不用布总线、不用终端电阻、没有单主站限制,而且网络上任何位置都能够到设备。只有当设备只有 RS-485 口时才用 RTU——而这在便宜的继电器板和老空调设备上依然很常见。

务实的第三选项是网关。 一个 Modbus RTU 转 TCP 转换器能把 RS-485 总线搬上网络,从中控系统看过去一切都变成了 TCP。展厅里只有一条 RS-485 灯控总线、其余全是网络时,这几乎总是正确的架构——它意味着你的中控系统里只有一条协议路径,而不是两条。

你真正会用到的功能码

Modbus 的功能码列表很长。中控和楼宇场景里你只会用到四个:

码名称用途
0x01读线圈读开关量输出(继电器状态)
0x03读保持寄存器读数值(温度、设定值、状态)
0x05写单个线圈控制继电器通断
0x06写单个寄存器写数值(调光值、模式)

0x0F 和 0x10 一次写多个线圈/寄存器,适合一笔事务设置整个场景。

线圈是位,寄存器是 16 位字。 继电器板暴露的是线圈,温度传感器暴露的是寄存器。读错空间会返回异常码而不是错误的值——至少它是"响亮地失败"。

CRC 陷阱:低字节在前

Modbus RTU 在帧尾追加 16 位 CRC。关于它的两个事实造成了大多数 RTU 故障:

1. 多项式是 0xA001,初值 0xFFFF。 这是专门的 CRC-16/MODBUS——不是通用库里那个 CRC-16,那个会给出完全不同的结果。

2. CRC 是低字节在前追加的。 Modbus 里其他所有多字节字段都是大端序,唯独 CRC 是例外,而这个例外一直在坑人。

实算示例——从从站 1 读 1 个保持寄存器,起始地址 0:

帧体      :  01 03 00 00 00 01
CRC-16    :  0x0A84
追加      :  84 0A          ← 先低字节,后高字节
完整帧    :  01 03 00 00 00 01 84 0A

最后这一行是每本教科书上都有的 Modbus 标准样例,也是个很好的自检:如果你的 CRC 例程算出的是 0A 84 而不是 84 0A,说明你把字节序搞反了,任何设备都不会回你。

更多已验算的帧,可用来对照你的实现:

动作帧
读 1 个保持寄存器 @001 03 00 00 00 01 84 0A
读 2 个保持寄存器 @001 03 00 00 00 02 C4 0B
读 1 个线圈 @001 01 00 00 00 01 FD CA
写线圈 @0 = 通01 05 00 00 FF 00 8C 3A
写线圈 @0 = 断01 05 00 00 00 00 CD CA
写寄存器 @0 = 101 06 00 00 00 01 48 0A

注意"通"的值是 FF 00,不是 00 01。 功能码 0x05 用 FF00 表示通、0000 表示断——这是一对固定的魔数,不是布尔值。发 00 01 什么也不会发生。

那个能浪费掉一下午的差一错误

设备厂商的 Modbus 文档存在两套互不兼容的编号约定,把它们混起来是除接线外最常见的故障:

  • 协议地址从 0 开始。这是写进帧里的值。

  • 厂商手册里的寄存器编号常常从 1 开始,或者用 4xxxx 约定(保持寄存器 1 = 40001)。

所以手册说"温度在寄存器 40001",意思是协议地址 0。手册说"继电器 1 在线圈 1",通常意思是地址 0。

从错误的寄存器读到一个看起来合理的值时,不会有任何报错——你只是拿到了隔壁那个数据点,然后花一小时琢磨温度为什么是 47。当一个值"正好错了一位"的时候,先把地址挪一位试试,再去怀疑别的。

32 位数值与字节序

寄存器是 16 位。任何更大的东西——表示功耗的 32 位浮点、32 位计数器——都要跨两个连续寄存器存放,而这件事没有标准。

实际存在四种排列。以两个原始字 0x1234 和 0x5678 为例:

顺序字节别称
ABCD12 34 56 78大端序
BADC34 12 78 56大端字节交换
CDAB56 78 12 34字交换——非常常见
DCBA78 56 34 12小端序

你最常撞上的是 CDAB,因为很多设备把低位字存在前面。症状非常好认:本该是 23.5 的浮点数回来变成 1.2e-38 这样荒谬的值,或者一个整数读出来是几百万而不是几十。

修它只是改一个配置项,不用改代码——但你得先认出这个症状。如果一个 32 位值是"离谱地错"而不是"轻微地错",那是字节序问题,不是缩放问题。

缩放是另外一半:很多设备存的是 235,指望你除以 10 得到 23.5。这在每个寄存器的文档里写着,是乘法问题不是字节问题。缩放错会让你的值差一个 10 的幂;字节序错会给你一堆无意义的数。分清这两种症状能省下大量时间。

Modbus RTU 的 RS-485 接线

RS-485 是两线差分总线,它的规矩比以太网严苛得多:

  • 只能手拉手。 不能星型、不能分支。设备接设备接设备。

  • 极性有讲究。 A/B(有时标 D+/D−)必须全总线一致。某一台接反了,那一台就哑了——而其余设备照常工作,于是看起来像那台设备坏了。

  • 必须共地。 供电分开的机柜之间长距离走线要有地参考,否则会出现看起来像干扰的间歇性数据损坏。

  • 终端电阻。 120 Ω,接在总线的两个物理末端,而且只在那两处。中间多接的终端电阻会把总线拉垮。

  • 单主站。 Modbus RTU 只能有一个主站。两套中控同时轮询同一条总线会碰撞,两边都会看到随机超时。

  • 所有设备的波特率、校验位、停止位必须一致,而且每台要有唯一的从站 ID。两台 ID 相同的设备会同时应答、互相破坏。

从站 ID 重复这一条值得单独点出来,因为它的症状特别迷惑人:偶发的乱码回复,而不是稳定的失败。 而出厂的继电器板非常经常地默认是从站 ID 1。

为什么你的 Modbus 设备不应答

1. CRC 字节序反了。 见上。用 01 03 00 00 00 01 84 0A 自测。

2. 从站 ID 错了,或者两台设备共用了一个 ID。

3. 某一台的 A/B 接反了。

4. 终端电阻缺失或多余。

5. 地址差一位——40001 约定。

6. 功能码与数据类型不匹配——去线圈空间读寄存器。

7. 串口参数不匹配。 Modbus RTU 默认常用偶校验(8E1),这和多数中控设备不一样。设备在 8N1 下不吭声,先试 8E1。

8. TCP 场景:单元 ID 错了。 即使走 TCP,帧里仍然带一个单元标识。网关用它来选择下游总线上的哪台 RTU 设备;直连以太网的设备通常什么都收,或者要求正好是 1 或 255。

用 SoftControl 控制

SoftControl 原生支持 modbus_tcp 和 modbus_rtu 两种协议,功能码、从站 ID、地址、数量、数据类型、字节序、缩放、偏移、精度都可以按指令配置——所以 ABCD/BADC/CDAB/DCBA 是一个下拉框,而不是一次手工挪字节的练习,CRC 也由它替你算。指令测试页会显示实际发出的帧和原始响应,这正是你分辨"CRC 被拒"和"设备根本不在总线上"的手段。

这在展厅工程里的意义是:灯光继电器、窗帘电机和传感器,和投影机、显示器待在同一个界面里——协议之间怎么配合见 AV 控制协议详解,一个完整应用见工业 Modbus 看板。

立即体验 SoftControl

免费下载,无需注册即可开始 30 天试用

免费下载查看功能

留言讨论

评论发布后会被人工复核,违规内容将被删除。

    还没有人评论,来说说你的看法