LCD 渲染:避开整屏重绘
PipeMonitor 的现场 LCD 同时显示多个传感器的实时数值。最容易踩的坑就是每次刷新都整屏重绘,眼睛看上去一直在抖。
LCD 模块在 applications/PipeMonitor/LCD/ 下,做了几件事:
- 静态布局一次绘制完成:标题栏、表格框、单位标签等不会变的部分只画一次
- 动态行脏数据局部重绘:每个测点维持一份”上次显示的值”,只有当新值与上次显示不同(或精度位变化)时,才用背景色矩形把那一行擦掉再画新值
- 告警以特殊颜色显示:当采集层报告该测点处于异常状态(连续超时、CRC 错误、量程溢出)时,那一行切换到告警色
这样一来,正常工况下屏幕几乎”看不出”在刷新;告警发生时反而能一眼看到。
UI 线程不直接访问 Modbus 总线。它只从测点的内存快照读最新值,快照由采集线程更新,互斥锁保护。
LittleFS 文件系统
为什么不直接拿 RAW Flash 顺序写:
- 现场设备会经常掉电
- 单次写入要保证原子性,至少在一行 CSV 内不能被截断
- 老数据需要按时间滚动,不能写满 Flash 后停摆
LittleFS 自带掉电安全和磨损均衡,刚好满足这些条件。packages/ 目录下接入了 RT-Thread 的 LittleFS 软件包,挂载到一段独立的 Flash 区域。
measurements.csv 字段设计
存储线程把每次采集事件序列化成一行 CSV。字段顺序固定如下:
timestamp, uptime_ms, flow_lpm, total_l, velocity_ms,
pxw_temp_c, pxw_pres_mpa,
temp_4_1_c, temp_4_2_c,
temp_5_1_c, temp_5_2_c, temp_5_3_c, temp_5_4_c
| 字段 | 含义 |
|---|---|
timestamp | 现场时钟时间戳 |
uptime_ms | 系统上电后毫秒数,用于跨重启对齐 |
flow_lpm / total_l / velocity_ms | 超声波流量计三项 |
pxw_temp_c / pxw_pres_mpa | PXW 温度与压力 |
temp_4_*_c | PT100 4 通道四路温度 |
temp_5_*_c | PT100 5 通道四路温度(保留位) |
刷盘策略:批量 + Rotate
存储线程不会每次采集都立刻 fsync:
- 批量刷盘:内存里维护一段写入缓冲区,按定时阈值或缓冲区水位触发刷盘
- 文件 Rotate:单文件超过预设大小后自动切换到下一个文件名,老文件按 FIFO 删除,避免写满 Flash
总线错误时的保护策略
读写失败的字段不能写一个看似合理的”假值”,否则会污染历史数据。处理原则:
- 空值跳过:失败字段写空字符串(
,,),CSV 在解析时识别为缺失 - 哨兵值标记:对于不能用空值表达的语义错误(例如温度负数极值),写一个特定的哨兵值(例如
-9999),辅助事后分析
这样后续在 PC 端做曲线/告警分析时,可以清楚区分”无数据”和”采集异常”两种情况。