为什么不直接用现成的 Modbus 协议栈
PipeMonitor 现场的从站既包括压力变送器、超声波流量计,也包括 PT100 温度模块,节点数和测点数都会变。如果把 Modbus 帧发送、寄存器布局、轮询调度都耦合在一起,每加一个传感器型号都要动多处代码。
所以这里把 Modbus 拆成了三层:
PipeMonitor/
├── Modbus_Master.* # 串口/总线收发、帧校验
├── Modbus_Service.* # 轮询调度、超时与异常节点处理
└── nanomodbus.* # 轻量级 Modbus 协议核心库(深度封装)
nanomodbus 是协议本体,Modbus_Master 负责把它接到 RT-Thread 的 UART 设备上,Modbus_Service 负责把”什么时候轮询哪个测点”这件事抽象成可配置的任务。
轮询调度
每个传感器都有一张测点表,描述它在 Modbus 总线上的从站地址、寄存器起始地址、寄存器数量、采集间隔。Modbus_Service 在调度循环里按以下顺序工作:
- 遍历测点表,找到下一个到期的测点
- 通过
Modbus_Master发出对应的读寄存器请求 - 解析回包,按测点的标定参数写回内存中的最新值快照
- 如果连续多次失败,把节点标记为异常并降级轮询频率
这样:
- 采集间隔分配:高频量(如压力)和低频量(如累积总流量)可以单独配置,不会因为低频量挤占高频量的轮询窗口
- 超时容错:
nanomodbus拿不到回包时返回错误码,调度层不会卡死 - 异常节点过滤:节点掉线后会自动降级,不会无限制地拖慢整体轮询
三类传感器的接入方式
| 模块 | 文件 | 说明 |
|---|---|---|
| PXW 压力温度 | PXW_Pressure.* | 单设备多寄存器,压力与温度成对读取 |
| 超声波流量计 | Flowmeter.* | 瞬时流量、流速、累积总流量;累积量单独低频轮询 |
| PT100 4 通道 | PT100_4.* | 一台从站映射 4 路温度 |
| PT100 5 通道 | PT100_5.* | 一台从站映射 5 路温度,与 4 通道版本走相同的服务接口 |
每个文件都暴露两类接口:
*_init(...)—— 把测点注册到Modbus_Service*_get_latest(...)—— 给上层(LCD、存储)拿到最近一次采集的快照值
上层永远不直接访问 Modbus 总线,只读快照,所以 LCD 渲染线程和存储线程都不会被串口收发阻塞。
与 RT-Thread 的协同
- 串口读写走 RT-Thread UART 设备框架,
Modbus_Master内部用 RT-Thread 的 IPC 等待应答 - 测点快照用互斥锁保护,写入端是采集线程,读取端是显示线程和存储线程
- 异常事件(连续超时、CRC 错误)通过 RT-Thread 消息队列发给上层告警逻辑,由 LCD 模块切换到告警颜色显示