1. 项目概述:基于STM32的智能药盒开发实录
去年帮家里老人做的一个小项目,没想到成了亲戚朋友争相索取的"爆款"。这个智能药盒核心解决两个痛点:一是容易忘记吃药,二是无法远程监控药量。整套系统成本控制在200元以内,但实现了市面上千元级产品的核心功能。
作为主控的STM32F103C8T6相信大家都不陌生,江湖人称"蓝莓派"的性价比之王。搭配SIM800L模块实现短信提醒,实测在2G网络覆盖一般的环境下也能稳定工作。最让我惊喜的是药量检测模块的精度——经过校准后的HX711重量传感器,误差可以控制在±0.5g以内,足够检测药片的取出动作。
2. 硬件架构深度解析
2.1 主控选型与电路设计
选择STM32F103C8T6主要基于三点考量:
- 丰富的外设接口:3个USART(分别接GSM、调试口、预留扩展)
- 充足的GPIO:驱动OLED、传感器、蜂鸣器等外设毫无压力
- 低功耗特性:运行模式下<36mA,睡眠模式可降至2μA
电路设计上有几个关键点:
- GSM模块电源必须独立设计,瞬时电流可能达到2A
- 传感器信号线要加RC滤波,防止MCU数字噪声干扰
- RTC模块建议使用DS3231,比DS1302精度高一个数量级
2.2 传感器方案对比测试
测试了三种药量检测方案:
- 红外对射方案:成本低(<5元),但易受环境光干扰
- 压力传感器:精度高,但需要定制机械结构
- HX711+称重传感器:最终选择方案,50kg量程模块约15元
校准方法:
c复制// 空盒校准
float empty_weight = read_hx711(100); // 采样100次取平均
// 满盒校准
float full_weight = read_hx711(100);
// 单位药片重量
float pill_weight = (full_weight - empty_weight)/pill_count;
2.3 电源管理设计
采用TP4056充电管理+3.7V锂电池方案,关键设计:
- 双电源自动切换电路(电池/USB供电)
- 所有外设通过MOS管控制供电,非使用时段彻底断电
- 加入LC滤波电路消除GSM模块工作时对MCU的干扰
实测数据:
- 待机电流:1.8mA(所有外设关闭)
- 工作电流:85mA(GSM发送短信时峰值)
- 续航时间:2000mAh电池可使用约3周
3. 软件实现关键细节
3.1 系统状态机设计
采用事件驱动架构,核心状态包括:
mermaid复制stateDiagram
[*] --> Idle
Idle --> TimeCheck: 每分钟RTC中断
TimeCheck --> Alert: 到达服药时间
Alert --> WaitConfirm: 触发提醒
WaitConfirm --> Log: 按键确认
WaitConfirm --> Escalate: 超时未确认
Escalate --> SendSMS: 二次提醒
3.2 GSM通信优化实践
SIM800L模块的几个坑:
- 网络注册可能需要长达3分钟
- 短信发送成功率与信号强度强相关
- 必须正确处理URC(Unsolicited Result Code)
改进后的短信发送流程:
c复制void safe_send_sms(char *num, char *msg) {
for(int retry=0; retry<3; retry++){
if(check_signal() > 2){ // 信号强度大于2格
if(send_at_cmd("AT+CMGF=1", "OK", 1000)){
sprintf(buf, "AT+CMGS=\"%s\"", num);
if(send_at_cmd(buf, ">", 2000)){
if(send_at_cmd(msg, "\x1A", 5000)){
return; // 发送成功
}
}
}
}
[HAL](https://taotoken.net/?utm_source=hardware)_Delay(30000); // 30秒后重试
}
}
3.3 药量检测算法优化
原始方案直接比较瞬时值,导致误报率高。改进方案:
- 采用滑动窗口滤波(窗口大小=10)
- 引入状态变化检测:
- 持续5次检测到重量减少→判定为取药
- 单次突变→判定为干扰
- 自动补偿环境漂移:
c复制void auto_calibrate(){
static float history[24];
// 每小时记录一次基准值
history[hour] = read_hx711(50);
// 每天凌晨计算环境漂移
if(hour == 0){
float drift = median(history) - empty_weight;
empty_weight += drift * 0.2; // 渐进式调整
}
}
4. 生产级优化技巧
4.1 可靠性增强方案
- 看门狗设计:
- 独立硬件看门狗(MAX706)
- 软件看门狗分任务喂狗
- 异常恢复机制:
- GSM模块死机时自动断电重启
- Flash写失败自动切换备份扇区
- 数据完整性校验:
- 所有存储数据带CRC32校验
- 关键操作实现原子性提交
4.2 量产测试方案
开发了自动化测试工装:
- 药量模拟器:步进电机带动砝码升降
- 时间加速器:10倍速运行RTC时钟
- 网络模拟器:可编程信号衰减器
测试用例示例:
python复制def test_alert_flow():
set_rtc("10:00") # 设置到服药时间
wait_for_buzzer() # 等待蜂鸣器响起
press_button() # 模拟按键确认
assert sms_not_sent() # 应不发送短信
set_rtc("10:30") # 超时未服药
assert sms_sent_to("13800138000") # 应发送提醒短信
4.3 成本控制技巧
- 元器件选型:
- 用国产AT6558替代DS3231(节省8元)
- 选用公版SIM800C模块(比SIM800L便宜5元)
- 结构设计:
- 3D打印药盒转轴结构
- 采用磁吸式上盖简化装配
- 软件优化:
- 用软件I2C省去硬件I2C引脚
- 将部分功能移到GSM模块执行(如短信重发逻辑)
5. 典型问题排查指南
5.1 GSM模块无法注册网络
排查步骤:
- 测量天线端阻抗应为50Ω±10%
- 检查SIM卡触点氧化情况
- 用AT+CSQ检查信号强度(>10才可稳定通信)
- 确认APN设置正确(移动:CMNET)
5.2 药量检测异常
常见现象及对策:
- 读数漂移:
- 检查传感器供电电压(必须稳定5V)
- 增加防潮处理(涂覆三防漆)
- 突发干扰:
- 在HX711的DT和SCK线上加10pF电容
- 软件增加突变值过滤
5.3 功耗异常偏高
诊断方法:
- 分段测量电流:
- 断开GSM模块测基础功耗
- 逐个关闭外设定位问题
- 检查GPIO配置:
- 未使用引脚应设为模拟输入
- 输出低电平比高电平更省电
- 睡眠模式配置:
- 正确配置唤醒源
- 关闭所有外设时钟
6. 扩展功能实现
6.1 蓝牙配网方案
增加HC-05模块实现:
- 手机APP开发(Android示例):
java复制void sendAlarmTime(String time) {
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
socket.connect();
OutputStream out = socket.getOutputStream();
out.write(("TIME:"+time).getBytes());
}
- 协议设计:
- 采用TLV格式(Type-Length-Value)
- 增加AES-128加密传输
6.2 云平台对接
通过ESP-01S实现WiFi上传:
- 数据格式:
json复制{
"device_id": "BOX001",
"timestamp": 1654321000,
"events": [
{"type": "alert", "time": "08:00"},
{"type": "confirm", "time": "08:05"}
]
}
- 断网缓存机制:
- 本地存储最多100条记录
- 网络恢复后批量上传
6.3 多语言支持
采用UNICODE编码实现:
- 短信编码转换:
c复制void gsm_send_unicode(char *msg) {
uint16_t unicode[64];
UTF8_to_UTF16(msg, unicode);
hex_encode(unicode, buf);
send_at_cmd("AT+CSCS=\"UCS2\"", "OK", 1000);
send_sms(phone, buf);
}
- OLED显示处理:
- 使用自定义点阵字库
- 实现文本自动换行算法
这个项目最让我自豪的不是技术实现,而是收到用户反馈说"这个盒子让我妈妈再没错过吃药"。在硬件开发中,这种能直接改善生活的项目特别有意义。最后分享一个小心得:调试GSM模块时,���老式2G手机当信号强度参考最靠谱,那些专业仪器反而不如这个土办法直观。
