在医疗健康监测领域,便携式设备的续航能力一直是制约用户体验的关键因素。我最近完成了一个基于STM32L0系列微控制器的超低功耗血压和心率监测系统,通过精心设计的硬件架构和软件优化,实现了单次充电30天以上的续航表现。这个系统特别适合需要长期健康监测的中老年人群和慢性病患者。
核心功能包括:
整个系统的平均工作电流控制在2mA以内,这主要得益于三个关键设计策略:动态电源管理(各模块分时供电)、算法轻量化(减少计算复杂度)以及外设休眠机制(非工作时段关闭90%以上电路)。
这个系统的硬件架构围绕着"按需供电"的原则构建。锂电池电压经过TPS62740 DC-DC转换器降压到3.3V,这个转换器的效率高达95%,相比传统LDO稳压器能节省约30%的功耗。主控选用STM32L051C8T6,这是ST专为低功耗设计的Cortex-M0+内核MCU,具有以下优势:
传感器部分采用模块化设计,每个模块都有独立的电源控制:
在选择传感器时,我对比了市场上主流的几种方案:
心率传感器选型对比表
| 型号 | 技术原理 | 功耗(工作/休眠) | 接口 | 优点 | 缺点 |
|---|---|---|---|---|---|
| MAX30102 | PPG | 1mA/0.1μA | I2C | 集成度高,支持血氧 | 需要良好接触 |
| AFE4400 | PPG | 2.5mA/1μA | SPI | 信号质量好 | 外围电路复杂 |
| BH1790GLC | PPG | 0.7mA/0.5μA | I2C | 低功耗 | 仅支持心率 |
最终选择MAX30102是因为其集成度高(内置LED驱动和ADC),且支持双波长测量(未来可扩展血氧功能)。
血压传感器选型考量
对于血压测量,示波法需要高精度的压力传感器。MPX5050DP的线性度(±1.5%FSO)和温度稳定性(±1%FSO)满足医疗级需求。其模拟输出特性虽然需要额外ADC,但相比数字传感器(如BMP388)有以下优势:
整个系统的电源网络采用分级设计:
主电源路径:
外设电源控制:
关键提示:在PCB布局时,将常开电路和受控电路分区布置,避免漏电流路径。实测发现不当布局可能导致高达50μA的暗电流。
PPG信号采集电路
MAX30102的典型应用电路需要特别注意:
血压信号调理电路
MPX5050DP的输出信号处理采用两级滤波:
ADC采样配置要点:
整个软件基于状态机模型实现,这是低功耗系统的典型设计模式。主循环结构如下:
c复制while(1) {
switch(sys_state) {
case SLEEP_MODE:
Enter_Stop_Mode(RTC_WAKEUP);
break;
case HR_MEASURE:
heart_rate = PPG_Algorithm();
Save_To_Flash();
break;
case BP_MEASURE:
Measure_BloodPressure(&sys, &dia);
Check_Abnormal();
break;
case BLE_TX:
BLE_Send_Data();
Enter_Sleep();
break;
}
}
状态转换由以下事件触发:
PPG信号处理采用了我改进的峰值检测算法,相比传统方法有三个优化点:
c复制// 基于信号强度自动调整检测阈值
threshold = signal_min + (signal_max - signal_min) * 0.6;
c复制// 通过红外信号补偿运动干扰
compensated = red_data - 0.8 * ir_data;
c复制// 检查连续三个RR间期的变化率
if(abs(rr1-rr2)<rr_threshold && abs(rr2-rr3)<rr_threshold) {
hr_valid = 1;
}
实测表明,这种算法在静息状态下精度可达±2bpm,即使在轻度运动时也能保持±5bpm的精度。
示波法血压测量的关键在于特征点提取,我的实现包含以下步骤:
c复制// 充气到180mmHg
while(pressure < 180) {
HAL_GPIO_WritePin(PUMP_GPIO, PUMP_PIN, GPIO_PIN_SET);
pressure = Read_Pressure();
}
// 缓慢放气(约2mmHg/s)
HAL_GPIO_WritePin(VALVE_GPIO, VALVE_PIN, GPIO_PIN_SET);
c复制// 带通滤波(0.5-5Hz)
for(i=0; i<BUFFER_SIZE; i++) {
osc_wave[i] = Original[i] - Moving_Average(Original, 10);
}
c复制// 寻找最大振幅点(MAP)
max_amp = Find_Max(osc_wave);
// 收缩压=MAP前振幅上升至30%max的点
// 舒张压=MAP后振幅下降至30%max的点
通过实测发现,即使外设不工作,如果时钟未关闭也会消耗可观电流。我的优化措施包括:
c复制// 测量前开启外设时钟
__HAL_RCC_ADC1_CLK_ENABLE();
// 测量后立即关闭
__HAL_RCC_ADC1_CLK_DISABLE();
c复制// 未使用的GPIO配置为模拟输入
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
c复制// 用定点数代替浮点(Q15格式)
int32_t pressure_mmHg = (pressure_adc * 75) >> 10;
c复制// 展开关键循环减少跳转指令
for(i=0; i<100; i+=4) {
sum += data[i] + data[i+1] + data[i+2] + data[i+3];
}
c复制// 将频繁访问的变量定义为register类型
register uint32_t sensor_data;
在不同工作模式下的电流消耗:
| 工作模式 | 平均电流 | 持续时间 | 每日耗电 |
|---|---|---|---|
| Stop模式 | 0.8μA | 23.9小时 | 0.019mAh |
| 心率测量 | 4.2mA | 10秒 | 0.012mAh |
| 血压测量 | 9.8mA | 30秒 | 0.082mAh |
| BLE传输 | 5.1mA | 2秒 | 0.003mAh |
总日均耗电:约0.116mAh/天
理论续航:200mAh / 0.116 ≈ 1724小时(约72天)
实际使用中考虑到电池自放电等因素,实测续航约45-60天。
与医用血压计对比测试结果(单位:mmHg):
| 测试次数 | 标准值(SYS/DIA) | 测量值(SYS/DIA) | 误差 |
|---|---|---|---|
| 1 | 120/80 | 122/82 | +2/+2 |
| 2 | 135/90 | 138/88 | +3/-2 |
| 3 | 110/70 | 108/73 | -2/+3 |
| 4 | 125/85 | 128/83 | +3/-2 |
心率测量与心电图对比结果(单位:bpm):
| 测试场景 | 标准值 | 测量值 | 误差 |
|---|---|---|---|
| 静坐 | 72 | 71 | -1 |
| 轻度活动 | 95 | 93 | -2 |
| 深呼吸 | 68 | 70 | +2 |
问题现象:血压测量结果波动较大
可能原因:
解决方案:
c复制// 修改低通滤波截止频率从1.6Hz到1.2Hz
#define CUTOFF_FREQ 1.2
问题现象:手机APP偶尔无法连接设备
排查步骤:
最终解决方案:
code复制原设计:π型匹配(3.3pF+6.8nH+3.3pF)
优化后:3.6pF+5.6nH+3.6pF
c复制// 缩短连接间隔
gap_params.conn_params.min_conn_interval = 12; // 15ms
gap_params.conn_params.max_conn_interval = 24; // 30ms
问题现象:偶尔无法从Stop模式唤醒
调试过程:
根本原因:
电源上电速度过快导致MCU未正确初始化。解决方法:
c复制// 在初始化代码中添加延时
HAL_Delay(50); // 等待电源稳定
// 启用内部电压监测
PWR->CR |= PWR_CR_ULP;
经过实际使用,我认为还可以从以下几个方向进一步提升系统性能:
c复制// 检测能量收集源电压
if(Read_VIN() > 3.8) {
Enable_Charging();
}
算法升级计划:
生产优化建议:
这个项目最让我自豪的是通过精细的功耗管理,将常规设计需要每天充电的设备,优化到了数月才需充电一次的水平。在实际测试中,有个小技巧特别有用:在正式测量前让用户静坐30秒,这样不仅能稳定心率,还能让各传感器进入最佳工作状态,显著提升测量准确性。