将 Modbus RTU 桥接到 MQTT,是指把串行现场设备通过 RS-485 总线暴露的寄存器值,作为结构化消息发布到 MQTT broker,供您的 SCADA、云平台或分析栈订阅。网关同时承担两项工作:它既是按固定周期轮询从站的 Modbus 主站,也是把每次轮询结果转换为某个主题(topic)上负载(payload)的 MQTT 客户端。本指南将以 SURIOTA 的 SRT-MGATE-1210 网关 为实例,逐一讲解从串口线路参数到 TLS 的每一项配置决策。
为什么必须使用协议桥接
Modbus RTU 是共享串行总线上的请求-应答协议。主站必须显式地逐一轮询每个从站,一次只处理一笔事务,既没有设备自行推送数据的概念,也没有发布-订阅(publish/subscribe)的拓扑。MQTT 则恰好相反:它是一种轻量级的发布-订阅协议,专为基于 TCP/IP 的多对多事件分发而设计(通常使用端口 1883 明文,或 8883 加 TLS)。关于 broker、主题设计和 QoS 级别的基础知识,请参阅我们的配套指南 面向工业物联网的 MQTT;本文则聚焦于生成这些消息的网关配置。网关调和了这两个世界:它在串行侧保持确定性的轮询循环,并把采集到的值翻译为网络侧的异步发布。如果您还在现场侧的串行与以太网 Modbus 之间犹豫,我们的解析文章 Modbus RTU 与 Modbus TCP 对比 详细阐述了两者的取舍。
第 1 步:设置串口线路参数
同一 RS-485 段上的每个从站都必须使用完全一致的串口参数,否则总线将无法通信。请将网关的串口配置为与现场设备完全匹配:
- 波特率:采用标准值之一(9600、19200、38400、57600、115200)。9600 和 19200 是仪表和传感器最常见的默认值。
- 数据位、校验位、停止位:典型的 Modbus RTU 帧格式为 8 个数据位、偶校验、1 个停止位(8E1)。当不使用校验时,规范要求采用 2 个停止位(8N2),以保持 11 位的字符帧。
- 从站地址:有效的单元 ID 为 1 到 247;0 是广播地址,永远不会被轮询应答。
同时也要遵守 EIA/TIA-485-A 标准的物理限制:单段最多支持 32 个单位负载(unit load),在较低波特率下电缆长度约为 1200 m,并在干线两端各接一个端接电阻(通常为 120 欧姆)。布线不良是间歇性超时的最常见单一成因,因此若您看到 CRC 错误,请查阅我们的指南 RS-485 布线与端接故障。
第 2 步:定义寄存器与轮询表
接下来,告诉网关要读取什么。每条轮询条目都需指定从站地址、Modbus 功能码、起始寄存器、数量,以及如何把原始 16 位字解码为工程值。四种标准数据模型与功能码的对应关系如下:读线圈(Read Coils,01)、读离散输入(Read Discrete Inputs,02)、读保持寄存器(Read Holding Registers,03)、读输入寄存器(Read Input Registers,04)。保持寄存器(功能码 03)承载了大多数模拟量测量值。如果您不清楚设备的寄存器布局,配套文章 Modbus 寄存器映射详解 解释了地址偏移与数据类型。
请密切关注数据宽度与字序(word order)。一个 32 位浮点数或 kWh 累加器会跨越两个连续的 16 位寄存器,而不同厂商在高字在前(大端,big-endian)还是低字在前(小端或字交换,little-endian/word-swapped)上各不相同。设置错误的字序会产生看似合理、但比例严重失真的数值,因此在调试期间务必对照设备显示值进行校验。
第 3 步:设计 MQTT 主题结构
主题是一个用正斜杠分隔层级的 UTF-8 分层字符串。规范、自描述的层级结构会让后续的订阅和访问控制大为简便。一个实用的模式是 site/area/device/measurement,例如 plant1/utility/meter01/voltage。请避免使用前导斜杠,也不要在所发布的主题中包含通配符 + 和 #(它们保留给订阅方使用)。下表展示了 SURIOTA PM1611-WD 电力仪表 的一小组寄存器如何映射到总线以及映射到 MQTT。
| 从站 | 功能码 | 寄存器 | 类型 | 测量值 | MQTT 主题 |
|---|---|---|---|---|---|
| 1 | 04(输入) | 0x0000 | uint16, /10 | 相电压 L-N (V) | plant1/utility/meter01/voltage |
| 1 | 04(输入) | 0x0006 | uint16, /100 | 电流 (A) | plant1/utility/meter01/current |
| 1 | 04(输入) | 0x000C | int16, /1000 | 功率因数 | plant1/utility/meter01/pf |
| 1 | 03(保持) | 0x0100 | uint32, /1 | 有功电能 (kWh) | plant1/utility/meter01/energy |
| 2 | 04(输入) | 0x0001 | int16, /10 | 温度 (degC) | plant1/utility/thm01/temperature |
| 2 | 04(输入) | 0x0002 | uint16, /10 | 湿度 (%RH) | plant1/utility/thm01/humidity |
此处的温度和湿度行来自共享同一总线的 SURIOTA THM-30MD Modbus 传感器,而这种混合设备段正是网关专为处理而生的场景。
第 4 步:设计 JSON 负载
您可以每个主题以裸数字形式发布一个值,但每个设备发布单个 JSON 对象通常更易于消费,因为它把时间戳、质量标志和所有测量值打包到一条原子消息中。请保持键名简短且稳定,并包含 UTC 时间戳,使下游系统无需依赖自身时钟。一个典型的单设备负载如下所示:
{
"ts": "2026-06-09T08:30:00Z",
"device": "meter01",
"status": "ok",
"data": {
"voltage": 229.8,
"current": 12.34,
"pf": 0.97,
"energy_kwh": 184523
}
}
status 字段很重要。当某个从站不应答或返回 Modbus 异常时,不要悄无声息地丢弃该读数。请发布一个带有 "status": "timeout" 或明确错误的负载,以便消费方能够区分陈旧值与零值。干净利落地映射异常码是稳健集成的一半工作,下表列出了网关可能在应答帧中收到的标准代码。
| 代码 | 名称 | 典型成因 |
|---|---|---|
| 01 | 非法功能 (Illegal Function) | 从站不支持所请求的功能码 |
| 02 | 非法数据地址 (Illegal Data Address) | 寄存器地址超出该设备的有效范围 |
| 03 | 非法数据值 (Illegal Data Value) | 数量或数值超出允许的限值 |
| 04 | 从站设备故障 (Slave Device Failure) | 从站内部发生不可恢复的错误 |
| 05 | 确认 (Acknowledge) | 请求已接受,长时间处理正在进行中 |
| 06 | 从站设备忙 (Slave Device Busy) | 从站正在执行长命令,请稍后重试 |
| 0B | 网关目标设备未响应 (Gateway Target Failed to Respond) | 网关后面被寻址的设备无应答 |
第 5 步:选择 QoS 与发布间隔
MQTT 提供三种服务质量(QoS)级别。QoS 0(至多一次)是无确认的发后即弃;QoS 1(至少一次)保证投递但可能重复;QoS 2(恰好一次)通过四步握手保证单次投递。对于每隔几秒就重新发布一次的周期性遥测数据,QoS 1 通常是最佳折中:您容忍偶尔的重复,但绝不丢失任何读数。请把 QoS 2 保留给那些绝不能重复的事件,例如命令确认。我们更深入的文章 MQTT 主题与 QoS 设计 进一步阐述了保留消息(retained messages)、遗嘱消息(Last Will and Testament)以及清洁会话(clean session)行为。
请根据所测量对象的物理特性来设置发布间隔,而不是按总线能承受的最大值来设置。电能表变化缓慢,因此 5 到 30 秒的间隔已绰绰有余;而振动或压力趋势可能需要 1 秒。请记住串行总线才是瓶颈:在 9600 波特下,每笔事务需要数十毫秒,因此每秒在 10 个从站上轮询 30 个寄存器是现实的,但以亚秒级速率轮询数百个寄存器则不现实。网关的轮询循环周期必须始终长于所有事务时间加帧间间隙的总和。
第 6 步:保护连接安全
切勿将明文 broker 连接投入生产环境。请按如下方式配置网关:
- TLS:使用 CA 证书在端口 8883 上连接,以便客户端验证 broker。在 broker 支持的情况下使用双向 TLS(客户端证书)。
- 认证(Authentication):为每个网关配置唯一的用户名和密码,绝不使用共享凭据,这样某个设备被攻陷后可被吊销而不影响整个设备群。
- 授权(Authorisation):将每个网关的 broker ACL 限制为其所拥有的主题前缀,例如发布限定为
plant1/utility/#,除非它需要接收命令,否则不授予任何订阅权限。
在串行侧,请保护 RS-485 线路本身。长距离的户外走线易受浪涌和地电位差影响,这正是串接 RS-485 浪涌保护器 和适当隔离发挥价值的地方。这种布线规范是任何运作良好的 工业物联网与系统集成 项目的一部分——在从传感器到仪表板的长链条中,网关只是其中一环。
调试核对清单
- 确认串口参数与每个从站匹配,且端接与偏置(biasing)正确。
- 手动轮询一个寄存器,并与设备显示值对比,以验证比例与字序。
- 用测试客户端订阅网关的主题树,确认负载形状与时间戳。
- 强制制造一次超时(拔掉一个从站),确认 status 字段会如实报告,而非发布陈旧数据。
- 启用 TLS 与认证,然后端到端重新验证整条路径。
常见问题
我应该每个值发布一个主题,还是每个设备发布一个 JSON 对象?
通常更推荐每个设备发布一个 JSON 对象,因为它把相关的测量值连同共享的时间戳和质量标志归入一条原子消息中,从而简化下游的时间对齐。仅当某个消费方需要独立订阅单个测量值,或负载大小必须最小化时,才使用每值一主题的方式。
对于经 MQTT 传输的 Modbus 遥测,哪种 QoS 级别最合适?
QoS 1 是周期性遥测的实用默认值。它保证 broker 至少接收每个读数一次,同时保持较低的开销。QoS 2 增加了更慢的四步握手,仅对那些绝不能重复的消息(例如控制确认)才值得采用。
网关轮询 Modbus RTU 并发布的速度能有多快?
串行总线决定了上限。在 9600 波特下,单笔事务需要数十毫秒,因此总循环时间等于所有事务加帧间间隙的总和。请把发布间隔设置得比该循环更长,并使其与被测量对象实际变化的快慢相匹配,而非与总线最大值相匹配。
一个网关能否在同一总线上处理不同类型的设备?
可以。只要所有设备共享相同的串口参数并具有唯一地址(1 到 247),网关就能轮询由仪表和传感器组成的混合集合,并把每个寄存器块映射到各自的主题与负载,正如上方映射表所示。