量产 Modbus 数据重组网关项目复盘

项目背景:本网关基于 STM32F103 + RT-Thread 实现。PLC 通过 RS-485 接多台 Modbus 仪表,同厂家不同型号的同一种业务数据(如当前温度)寄存器地址也各不相同。设备一多,PLC 侧要为每型号写一套地址映射,现场换一台设备就可能要改 PLC 程序。本网关把这些分散寄存器收敛成一张统一寄存器表,PLC 只按固定偏移读写,不关心底层接了什么型号,换型号不改 PLC 程序。

职责:独立设计并实现网关固件与寄存器映射架构。

核心技术

同厂家多型号寄存器地址不一致,PLC 程序失控

同样是"当前温度",A 型号可能在 0x2000,B 型号在 0x2004。PLC 每接一种新型号都要加一套地址映射逻辑,差异散落在 PLC 程序里,换设备即改程序、不可复用。

解决方向是把差异收敛到网关:对下适配不同型号地址差异,对上输出统一寄存器表。PLC 读的是网关整理好的地址空间,不是物理设备的原始寄存器。

业务语义连续表:把零散寄存器排成可整块读的统一地址空间

地址碎片整理成连续表 把被打散的数据,按业务语义重新排成连续分区。

虚拟地址解耦:映射表把设备差异封装在网关内

虚拟地址如何落到真实设备?网关维护两张静态配置表:采集任务表描述每台下位机的物理寄存器起始地址、长度与读写权限,映射规则表描述这些物理寄存器投递到虚拟空间的哪个分区和通道偏移。

上位机只访问统一虚拟地址,网关按表翻译回"具体通道 + 真实寄存器",设备型号差异彻底封装在网关内——换型号只改配置、不动 PLC 程序。

虚拟地址映射异构设备 用虚拟地址屏蔽设备差异,对上统一成一张寄存器表。

慢速半双工总线阻塞上位机:后台轮询缓存换零等待读取

若 PLC 每次读取都透传到 RS-485,系统很慢:多设备共享半双工总线,报文往返时延大。

做法:后台按采集任务表持续轮询下位机刷进缓存,PLC 直接读缓存。

慢速总线变成快速读取 后台轮询负责采集,缓存负责对上快速返回。

为榨干总线性能,做三项核心处理:

  1. 优先级与行动点数调度:高优先级(温度、报警)和普通优先级分别建轮询任务;通过"行动点数"分配总线使用权,高优先级执行一定次数后把点数让给普通任务,实现带宽精细化分配。
  2. 相邻地址自动粘黏合并:轮询时状态机自动检测相邻且物理地址连续的规则,合并成一次批量读取;单次合并严格 ≤124 寄存器,大幅减少总线碎片化往返。
  3. 精准失效标记:通信失败时不保留旧值,改按出错任务块规则向缓存填对应异常状态值,让上位机准确知道哪块数据当前不可信。

写缓存被旧值冲掉:位图隔离读写冲突并写后回读校验

PLC 刚把新设定值写进网关,若后台轮询刚好读回下位机旧值,就会把缓存里的新值冲掉——读写路径在争抢同一份数据。

设计引入位图机制分开两个概念:

配置掉电损坏:延迟保存 + A/B 双分区 + 拨码兜底

配置保存最怕频繁写废 Flash,以及断电导致配置损坏:

  1. 延迟保存与软重启:配置变更后不立即落盘,经事件机制累积写操作;超时无新操作才触发落盘并执行软重启,避免运行时热切换参数的边界问题。
  2. 双分区交叉修复:Flash 分 A/B 两独立分区;读取时若 A 校验损坏,自动读 B 并尝试修复 A;写入时总是先擦写已知损坏分区,再擦写另一分区,确保任意时刻断电至少一份完整配置。
  3. 硬件拨码兜底:启动时优先读硬件拨码开关初始化基础从机地址和波特率,即使 Flash 配置彻底损坏,设备仍能被上位机访问并重新配置。

设计取舍与可复用边界

  1. 静态配置:映射规则编译时静态定义,不支持动态下发;牺牲远程加设备灵活性,换确定性与防误操作。
  2. 内存换速度:全量数据缓存到 RAM,占用内存换 PLC 侧零等待。
  3. 复杂度集中:适配逻辑集中在网关单点,PLC 程序标准化;现场设备远多于网关,更划算。
  4. 设备适配成本:新增型号只需加一套物理地址与映射偏移描述配置,架构不动;成本从"改 PLC 程序"降为"加一行配置"。

现场效果:PLC 面对固定格式寄存器表;下位机换型号不改 PLC 程序;调好的 PLC 程序可复用到不同现场。