去年帮家里老人调试血压计的时候,突然意识到传统医疗设备有两个痛点:一是体积大不便携,二是功能单一。于是萌生了用单片机开发多功能健康监测设备的想法。这个设计以STM32F103C8T6为核心,整合了心率、血氧、体温三合一检测功能,通过0.96寸OLED实时显示数据,异常值还会触发蜂鸣器报警。整套系统用3.7V锂电池供电,实测待机电流仅8μA,连续工作状态下续航能达到72小时。
选择单片机方案主要考虑三点:首先是成本控制,BOM总价可以控制在50元以内;其次是开发灵活性,后期要新增跌倒检测之类的功能也很方便;最重要的是低功耗特性,这对可穿戴设备至关重要。下面我就从硬件选型到算法优化,详细拆解这个项目的实现过程。
主控芯片经历过三次迭代:最初用的Arduino Nano,虽然开发简单但功耗太高;后来换ESP8266,Wi-Fi功能完全是浪费;最终选定STM32F103C8T6(蓝色药丸),72MHz主频够用,休眠模式电流仅2μA。这里有个坑要注意:同系列的STM32F103CBT6虽然Flash更大,但价格贵了三分之一,而我们的程序量根本用不到128K。
传感器组合方案对比表:
| 传感器类型 | 候选型号 | 单价(元) | 精度 | 功耗 | 最终选择 |
|---|---|---|---|---|---|
| 心率血氧 | MAX30102 | 18.5 | ±2bpm | 0.8mA | √ |
| SEN0203 | 32 | ±1bpm | 1.2mA | × | |
| 温度 | DS18B20 | 4.2 | ±0.5℃ | 1mA | × |
| MLX90614 | 56 | ±0.2℃ | 2mA | × | |
| MAX30205 | 21 | ±0.1℃ | 0.6mA | √ |
经验之谈:MAX30102一定要买带FIFO的版本!早期样品没注意这个细节,导致单片机要不停处理中断,功耗直接翻倍。
电源管理电路:采用TPS62740降压芯片,效率高达95%。特别设计了磁保持开关,长按3秒才开机,避免在包里误触发。实测发现,如果直接用LDO,电池电量低于3.6V时MAX30102就会工作异常。
信号调理电路:心率信号要经过两级放大——先用AD8232做仪表放大器(增益100倍),再用LMV358做带通滤波(0.5Hz-5Hz)。这里有个血泪教训:最初没加EMI滤波器,结果每次用手机充电器供电,心率数据就跳成心电图。
PCB布局禁忌:模拟地和数字地单点连接在MAX30205下方;MAX30102必须远离MCU且正面无走线,否则红外干扰会导致血氧读数漂移。我们的第三版PCB才解决这个问题,前两版只能靠软件滤波补救。
通过STM32的Stop模式+RTC唤醒,把平均功耗压到0.15mA:
c复制void Enter_StopMode(void){
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 被RTC唤醒后需要重新配置时钟
SystemClock_Config();
}
配合传感器间歇工作模式:每5秒唤醒采集10次数据(约1.2秒),其余时间全部断电。这里有个优化技巧:MAX30102的LED电流可动态调整,检测到信号弱时才提高电流,这样能省30%功耗。
原始PPG信号要经过五步处理:
最开始直接套用开源库算法,在运动状态下误差高达±10bpm。后来改进为运动补偿算法:通过三轴加速度计数据识别运动状态,动态调整滤波参数。关键代码如下:
c复制float dynamic_threshold(float accel_magnitude){
return BASE_THRESHOLD + accel_magnitude * 0.12f;
}
MAX30102厂商不公开SpO2算法,我们通过实验数据反推得出经验公式:
code复制SpO2 = 110 - 25*(R/AC_RED)/(R/AC_IR)
其中R是红光/红外光AC分量比值。要特别注意环境光补偿:必须先读取环境光强度,然后在LED关闭时采样一次作为基准值。我们收集了200组临床对比数据,最终将误差控制在±2%以内。
现象:连续使用20分钟后,体温读数会缓慢升高0.3℃
排查过程:
测试场景:慢走状态下的心率检测
原始算法输出:85 → 102 → 79 → 110(实际92)
优化方案:
第一个量产批次出现10%设备无法唤醒,最终发现是TPS62740的EN引脚没加下拉电阻,静电积累导致误触发。教训:所有使能引脚必须明确上下拉状态,不能依赖MCU内部电阻。
这个项目最让我意外的是MAX30205的响应速度——实测从休眠到稳定输出只需180ms,比DS18B20快20倍。现在正在开发第二代产品,准备加入ECG功能和蓝牙传输,不过那又是另一个故事了。