ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于STM32的可穿戴多生理参数监测系统:硬件选型、低功耗与预警算法实战

基于STM32的可穿戴多生理参数监测系统:硬件选型、低功耗与预警算法实战 我去年做的一个可穿戴项目前前后后迭代了三版硬件踩了不少坑这篇把完整的技术路径和心得写出来。项目本身是围绕STM32搭建的多生理参数实时监测与预警系统能同时采集心率、体温、运动状态等数据在本地完成异常判断并发起预警。适合正在做嵌入式毕业设计、准备电子设计竞赛或者想从零开始做一款完整可穿戴设备的开发者参考整篇会覆盖硬件选型、信号链路、低功耗设计、预警策略和实际测试这几个核心环节。1. 硬件选型与信号链设计的核心取舍1.1 为什么是STM32而不是ESP32或其它方案说起可穿戴设备的主控很多人第一时间会想到ESP32毕竟自带Wi-Fi和蓝牙开发资料也丰富。但这个项目我最终选了STM32L4系列原因有三点。第一是功耗。可穿戴设备长时间贴身佩戴电池不可能做得很大一颗100mAh左右的锂电池要撑住至少24小时对主控的待机功耗和运行功耗要求非常苛刻。STM32L4系列在运行模式下电流可以压到100μA/MHz以内停止模式更是能到微安级别这是ESP32做不到的。ESP32的Wi-Fi模块虽然平时可以关掉但它的射频前端和协议栈功耗还是偏大做低功耗手表这类产品不太合适。第二是模拟外设。多生理参数采集最核心的环节是把传感器输出的微小模拟信号转换成数字量。STM32L4内置了16位ADC和多个运放、比较器配合DMA可以直接把采集到的数据搬进内存CPU几乎不参与。这类高精度模拟采集能力是很多通用MCU不具备的。第三是生态。STM32的CubeMX加HAL库开发效率很高芯片型号切换也方便。而且这个项目涉及多路传感器、无线模块、OLED显示各种外设资源要同时跑STM32的中断优先级管理和定时器资源足够丰富后期扩展功能时心里有底。1.2 传感器选型每一路信号的来源这套系统一共采集三路生理参数心率、体温、运动状态。每一路传感器都经历过对比和替换我把最终方案和备选方案一并列出来。参数最终选型备选方案选择理由心率/血氧MAX30102反射式PPG传感器、胸带式ECG模块体积小I2C接口绿光红外双波长抗运动干扰能力比单波长强体温NTC热敏电阻(100kΩ)DS18B20、红外热电堆NTC响应速度快线性度可通过查表修正功耗极低成本几毛钱运动姿态LSM6DS3MPU6050、ADXL345六轴一体内置DMP可输出步数等算法结果功耗比MPU6050低15%左右这里多说一句心率传感器的坑。MAX30102在国内很容易买到但市面上水货很多部分芯片的寄存器地址和读出的数据跟正品有差异。我后来直接在立创商城买带编带的原装货虽然贵一点但省去了排查异常数据的痛苦。如果是做毕业设计建议优先在正规渠道购买某宝上散装芯片十片有八片数据不太对劲。体温测量我放弃了DS18B20原因是它温度分辨率虽然高但不适合做皮肤接触式测温。DS18B20是不锈钢封装的话热容太大测量皮肤表面温度时响应很慢而且贴紧程度不同读数差异很大。最后用了贴片NTC直接压在PCB的铜箔焊盘上再通过导热硅胶垫接触皮肤实测响应时间能控制在两秒以内。1.3 整体硬件架构和各模块的连接关系整个系统的硬件拓扑是一个典型的嵌入式数据采集链路传感器作为信号源STM32作为数据汇聚和处理中心OLED做本地显示蓝牙模块负责与手机通信蜂鸣器加LED做本地预警。MCU用的是STM32L431RCT6256KB Flash、64KB SRAM对这套系统来说绰绰有余。传感器I2C总线上挂了MAX30102和LSM6DS3体温NTC通过电压采样电路接到ADC引脚。电源部分用了TP4056充电芯片加XC6206 LDO把锂电池电压稳定到3.3V。有一个设计细节我觉得做得比较满意把传感器的模拟地和数字地做了单点连接避免数字信号噪声串进模拟采集链路。可穿戴设备PCB面积小地平面往往只有一整块但心率信号峰值只有几微安级别的光电流转换而来对噪声非常敏感。我在这上面吃过亏第一版PCB信号噪声大得离谱示波器一看波形全是锯齿后来把传感器底部做了开槽隔离才好转。2. 三路生理参数的数据采集实现细节2.1 心率采集从PPG原始波形到BPM计算PPG信号光电容积脉搏波描记法的原理不复杂LED发出的光穿透皮肤组织被血液部分吸收后光电二极管接收到反射光强信号。心脏搏动时血管容积变化导致接收光强产生周期性波动这个波动的频率就是心率。MAX30102内置了红光660nm和红外光940nm两个LED我的做法是用红外光作为主信号源。红外光对皮肤色素不敏感穿透深度更深在肤色较深的人身上表现更稳定。红光通道留着做血氧计算这个项目没有对血氧精度做临床级要求所以暂时只用了红外通道。采集逻辑上用定时器触发DMA连续读取FIFO每50ms读取一次积累到256个采样点做一轮处理。数据处理流程分四步滑动平均去高频噪声、去除基线漂移、峰值检测、计算瞬时心率。峰值检测我用的是自适应阈值法。具体来说就是维护一个滑动窗口取窗口内的最大值和最小值的中间值作为动态阈值信号上升沿跨过阈值时记一次心跳。这个办法比固定阈值鲁棒很多因为PPG信号的幅值会随着佩戴松紧、运动状态剧烈变化固定阈值要么漏检要么误检。一个实际的例子静坐时红外PPG信号的峰值电压大约在200mV左右但稍微走动一下运动伪迹产生的基线漂移就能达到500mV以上。如果不做基线漂移去除峰值检测算法会把这些漂移误认为心跳信号算出来的心率直接飙到150以上。2.2 体温采集NTC查表法和滤波处理NTC热敏电阻的阻值随温度非线性变化我用的100kΩ规格在25℃时阻值是100kΩ温度系数大约是-4.4%/℃。为了把电阻变化转成电压信号我搭了一个简单的分压电路3.3V电源串联一个100kΩ精密电阻再串NTC到地从两个电阻的连接点取电压。ADC采到的电压值经过下面公式换算成电阻值R_ntc R_ref × (V_ref - V_out) / V_out拿到电阻值之后通过查表法换算成温度。我在代码里建了一张-20℃到60℃、精度0.1℃的NTC分度表总共801个点占用不到1KB的Flash。查表时用二分查找找到相邻两个温度点的区间再线性插值出精确温度。实际测试下来这个方案的测量误差能做到±0.2℃以内跟水银体温计对比过满足日常体温监测需求。滤波方面我用了滑动平均加一阶低通滤波双保险。NTC本身热质量小容易受到环境温度波动的影响一段30秒的采样数据如果不做滤波可以看到明显的随机抖动。滑动平均窗口取16个点一阶低通的系数取0.8实测滤波后数据平滑很多响应速度也不会有明显延迟。2.3 运动姿态采集加速度计数器的低功耗处理LSM6DS3的配置上我把加速度量程设成±4g采样率设成52Hz。这个采样率是经过计算的人体日常运动的频率主要集中在0.5Hz到20Hz之间52Hz的采样率足以覆盖有效频段同时功耗只有0.4mA左右。运动状态判断用了一个非常简单的算法每秒钟计算一次加速度向量的模长平方公式是a² x² y² z²。静止状态下模长平方约等于1g²因为只有重力加速度一旦人开始走动或者跑动模长会明显偏离这个值。设定两个阈值来判断状态A² 1.1时判定为静止1.1 ≤ A² 1.8时判定为轻微活动A² ≥ 1.8时判定为剧烈运动。这套判断在普通行走、上楼、慢跑等场景下实测准确率大概在八成左右作为状态判断已经够用。更精细的计步算法其实可以依赖LSM6DS3内置的计步功能它内部有个步数计数器走一步加一。但实测下来这个内置计步器在慢走时偶尔会漏步所以我最后还是在MCU端自己实现了步数检测做法是对加速度波形做峰值检测加零交叉计数每检测到一个完整的波峰波谷且幅值超过阈值才算一步。3. 预警系统的算法设计阈值、判定与去误报3.1 多参数联合判定单一参数容易误报组合起来才靠谱预警系统最核心的难点不是阈值设多少而是怎样减少误报。只盯着心率一个指标血压偏高的人稍微走两步心率就上100如果100次/分钟就报警那系统几乎每分钟都在响。我的做法是采用多参数联合判定逻辑。只有当心率、体温、运动状态三个维度同时满足异常条件时系统才触发预警。判定规则用了一张状态表来表达。运动状态心率异常阈值体温异常阈值预警等级静止静息心率超过100或低于50体温超过37.5℃或低于35.5℃中级预警轻微活动心率超过140体温超过38.5℃中级预警剧烈运动心率超过180无低级别提醒这个表的设计思路是静息状态下心率阈值设得比较严格因为正常情况下静息心率在一个窄范围内波动运动状态下心率本来就该升高所以阈值放宽到对应运动强度下的预期心率区间。实现上运动状态判定模块的输出会传到一个状态机预警判定逻辑每秒钟执行一次。只有当异常情况持续超过30秒才真正触发预警短于30秒的偶发抖动一律忽略掉。这个30秒的延迟窗口对减少误报帮助极大实测下来误报率至少下降了七成。3.2 心率变异性特征作为预警的辅助维度除了绝对阈值我还加了一个心率变异性HRV的分析维度。HRV是指相邻两次心跳之间时间间隔的波动情况医学上认为HRV降低往往意味着身体处于应激状态或者过度疲劳。具体实现是记录最近60次心跳的RR间期相邻R波之间的时间间隔计算标准差和均方根差值。当标准差连续两分钟低于某个阈值同时心率又超过正常范围系统会给出疑似疲劳状态的提示。这个功能实现起来不复杂但非常加分。比如一个用户静坐时心率80不算异常但HRV指标明显下降说明他的自主神经调节状态可能有问题。这种看图说话式的联合分析比单纯看心率高低有价值得多。3.3 预警响应的分级设计与防抖机制预警不是一触即发我设计了三级响应机制提醒级别OLED屏幕闪烁显示异常参数蜂鸣器短鸣一次信息通过蓝牙推送到手机App。中级预警OLED持续显示异常提示蜂鸣器每5秒响一次手机App持续推送通知。高级预警蜂鸣器连续鸣响系统自动通过蓝牙向预设联系人发送紧急通知消息。防抖机制除了前面提到的30秒确认窗口还有一个冷却时间设计。同一种类型的预警触发后5分钟内不会再次触发同级别预警防止设备在异常状态持续存在时反复报警导致用户麻木。这个设计在真实使用中很实用我戴着手环做测试的那段时间如果没有冷却时间设计光是心率偶尔波动就会让手机响个不停。4. 低功耗设计续航才是可穿戴设备的第一竞争力4.1 功耗预算表每一毫安电流都要精打细算可穿戴设备能不能被用户接受续航能力是决定性的。我给自己定的目标是100mAh电池持续工作24小时以上。为了实现这个目标我首先做了一张完整的功耗预算表。硬件模块工作电流占空比平均电流STM32L431运行模式4.8mA 16MHz50%2.4mAMAX30102心率传感器0.6mA20%0.12mALSM6DS3加速度计0.4mA100%0.4mANTC分压电路33μA100%0.033mAOLED显示屏18mA10%1.8mABLE蓝牙模块8mA5%0.4mALDO静态电流1μA100%0.001mA系统总平均电流--约5.15mA注意OLED显示屏是整个系统最大的耗电来源虽然它只在显示时工作18mA但10%的占空比就占了平均电流的1.8mA。为了进一步压低这块功耗我把屏幕刷新率降到1Hz同时只刷新变化的区域。正常显示状态下一块屏幕每秒钟需要的电流大约只有静态全亮刷新时的三分之一。按照5.15mA的平均电流计算100mAh电池的理论续航是19.4小时不够24小时的目标。所以还需要做进一步优化。4.2 动态电源管理让MCU在99%的时间里睡觉进一步优化核心思路是让STM32进入低功耗模式。具体做法是把系统改成事件驱动模式正常情况下MCU进入STOP2模式电流只有1μA左右然后通过RTC闹钟每500ms唤醒一次处理完数据又睡回去。RTC唤醒周期内的工作流程是这样的唤醒后先读取加速度计数据判断是否发生运动如果有运动就进入全速模式采集心率如果静止则把心率采集的间隔拉长到5秒一次体温每10秒采一次。这个策略的依据是人在静坐或者睡眠时生理参数变化缓慢没必要以100Hz的频率连续采集中等频率采样完全够用。而在运动状态下心率变化快需要连续监测所以动态调整采样率。优化后系统功耗模型变为配置模式下CPU使用率不足1%系统绝大多数时间处于低功耗睡眠状态。实测下来100mAh电池的续航从19.4小时提升到了30小时以上最初设定的24小时目标顺利达成。4.3 传感器和蓝牙模块的供电开关设计传感器和BLE蓝牙模块是除了MCU之外的另外两个耗电大头。MAX30102内部LED的驱动电流是可以配置的我把它从默认的50mA降到了20mA配合合适的透光率在手腕上依然能采到有效信号。这样MAX30102在工作模式下的电流从0.6mA降到了0.25mA。蓝牙模块我用了BLE 4.2协议的透传模块工作电流8mA左右。BLE协议本身支持广播间隔和连接间隔的动态调整在静止状态下我把广播间隔拉长到1000ms连接间隔拉到100ms这样平均电流可以压到0.1mA左右。一进入预警状态再把广播间隔调到100ms确保手机能第一时间收到消息。还有一个细节NTC分压电路虽然静态电流只有33μA但它是常开的。我加了一个MOS管做电源控制在MCU深度睡眠期间把分压电路的电源也断掉又省了一部分电流。这类看起来很小但积累起来很可观的电流开销在可穿戴设备里比比皆是每省下一毫安续航就多一份保障。5. 数据链路与上位机本地显示、手机推送与云端存储5.1 蓝牙通信协议设计与数据帧格式可穿戴设备和手机之间要交换的数据类型很杂有心率、体温、运动状态、预警事件、设备状态等。如果只是简单地把所有数据拼在一起发送解析端会很痛苦。所以我在数据链路层设计了一套轻量级的帧格式。帧格式如下字段长度说明帧头1字节固定为0xAA数据类型1字节0x01心跳数据0x02状态数据0x03预警事件数据长度1字节数据域字节数数据域N字节具体数据校验和1字节数据域累加和的低8位校验和用于检测数据传输过程中的错误。BLE传输偶尔会出现丢包加了校验之后接收端可以识别出坏帧并请求重传。预警事件帧的数据域我定义成这样第一个字节是预警等级第二个字节是预警类型1心率异常、2体温异常、3运动状态异常后面跟着具体数值和时间戳。这样手机端收到预警事件后可以直接根据类型弹出对应的通知文案。5.2 手机端数据展示与本地日志存储手机端我用的是Android平台的简单App通过系统的BLE API与设备通信。App的功能分成三块实时数据展示、历史数据曲线、预警消息管理。实时数据展示部分用一个自定义View画折线图每收到一帧数据就更新曲线并显示最新数值。历史数据先缓存在手机本地SQLite数据库里这样即使不联网也能查看过去七天的心率变化趋势。预警消息管理会单独放一个列表标记每次预警的时间、类型和当时的三项参数值。BLE通信这块有个容易踩的坑Android的BLE API在连续收发小数据包时偶尔会出现Gatt status 133连接断开的问题。这个错误通常是因为底层在短时间内收到了太多数据超过了协议栈的处理能力。我在代码里把发送间隔限制到50ms以上每次只发20字节以内的数据问题就消失了。5.3 数据上云可选的进阶功能本地存储的问题在于数据不能远程查看。我给系统预留了Wi-Fi模块的接口通过ESP-01S模块和MQTT协议将采集到的数据上传到公共MQTT服务器。这样手表周围5公里内通过手机App可以远程看到家里老人的实时体征数据。MQTT的主题设计成按设备ID和设备类型分层的结构比如device/{id}/heartrate和device/{id}/alert。服务器端用Node-RED做一个简单的订阅程序实时转发到网页仪表盘上。这部分的功耗会比只开蓝牙高出不少所以做成可配置项默认关闭。只有需要远程监控时才在手机App里手动打开。6. 整机测试与问题排查实测数据、典型故障与解决思路6.1 正常佩戴场景下的实测数据设备完成之后我戴在手腕上进行了48小时的不间断测试记录了三组典型的实测数据。静坐状态下心率稳定在68-75次/分钟之间运动状态切换时心率从70左右逐渐上升到100左右。体温数据在36.3-36.8℃之间波动符合正常人体体温范围。运动状态下心率从120回到静息值约需要2-3分钟这个恢复速度说明心率监测模块的响应比较及时。我特意测试了一个异常预警的场景连续做高抬腿运动两分钟让心率冲到150以上系统在心率超过140并持续30秒后触发中级预警OLED弹出红色警告图标手机端同步收到推送。整个过程从心率越线到预警响应延迟大约35秒包含30秒确认窗口和传输延迟符合设计预期。6.2 信号质量问题的完整排查链路第一版样机在验证阶段出现了一个典型的信号质量故障心率数据时有时无静止状态下也无法稳定采到有效波峰。排查过程花了整整两天我把完整链路写出来供大家参考。第一步怀疑传感器本身。用示波器监控I2C引脚发现传感器能正常应答数据能够读取但FIFO里读出的原始光强数据幅值极低几乎只有正常值的三分之一。这说明问题出在光路环节。第二步检查透光结构。排查发现我用的手环外壳是深色半透明硅胶对红外光有较大的吸收。把外壳拆掉之后原始信号幅值立刻恢复到了正常水平。第三步验证后发现还有一个隐藏问题。传感器与皮肤贴合面留了0.5mm的缝隙环境光直接射进了传感器导致基线漂移严重。解决方案是在传感器周围加一圈遮光泡棉让传感器紧贴皮肤同时排除环境光干扰。这个排查过程告诉我一个道理PPG模块的光路设计和电路设计同样重要甚至更重要。传感器周围哪怕只有一条细小的漏光缝隙都会对信号质量产生毁灭性影响。可穿戴设备的外壳设计阶段就要把光学窗口和贴合结构纳入考虑不能等硬件做完了再补救。6.3 系统级联调时的线程优先级问题软件联调阶段遇到一个隐蔽的Bug心率采集偶尔会丢数据排查后定位到是SPI和I2C的中断优先级配置问题。LSM6DS3的SPI中断优先级高于MAX30102的I2C中断在高数据速率下SPI中断频繁抢占I2C中断的时序导致I2C通信偶尔失败。处理方式是把I2C中断优先级提到最高SPI中断降一级同时在两个外设的DMA中断服务函数里加入互斥判断避免同一时间两个DMA同时访问内存缓冲区。这类问题很难通过查阅数据手册发现只有在真实系统里跑高频数据流时才会暴露。调试时推荐用逻辑分析仪同时抓取两路总线的波形对比看看是否存在总线冲突定位效率会高很多。7. 项目可扩展方向与个人经验总结这套系统基本功能已经跑通但距离产品还有不少距离。如果大家想在这个基础上继续深入我列出几个我认为最有价值的扩展方向。第一个方向是提升算法的临床价值。目前的心率算法、HRV分析都还只是能跑的程度距离医疗级的准确度和可靠性还有差距。接入更复杂的信号处理算法比如基于小波变换的伪迹去除、基于机器学习的运动状态识别可以让预警系统的准确率提升一个台阶。第二个方向是引入更多传感器。血氧饱和度SpO2、血压趋势、皮肤电导率GSR都是很容易集成进去的生理参数。MAX30102本身就支持红光和红外光双波长只需在算法上增加一个光密度比计算就能输出血氧值。第三个方向是结构设计的优化。我用的是3D打印的外壳加上弹性表带体积和重量控制得不算好。如果做到接近主流手环的尺寸需要在PCB堆叠、电池形态、传感器布局上做更精细的规划。最后说一个我在整个项目中感受最深的地方可穿戴设备和普通嵌入式项目最大的区别在于它的每一个子系统都要同时满足功能、功耗、体积三个维度上的约束。采集到信号不难难的是在微安级电流预算内持续稳定地采集信号做一个功能模块不难难的是把它塞进一小块PCB上实现一个算法不难难的是让它在低功耗处理器上实时运行。做这个项目的过程中我在这三个约束之间反复权衡、反复妥协最终找到一套还算平衡的方案。这种戴着镣铐跳舞的训练对理解嵌入式系统设计的本质帮助非常大。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进