系统总体架构设计

好,咱们开始聊系统架构。说实话,很多初学者一上来就急着写代码、焊电路板,结果做到一半发现各个模块连不起来——这种坑我踩过不止一次。所以这一章,咱们先把骨架搭好。

药盒安全用药检测与异常报警系统,说白了就是一套「感知-决策-执行-通知」的闭环。我习惯把整个系统拆成三块来看:硬件怎么搭、软件怎么跑、数据怎么流。咱们一个一个说。

硬件架构

硬件是系统的地基。地基不稳,上层再漂亮也没用。我个人习惯先画一张硬件框图,把每个模块的角色定清楚。

主控MCU

这是整个系统的大脑。我推荐用ESP32系列,原因有三:

  • 自带Wi-Fi和蓝牙,省掉一个通信模块
  • 双核处理器,一个核跑传感器采集,一个核跑通信协议
  • 价格便宜,开发资料多,社区活跃

嗯,这里要注意:ESP32的ADC有非线性问题。我在项目里吃过这个亏——采集到的药盒重量数据跳来跳去,后来加了软件滤波才搞定。

传感器模块

药盒需要感知什么?我总结了三类:

  1. 药盒状态传感器:霍尔传感器或微动开关,检测药盒盖子是否打开
  2. 用药检测传感器:称重传感器(HX711+压力传感器),检测药片是否被取出
  3. 环境传感器:DHT22温湿度传感器,监测药品存储环境是否超标
我的经验:称重传感器一定要做零点漂移补偿。每次上电后先读取空载值,再减去这个基准。否则放了一晚上,第二天数据全偏了。

执行器模块

执行器负责「动手」。我一般配置:

  • 蜂鸣器:异常时发出警报声,分贝值建议在85dB以上
  • LED指示灯:绿色表示正常,红色表示异常,黄色表示待处理
  • 振动马达:给老人或视障用户提供触觉反馈

通信模块

ESP32自带Wi-Fi,所以通信模块基本就是它了。但如果你用STM32或其他MCU,就需要外接ESP8266或4G模块。我个人建议:

  • 家庭场景:Wi-Fi + MQTT
  • 户外/无Wi-Fi场景:4G Cat.1模块 + MQTT over TCP

软件架构

软件架构我分成三层:嵌入式端、云端、移动端。每一层各司其职,互不干扰。

嵌入式端(MCU固件)

这一层跑在ESP32上。我习惯用FreeRTOS做任务调度,把系统拆成几个独立任务:

// 伪代码示意
Task1: 传感器采集任务(每500ms执行一次)
Task2: 用药逻辑判断任务(事件触发)
Task3: MQTT通信任务(每2秒上报一次)
Task4: 异常报警任务(优先级最高)

为什么要用RTOS?说白了,如果不用操作系统,你写个while(1)大循环,传感器采集时通信卡住,通信时报警延迟——这种问题我调试过整整两天。

云端(后端服务)

云端我推荐用Python Flask或FastAPI搭一个轻量服务。主要做三件事:

  • 接收MQTT消息,解析用药数据
  • 存储到数据库(MySQL或SQLite都行)
  • 分析异常规则,触发报警推送
核心逻辑:云端不做实时控制,只做数据存储和规则分析。实时控制交给嵌入式端,这样即使断网,药盒也能独立工作。

移动端(App/小程序)

移动端我用Flutter开发,跨平台省事。主要功能:

  • 查看用药记录(谁、什么时间、吃了什么药)
  • 接收报警推送(漏服、多服、环境异常)
  • 远程设置参数(用药提醒时间、报警阈值)

数据流设计

数据怎么流?我画了一条线:从药盒到手机,中间经过云端。咱们一步步拆。

第一步:用药数据采集

传感器采集原始数据。比如称重传感器输出的是电压值,经过HX711转换成数字量。我习惯在MCU端做一次预处理:

// 称重数据预处理
float raw_weight = hx711_read();
float filtered_weight = moving_average_filter(raw_weight, 5); // 滑动平均滤波
float actual_weight = filtered_weight - tare_weight;          // 去皮操作

第二步:数据上传

MCU通过MQTT把数据发到云端。数据格式我用JSON,简单明了:

{
  "device_id": "pillbox_001",
  "timestamp": 1700000000,
  "weight": 12.5,
  "temperature": 25.3,
  "humidity": 45.2,
  "lid_status": "open"
}

上传频率我设的是2秒一次。太频繁浪费流量,太慢又怕漏掉关键事件。

第三步:数据分析

云端收到数据后,做两件事:

  1. 存储:写入数据库,保留历史记录
  2. 规则判断:检查是否触发异常条件

举个例子,如果检测到药盒盖子打开后,重量没有变化——说明用户可能只是看了看,没吃药。这时候云端会标记一条「疑似漏服」记录。

第四步:异常报警

一旦触发异常,云端通过MQTT或HTTP推送通知到移动端。我设计了几种报警等级:

报警等级 触发条件 响应方式
一级(紧急) 多服/漏服超过2小时 蜂鸣器+App推送+短信
二级(警告) 环境温湿度超标 App推送+LED红灯
三级(提醒) 用药时间到 蜂鸣器短鸣+LED绿灯闪烁

通信协议设计

通信协议我选了MQTT和HTTP两种。为什么用两个?

MQTT:用于实时数据上报

MQTT是发布/订阅模式,非常适合物联网场景。我设计的话题(Topic)结构:

pillbox/{device_id}/data      // 传感器数据上报
pillbox/{device_id}/alarm     // 报警事件
pillbox/{device_id}/command   // 云端下发指令

MQTT的QoS我设成1(至少一次),保证数据不丢,但允许重复。为什么不用QoS 2?因为药盒数据重复一条没关系,但丢一条可能就漏了报警。

HTTP:用于配置和查询

HTTP用在非实时场景。比如:

  • App查询历史用药记录
  • 用户修改用药提醒时间
  • 固件OTA升级

HTTP的优点是简单、调试方便。我习惯用RESTful风格,比如:

GET  /api/v1/records?device_id=001&date=2024-01-01
POST /api/v1/config
PUT  /api/v1/alarm/threshold
避坑提醒:我曾经把MQTT和HTTP混在一个端口上,结果调试时数据乱套。后来我严格区分:MQTT走1883端口,HTTP走8080端口。各走各的道,互不干扰。

好了,系统架构就聊到这儿。你想想看,硬件、软件、数据、协议——这四个维度都理清楚了,后面写代码、焊电路才不会跑偏。下一章咱们开始动手搭建开发环境,到时候我会把工具链和调试技巧一并分享。