4. 设备接口与通信协议解析

实验设备实时数据平台的第一道工程难题,不是数据库选型,也不是可视化,而是“怎么把设备里的数取出来”。实验室里常见的设备横跨几十年技术代际:老式电子天平可能只有 RS232 串口,环境试验箱用 RS485 挂 Modbus RTU,新型电源支持 Modbus TCP,高端光谱仪自带 OPC UA 服务端,而自研采集板卡往往只提供 MQTT 或裸 TCP。适配的本质,是把这些异构的物理接口、帧格式、寻址方式和语义模型,统一映射为平台可消费的“设备—测点—值—时间戳”结构。

一、先分清物理层与协议层

RS232、RS485 属于物理层/电气层规范,它们只规定电平、接线和传输方式,不规定数据含义。RS232 是全双工、点对点、传输距离通常十几米;RS485 是半双工、差分、总线型,可挂 32 个以上节点,距离可达 1200 米。因此“RS485 设备”这个说法并不完整,必须追问:485 上跑的是什么应用层协议?常见答案是 Modbus RTU,也可能是自定义 ASCII 帧或 DL/T 645 等。

Modbus、OPC UA、MQTT、HTTP 属于应用层协议,TCP/UDP 属于传输层。理解这个分层,才能判断适配工作发生在哪一层:换线缆解决物理层,改波特率解决链路层,解析寄存器解决应用层,而语义映射则发生在平台侧。

实验设备协议适配分层模型 设备侧(异构) 电子天平 RS232 · 自定义ASCII帧 环境试验箱 RS485 · Modbus RTU 可编程电源 以太网 · Modbus TCP 光谱仪 以太网 · OPC UA 自研采集板 WiFi · MQTT / 裸TCP HTTP 设备(REST 查询) 协议适配层(网关/驱动) 物理链路管理 串口参数 / TCP连接 / 心跳重连 帧解析与校验 CRC16 / 报文头尾 / 长度字段 寻址与轮询调度 从站地址 / 寄存器地址 / 周期 数据类型转换 uint16 / float32 / 字节序 / 缩放 语义映射 寄存器→测点ID / 单位 / 量程 时间戳与质量码 采集时刻 / 超时 / 坏值标记 统一输出:设备ID + 测点 + 值 + 时间戳 平台侧(统一) 消息总线 MQTT Topic / Kafka 实时库 / 时序库 测点写入 / 历史查询 规则与告警 阈值 / 变化率 / 断线 可视化与API 看板 / HTTP / WebSocket 统一测点模型

二、Modbus 适配:寄存器映射是核心工作

Modbus 是实验设备中最常见的应用层协议,分 RTU(串口)和 TCP(以太网)两种承载方式。它的数据模型只有四类:线圈(可读写位)、离散输入(只读位)、输入寄存器(只读 16 位)、保持寄存器(可读写 16 位)。适配时最关键的不是“连上”,而是建立寄存器地址到物理量的映射表。

以某环境试验箱为例,设备手册给出:温度值存放在保持寄存器 40001(即协议地址 0x0000),单位 0.1℃,有符号 16 位;湿度在 40002,单位 0.1%RH;运行状态在 40010,0=停止、1=运行、2=故障。适配配置可写成:

{
  "device": "TH-001",
  "protocol": "Modbus RTU",
  "serial": { "port": "/dev/ttyUSB0", "baud": 9600, "dataBits": 8,
              "stopBits": 1, "parity": "none" },
  "slaveId": 1,
  "pollIntervalMs": 1000,
  "points": [
    { "id": "temp",  "func": 3, "addr": 0,  "type": "int16", "scale": 0.1, "unit": "℃" },
    { "id": "humi",  "func": 3, "addr": 1,  "type": "int16", "scale": 0.1, "unit": "%RH" },
    { "id": "state", "func": 3, "addr": 9,  "type": "uint16",
      "enum": { "0": "停止", "1": "运行", "2": "故障" } }
  ]
}

这里有两个易错点。第一,手册上的 40001 是“文档地址”,实际发送时要去掉 4 前缀并减 1,得到 0x0000;若直接发 40001 会读到错误寄存器。第二,32 位浮点数会占用两个连续寄存器,且存在大小端问题,必须确认设备是 ABCD 还是 CDAB 字节序,否则读出的温度会是荒谬值。判断方法:读取后若数值明显偏离量程,先怀疑字节序,再怀疑缩放系数。

三、OPC UA 与 MQTT:语义化与轻量化两条路

OPC UA 面向的是“语义互操作”。设备不仅提供值,还提供节点路径、数据类型、工程单位、访问权限。适配时通常用 OPC UA 客户端订阅节点,例如 ns=2;s=Device1.Temperature,并利用订阅(Subscription)机制设置发布间隔和死区,避免无意义的高频上报。OPC UA 适合高端仪器和产线设备,代价是栈较重、配置复杂。

MQTT 则是轻量发布/订阅模型,适合自研板卡和无线传感器。适配重点是主题设计与 QoS 选择。推荐主题结构为 lab/{labId}/{deviceId}/{pointId},例如 lab/room301/TH-001/temp。QoS 0 最快但可能丢,QoS 1 至少一次但可能重复,平台侧需按时间戳去重。对于温度这类慢变量,QoS 1 足够;对于波形类高频数据,应改用批量打包或直接走 TCP 流。

四、TCP/UDP 与 HTTP 的取舍

裸 TCP 适合自定义二进制协议,优点是效率高、可控,缺点是要自己处理粘包与断线重连。粘包处理常用“固定长度”或“长度字段+报文体”两种策略。UDP 适合对实时性要求高、可容忍少量丢包的场景,如高速采样广播,但平台侧必须自行处理乱序和丢包标记。HTTP 是请求/响应模式,适合配置下发、历史查询和低频状态获取,不适合秒级以下的实时采集,因为每次请求的连接开销和头部冗余都太大。

选型口诀:慢变量、要语义,选 OPC UA;无线、轻量、多对多,选 MQTT;老设备、寄存器型,选 Modbus;高频、自定义帧,选 TCP;配置与查询,选 HTTP。

五、适配结果的验证方法

适配完成后不能只看“有数”,要验证四件事:一是数值合理性,例如室温应在 15~35℃ 之间,若读到 6553.5 说明缩放或字节序有误;二是时间戳连续性,采集周期 1 秒时相邻时间戳间隔应稳定在 1 秒附近,出现大间隔说明轮询阻塞或断线;三是断线恢复,拔掉串口线后平台应在设定超时(如 3 个周期)内将该测点标记为坏值,插回后自动恢复;四是多设备并发下的轮询公平性,若 485 总线上挂 8 个从站、每站 10 个寄存器,单次轮询耗时需实测,避免周期被拉长到无法满足实时要求。

把这些验证项固化为接入检查表,每接入一台新设备就逐项确认,可以显著减少后期“数据看起来对、实际不可信”的隐患。