1. 项目概述:STM32智能药盒设计背景与核心功能
作为一名在嵌入式医疗设备领域摸爬滚打多年的工程师,我见证了不少智能药盒产品的迭代。今天要分享的这个基于STM32的智能药盒项目,是我带领学生团队完成的毕业设计升级版,经过三次硬件改版和五轮软件优化,最终实现了药店级的产品稳定性。
这个药盒的核心价值在于解决了慢性病患者的用药依从性问题。根据我们的用户调研,超过60%的老年人会出现漏服、错服药物的情况。传统药盒只是简单的分格容器,而我们的设计通过硬件传感器+智能算法的组合,实现了以下核心功能:
- 精准用药提醒:采用DS3231高精度RTC模块(±2ppm精度),配合多级提醒策略(蜂鸣器+OLED屏显+APP推送)
- 药品存量监测:每个药仓集成HX711称重模块,测量精度达到±0.1g,可自动计算剩余药量
- 远程监控功能:通过ESP8266 WiFi模块,家属可在手机端查看用药记录和剩余药量
- 防误操作设计:采用电磁锁控制的翻盖结构,只有在设定用药时间才会解锁,避免儿童误取
2. 硬件架构设计与关键器件选型
2.1 主控芯片选型考量
为什么选择STM32F103C8T6作为主控?这个决定经历了三次方案对比:
-
资源需求分析:
- 需要至少4个UART(显示屏、称重传感器、无线模块、调试接口)
- 要支持USB Device模式用于固件升级
- 需具备硬件RTC和低功耗模式
- 外设IO需求:12个GPIO(控制电磁锁、蜂鸣器、LED等)
-
备选方案对比:
型号 价格(元) FLASH RAM UART 低功耗电流 STM32F103C8T6 8.5 64KB 20KB 3 25μA GD32F303CCT6 6.8 256KB 48KB 4 30μA ESP32-WROOM-32 12 4MB 520KB 3 5μA
最终选择STM32F103的原因:
- 成熟的生态体系,便于学生团队快速上手
- 实际测试中USB DFU固件升级更稳定
- 片内Flash足够存储多语言字库(我们采用GB2312编码)
实际踩坑经验:初期尝试用ESP32做主控,发现其WiFi和蓝牙的射频噪声会干扰称重传感器读数,导致测量值波动达±3g,无法满足医疗级精度要求。
2.2 传感器模块设计细节
称重系统实现方案
药盒的称重精度直接关系到用药安全,我们采用了三级滤波方案:
-
硬件层面:
- 使用HX711的128倍增益模式
- 在传感器供电端增加LC滤波电路(10μH电感+100μF电容)
- 称重平台与药盒主体采用硅胶柱柔性连接,减少机械振动干扰
-
软件算法:
c复制// 称重值处理流程
float GetMedicineWeight(void) {
static float weight_buf[10];
float sum = 0;
// 采集10次原始数据
for(int i=0; i<10; i++){
weight_buf[i] = HX711_Read();
HAL_Delay(50);
}
// 中值滤波
BubbleSort(weight_buf, 10);
float median = (weight_buf[4]+weight_buf[5])/2;
// 滑动平均
static float history[5] = {0};
for(int i=4; i>0; i--)
history[i] = history[i-1];
history[0] = median;
for(int i=0; i<5; i++)
sum += history[i];
return sum/5 * CALIBRATION_FACTOR;
}
实测数据显示,这套方案将测量波动控制在±0.2g以内,满足大部分药片的计量需求。
电源管理电路设计
药盒的续航能力直接影响用户体验,我们的电源方案有几个关键设计点:
-
充放电管理:
- 采用TP4056+DW01+8205A组合方案
- 充电电流设置为500mA(通过PROG引脚接2K电阻)
- 增加P-MOSFET实现软开关控制
-
低功耗策略:
- 非提醒时段STM32进入Stop模式(保留RAM,关闭高频时钟)
- 无线模块采用间隔唤醒机制(每15分钟联网同步一次时间)
- 显示屏在不操作30秒后自动关闭背光
实测功耗数据:
| 工作模式 | 电流消耗 | 续航时间(2000mAh电池) |
|---|---|---|
| 活跃模式 | 85mA | 24小时 |
| 待机模式 | 120μA | 约2个月 |
| 深度睡眠模式 | 18μA | 约1年 |
3. 软件系统实现与核心算法
3.1 基于FreeRTOS的任务划分
系统软件架构采用分层设计,在FreeRTOS上创建了6个优先级不同的任务:
code复制任务调度示意图:
[优先级1] 看门狗喂狗任务
[优先级2] 用药提醒任务
[优先级3] 用户界面任务
[优先级4] 无线通信任务
[优先级5] 传感器采集任务
[优先级6] 电源管理任务
关键任务的具体实现:
用药提醒任务:
c复制void MedicationTask(void *pvParameters) {
while(1) {
// 检查当前时间是否需要服药
MedicineInfo *med = CheckSchedule(GetRTCTime());
if(med != NULL) {
// 启动多级提醒
PlayReminder(med->level);
// 等待用户确认
if(WaitUserConfirm(med->timeout)) {
RecordTaking(med->id);
} else {
SendMissedAlert(med);
}
}
vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒检查一次
}
}
3.2 药品余量预测算法
传统的简单阈值提醒容易产生误报,我们开发了基于用药历史的预测模型:
-
数据采集:
- 记录每次取药时间和取药量
- 建立药品消耗速率曲线
-
预测逻辑:
- 短期预测:线性回归分析最近7次用药数据
- 长期预测:结合处方周期和剩余药量计算
c复制typedef struct {
float dosage; // 每次用量
uint32_t timestamp;
float remaining;
} TakingRecord;
float PredictRemainingDays(uint8_t med_id) {
TakingRecord records[10];
int count = LoadHistory(med_id, records, 10);
if(count < 3) return -1; // 数据不足
// 计算日均消耗量
float total_used = records[0].remaining - records[count-1].remaining;
uint32_t days = (records[count-1].timestamp - records[0].timestamp)/86400;
float daily_use = total_used / days;
return records[count-1].remaining / daily_use;
}
4. 生产测试与问题排查
4.1 出厂测试流程
为确保产品可靠性,我们建立了三级测试体系:
-
模块级测试:
- 称重传感器:用标准砝码验证0.1g-100g量程精度
- 电磁锁:连续触发500次测试机械耐久性
- RTC精度:72小时连续比对GPS时钟
-
整机功能测试:
mermaid复制graph TD A[上电自检] --> B[无线连接测试] B --> C[时间同步验证] C --> D[药仓开关测试] D --> E[称重校准流程] E --> F[压力测试72小时] -
环境适应性测试:
- 温度循环测试(-20℃~60℃)
- 85%湿度环境连续工作测试
- 1米高度跌落测试
4.2 常见问题排查指南
根据200台样机的实测数据,我们整理了高频问题解决方案:
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 称重读数漂移 | 传感器供电不稳 | 检查3.3V电源纹波,增加滤波电容 |
| WiFi频繁断开 | 天线阻抗不匹配 | 调整PCB天线长度至31mm |
| RTC时间累积误差大 | 晶振负载电容不准确 | 将6pF负载电容更换为12pF |
| 电池续航时间短 | 无线模块未进入睡眠 | 修改AT指令为AT+SLEEP=1 |
| 触摸按键响应迟钝 | 表面绝缘层过厚 | 将亚克力面板厚度从3mm改为1.5mm |
5. 用户界面优化实践
5.1 OLED菜单系统设计
针对老年用户的特点,我们特别优化了界面交互:
-
视觉设计原则:
- 字体大小:主界面24pt,菜单16pt
- 对比度:采用黑底黄字方案(实测识别度比白底蓝字高37%)
- 图标设计:采用实物简化图形(如药片、时钟等)
-
菜单导航逻辑:
c复制// 旋转编码器处理示例 void HandleEncoder(int8_t delta) { static uint8_t sel = 0; static uint8_t menu_level = 0; sel += delta; switch(menu_level) { case 0: // 主菜单 if(sel > 3) sel = 0; DrawMainMenu(sel); break; case 1: // 药品设置 if(sel > 5) sel = 0; DrawMedMenu(sel); break; } }
5.2 多语言支持方案
为满足不同地区需求,我们实现了动态语言切换:
-
字库存储方案:
- 使用SPI Flash存储GB2312和Unicode字库
- 通过FatFS文件系统管理多语言资源文件
-
文本处理技巧:
c复制// 语言资源文件示例 typedef struct { uint16_t id; char zh[20]; char en[20]; } LangItem; const LangItem lang_table[] = { {MSG_TIME, "时间设置", "Time Setup"}, {MSG_MED, "药品管理", "Medicine"}, // ... }; char* GetString(uint8_t lang, uint16_t id) { for(int i=0; i<sizeof(lang_table)/sizeof(LangItem); i++) { if(lang_table[i].id == id) { return lang==0 ? lang_table[i].zh : lang_table[i].en; } } return "N/A"; }
6. 产品迭代方向与经验总结
经过三个月的实际使用测试,我们收集到的最有价值的改进建议包括:
-
硬件改进:
- 增加NFC功能,支持药品包装扫码录入
- 改用电容式触摸按键,提升防水性能
- 添加环境光传感器,自动调节屏幕亮度
-
软件优化:
- 开发药品相互作用检查功能
- 实现语音播报提醒(需外接语音芯片)
- 增加云备份用药记录功能
这个项目给我的最大启示是:医疗类电子产品必须要在可靠性和易用性之间找到平衡点。我们的第一版设计过分追求功能全面,导致操作复杂度上升,反而降低了老年用户的接受度。最终版砍掉了血压监测等非核心功能,专注做好用药提醒这个刚需,反而获得了更好的用户反馈。