项目定位
Mill 是一套面向工业磨坊场景的控制与维护系统。它不是单一的固件工程,而是从嵌入式固件到桌面 OTA 工具、再到移动端 App 的完整链路。
整套系统解决的核心问题是:把现场数据采集、继电器控制、远程维护和固件升级这些原本分散的事情,收敛到一套可以真正落地的工程链路里。
系统以 STM32F103ZE 为主控,通过 RS485/Modbus 接入 PT100 温度传感器、称重模块、流量计和继电器设备,再经由 G780s 通信模块将数据推送到云端,最终在 Flutter 客户端上实现实时监控和历史回溯。
系统架构
整条链路可以分为四层:
┌─────────────────────────────────────────────────────┐
│ Flutter 客户端 (com.varka.mill) │
│ 实时数据 · 历史趋势 · 告警管理 · 继电器控制 │
└──────────────────────┬──────────────────────────────┘
│ HTTPS / WebSocket
┌──────────────────────▼──────────────────────────────┐
│ 服务端 (Node.js + Mosquitto + SQLite) │
│ MQTT 订阅 · 数据持久化 · WS 广播 · REST API │
└──────────────────────┬──────────────────────────────┘
│ MQTT over TLS (8883)
┌──────────────────────▼──────────────────────────────┐
│ G780s 通信模块 │
│ Modbus 主站轮询 · 边缘 JSON 组包 · MQTT 客户端 │
└──────────────────────┬──────────────────────────────┘
│ USART3 / Modbus RTU
┌──────────────────────▼──────────────────────────────┐
│ STM32F103ZE 控制板 │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ 现场采集 │ │ 继电器控制 │ │ A/B 升级 │ │
│ │ USART2 │ │ DI 去抖 │ │ Bootloader │ │
│ │ Modbus 主站 │ │ 本地按键 ��� │ YMODEM │ │
│ └─────────────┘ └──────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────┘
硬件组成
| 组件 | 型号/说明 | 角色 |
|---|---|---|
| 主控 | STM32F103ZE | 数据采集、继电器控制、Modbus 通信 |
| 温度传感器 | PT100 模块(4 通道) | RS485 Modbus 从站 |
| 称重模块 | 4 通道称重变送器 | RS485 Modbus 从站 |
| 流量计 | 超声波流量计 | RS485 Modbus 从站 |
| 继电器模块 | 多路继电器 | 输出控制 + DI 输入 |
| 通信模块 | G780s | Modbus 主站 + MQTT 上云 |
| 通信链路 | RS485 共线 | 现场总线 |
STM32 固件:两条总线,两个角色
STM32 同时扮演两个 Modbus 角色:
- USART2 — Modbus 主站:轮询现场传感器,采集 PT100 温度、称重数据、流量频率和继电器状态
- USART3 — Modbus 从站:面向 G780s,暴露 91 个寄存器,覆盖现场数据、远程配置、维护控制和诊断信息
这种设计让 G780s 只需要轮询 STM32 一台设备就能拿到所有现场数据,而不需要直接跟每个传感器打交道。
采集的传感器矩阵
| 传感器 | 寄存器 | 数据 |
|---|---|---|
| PT100 × 4 | 0x0001 ~ 0x0004 | 温度 ×10 ℃ |
| 称重 × 4 | 0x0005 ~ 0x000C | 32 位大端,每通道高/低各一个寄存器 |
| 流量计 | 0x000D ~ 0x000F | 瞬时流量 ×100,累计流量 ×1000 |
| 继电器 | 0x0010 ~ 0x0015 | 输出位图、输入位图、控制命令 |
远程维护:不只是读数据
G780s 侧的 Modbus 从站不只是一个数据源。它还暴露了一套完整的远程维护机制:
- 配置区(0x0020 ~ 0x0028):传感器采集周期、流量采样周期、DI 去抖时间、控制模式等参数,可以远程修改
- 维护控制(0x0030 ~ 0x0037):解锁口令、命令触发、状态查询,支持 30 秒维护窗口
- 诊断区(0x0038 ~ 0x005A):固件版本、运行时长、上电次数、重启原因、CRC 错误计数、串口异常计数、当前运行槽位等
远程维护的标准流程是:解锁 → 写配置 → 确认 → 提交保存。配置修改不会立刻写 Flash,必须显式提交才生效,避免误操作。
A/B 双槽位固件升级
这是整个系统里最值得说的设计之一。STM32 的 Flash 被分成三个区域:
0x08000000 ┌─────────────────┐
│ Bootloader │ 32 KB
0x08008000 ├─────────────────┤
│ Slot A │ 236 KB
0x08043000 ├─────────────────┤
│ Slot B │ 236 KB
0x0807E000 ├─────────────────┤
│ BootCtrl / State │ 参数页
0x08080000 └─────────────────┘
升级流程:
- App 请求进入 Bootloader 模式,写入升级状态页
- Bootloader 通过 YMODEM 接收镜像,写入非运行槽位
- 校验镜像大小、CRC32、SHA-256、向量表合法性
- 标记待试运行槽位,跳转执行
- 如果试运行失败(连续 3 次 IWDG 复位),自动回退到上一个槽位
这个设计的核心价值是:升级失败不会变砖。即使新固件有问题,Bootloader 也能检测到并回退。
OTA 桌面工具
PC 侧的 OTA 工具是一个 .NET / WPF 应用,提供三个主要功能:
- 本地升级:通过 USB 转 RS485 直接连接设备,发送解锁指令后用 YMODEM 传输固件
- 远程升级:通过虚拟串口映射,走同样的升级流程
- 远程维护帧:生成和导入 Modbus RTU 原始帧,方便调试和云平台对接
工具会自动读取寄存器 0x005A 判断当前运行槽位,然后推荐刷写对应的 App_A.bin 或 App_B.bin。
Flutter 客户端
移动端 App(com.varka.mill)是整个系统的用户界面,主要功能:
- 实时监控:通过 WebSocket 接收服务端推送的传感器数据,卡片式展示温度、称重、流量、继电器状态
- 历史趋势:基于 fl_chart 绘制时间序列图,支持分度值切换和视口缩放
- 告警管理:本地告警 + 历史告警拉取,支持未读计数持久化
- 继电器控制:手动模式下可远程控制继电器输出
技术栈:Flutter + Provider + Dio + WebSocket + sqflite。
服务端
服务端负责桥接 MQTT 设备数据和 Flutter 客户端:
- Mosquitto:MQTT broker,TLS 加密,设备凭据 + ACL 控制
- Node.js API:订阅
device/+/up主题,解析 G780s 边缘 JSON,映射到内部 tele schema,持久化到 SQLite - WebSocket:实时广播传感器数据给在线客户端
- REST API:历史数据查询、告警管理、用户认证(admin + user,不开放注册)
开发环境
- 主控:STM32F103ZE
- 固件构建:Keil MDK-ARM
- OTA 工具:.NET SDK 10 + WPF
- 客户端:Flutter 3.x
- 服务端:Node.js + Mosquitto + SQLite