做嵌入式医疗设备这些年,我接触过不少血压测量方案,从早期的分立式模拟电路,到后来带MCU的数字方案,再到现在的MCU Sensor Hub架构,变化确实大。简单说,MCU Sensor Hub就是把压力传感器、加速度计、温度传感器这些数据全部汇聚到一颗MCU上,由它统一完成采集、滤波、特征提取和血压计算,既当传感器中枢,又当算法主脑。这套方案解决了传统方案电路分散、校准困难、实时性差的问题,非常适合做电子血压计、可穿戴健康设备这类产品。无论你是刚入行的嵌入式工程师,还是想把成熟方案快速落地的产品经理,这篇内容都能给你一个完整的参考。
1. 方案整体设计与架构思路
1.1 为什么不是分立器件,而要用MCU做Sensor Hub
早年做血压计,模拟电路时代是压力传感器、运放、窗口比较器、屏显驱动一堆IC凑在一起,每个功能模块独立调参,非常痛苦。后来进入数字时代,最简单的是MCU只负责采集数据、计算、显示,传感器各自带调理芯片,通过I2C或SPI上报。这个方案能用,但有个致命问题:多路传感器并行接入时,数据同步、优先级、休眠唤醒的协调非常麻烦,一旦出现干扰或者某一路传感器异常,整个系统没有任何弹性缓冲。
MCU Sensor Hub的核心思路,是把MCU放在传感器和上层决策逻辑中间,所有传感器数据先经过MCU做一次预处理和融合,再把高质量的数据交给上层。这样带来的好处很明显:
- 实时性好。充气泵、泄气阀、压力采样这三件事必须严格同步,MCU直接管底层的PWM和ADC,数据从传感器到计算核心的延迟可以控制在微秒级。
- 功耗可控。Sensor Hub架构下,MCU可以采用轮询加中断的混合模式,没有测量任务时外设全部关断,MCU进入低功耗睡眠,按一个按键就能唤醒整个链路。
- 算法可迁移。血压计算、滤波、运动伪差识别这些算法写在MCU内部,换一个蓝牙SoC或者升级显示模块,核心算法不用变。
- 扩展性好。今天接血压传感器,明天想接血氧探头、体温探头,Sensor Hub的架构不需要推翻重来,新模块挂到总线上,加一段驱动和状态机就行。
所以我在做方案评审时,基本都会要求用MCU Sensor Hub架构,除非产品实在简单到只剩一个传感器。站在产品迭代的角度,这个架构的投资回报率是最高的,因为你不需要为下一代产品重写底层。
1.2 系统总体架构与数据流设计
整个血压测量方案,数据流大概是这样的:袖带里的气压经压力传感器转换为模拟电压或数字码值,进入MCU后先做校准补偿,再做带通滤波提取脉搏波;与此同时,MCU还要通过PWM控制充气泵和泄气阀。经过多次心跳周期,MCU从脉搏波包络中找出最大振荡点计算平均压,再按比例关系算出收缩压和舒张压,最后把结果送到LCD屏、蓝牙或手机App。
从硬件模块划分,主要有感知层、处理层、执行层和交互层:
- 感知层:压力传感器、加速度计(运动检测)、温度传感器。压力传感器多数是模拟输出,也可以选择带I2C的数字压力传感器,后者能省掉外部运放。
- 处理层:一颗带ADC、定时器、PWM和低功耗模式的MCU,这是Sensor Hub的核心。
- 执行层:充气泵(直流电机或微型气泵)、泄气阀(比例阀或电磁阀),通过MOS管或驱动芯片受MCU控制。
- 交互层:LCD段码屏或LCD点阵屏,以及BLE模块。
在实际项目中,为了控制成本,很多人倾向用单颗MCU直接驱动BLE,而不是MCU加蓝牙双颗芯片。比如带BLE的ARM Cortex-M4芯片,把Sensor Hub功能和无线协议栈放在同一颗芯片里,虽然协议栈会占用部分资源,但整机BOM成本和PCB面积都下降明显。如果是可穿戴血压手表,建议用带BLE的SoC方案;如果是家用上臂式电子血压计,MCU外接蓝牙模块也完全够用。
我在这里给一个芯片选型的参考表格,都是实际项目中比较常见的组合:
| 方案类型 | 典型芯片 | 适合场景 | 关键优势 | 主要代价 |
|---|---|---|---|---|
| 裸机MCU+外部蓝牙模块 | STM32F0xx + nRF52832 | 家用上臂式血压计 | 稳定、开发简单、成本低 | BOM器件多,PCB面积大 |
| 单芯片SoC带BLE | TLSR8258、nRF52840 | 可穿戴血压手表 | 集成度高、功耗低 | 需处理协议栈资源占用 |
| 高性能工业MCU | STM32H7、TI AM261x | 高端多传感医疗终端 | 异构并行处理能力很强 | 成本偏高,开发复杂度大 |
再补充一点关于高端MCU的使用场景。现在有不少大厂在工业医疗领域推高性能MCU,比如TI AM261x这类异构计算、实时控制和工业通信一体的架构,或者STM32H7系列里专门做FOC电机控制的高性能MCU。这些芯片用在血压计上确实性能过剩,但如果产品希望在同一颗MCU上同时做无线充电控制、多路传感器融合、FOC驱动的气泵电机,那高端MCU就派上用场。我们在做一款带无线充电的医疗健康终端时,就用过类似方案,电机控制环和传感器采样环在不同的执行内核上独立运行,互不干扰。
2. 核心传感器与信号处理细节
2.1 压力传感器选型与采样配置
压力传感器是决定测量精度的第一个关卡。袖带测量范围一般要覆盖到300mmHg,加上安全裕量,建议传感器量程选0到37kPa甚至更高。选择传感器有三个要点:
- 表压还是绝对压。血压测量要的是袖带内相对环境气压的压力,所以通常选表压传感器。如果用了绝对压传感器,需要在软件里减去环境气压,不仅多一个变量,还会引入气压计误差,不推荐。
- 模拟输出还是数字输出。模拟输出的好处是响应快、可选传感器多,但MCU需要集成高精度ADC,对采样电路、基准电压和布线都更挑剔。数字接口的传感器(如I2C接口的SSC系列、BMP388)自带内部温度补偿和校准,软件更省事,但采样率一般不会太高,选型时要仔细看datasheet里的OSR设置,别让采样率拖了后端算法的后腿。
- 温漂。如果产品要在零下20度到50度环境使用,压力传感器的温漂补偿必须考虑。选择带温度补偿输出的传感器,或者在PCB上放一颗温度传感器,软件做分段补偿,否则冬天和夏天的测量结果可能差好几个mmHg。
采样率方面,示波法脉搏波频率大概在1到4Hz,但包络提取和峰值检测需要足够的过采样。我一般把压力采样率设在200Hz,对应5ms一个点。这样既能保证包络细节,也不会给MCU造成太大负担。ADC分辨率我用16位,实际测量中压力范围0到300mmHg,用满量程算下来每一个可判别的码值对应的压力变化大约0.005mmHg,处理微小振荡波时余量充足。
2.2 示波法血压计算原理拆解
市面上电子血压计绝大多数用的是示波法,原理可以这样理解:袖带充气到超过收缩压,把动脉压闭,然后以恒定速率放气。在放气过程中,心脏每次泵血都会在袖带里产生一个很小的压力振荡,这个振荡叠加在袖带基础压力上。MCU的任务就是把两路信号分离开:直流分量是袖带压力,交流分量是脉搏波。
计算流程分几步走。第一步,从原始压力数据中提取袖带压力序列;第二步,通过带通滤波得到脉搏波振荡包络;第三步,找到振荡幅度最大的位置,此时袖带压力等于平均动脉压(MAP);第四步,按照收缩压和舒张压的经验比例,从包络的左右两侧分别找到对应幅度点。
具体来说,收缩压位置通常在最大振荡幅度的50%左右,舒张压在75%左右,但不同算法厂商会根据自己的临床数据库调整这些比例。比如有些算法会在0.45到0.55之间动态调整,有些会结合人群特征(年龄、臂围)做修正。这个比例参数强烈建议用自家的临床测试数据来标定,不要直接照搬别人的库参数,否则在不同人群上测出来的偏差会很明显。
这里要特别提醒一点:示波法不是直接测量血压,而是通过振荡包络特征推算血压,所以它依赖一个假设——脉搏波振荡从被阻断到恢复的过渡过程中,包络形状是光滑的单峰曲线。如果测量过程中出现明显体动,包络会变形,计算出的血压值就会失真。这也是为什么Sensor Hub方案里一定要加加速度计,靠它来识别运动伪差,一旦检测到手臂抖动,直接丢弃当前测量周期。
2.3 MCU端的滤波器设计与实现
压力传感器输出的原始信号里,直流袖带压可能高达200mmHg,而脉搏波振荡通常只有几个mmHg,二者的幅度差了两个数量级。如果直接用ADC原始码值做峰值检测,微弱振荡会被直流量淹没。所以软件滤波是整个方案里非常关键的一环。
我的做法是先用一个一阶高通或带通滤波器把直流分量去掉,再用滑动平均做去噪处理。
工程上,我会维护一个环形缓冲区,每次ADC中断到来,往里塞一个原始压力值,然后跑一次IIR滤波。IIR的系数不需要特别复杂,二阶巴特沃斯带通就够了。
// 带通滤波器示例:采样率200Hz,通带0.5~10Hz // 这里以二阶IIR为例,实际系数通过滤波器工具生成 float iir_bp(float x, float* x_hist, float* y_hist, const float* b, const float* a) { float y = b[0] * x + b[1] * x_hist[0] + b[2] * x_hist[1] - a[1] * y_hist[0] - a[2] * y_hist[1]; x_hist[1] = x_hist[0]; x_hist[0] = x; y_hist[1] = y_hist[0]; y_hist[0] = y; return y; }实际工程里,我不建议在MCU里用太高阶的滤波器,阶数越高,群延迟越大,脉搏波的峰值位置会被拉偏,MAP定位就不准。用二阶或四阶巴特沃斯就足够了。如果MCU资源够,可以在放气过程结束后,对完整波形做一次离线滤波;如果MCU性能弱,就做在线滑窗滤波。
滤波器实现时还要注意定点数的问题。很多MCU没有FPU,直接用浮点库会很慢,可以把滤波器系数缩放并转成Q15或Q31格式,用定点运算代替浮点。ADC采进来的数据是16位,做一次IIR运算保持到32位中间值,最后再归一化,精度完全够。这个点经常被新手忽略,实际踩过坑的人都知道,定点实现和浮点实现差距不小,特别是系数接近临界值时,浮点转定点后如果没用足够宽的中间变量,会出现极限环振荡,屏幕上就能看到波形在零点附近抖动。
3. MCU核心功能实现与实操
3.1 充气泵与泄气阀的闭环控制
很多人以为血压计的充气放气不就是开关一下泵和阀嘛,其实细节很多。充气阶段,MCU输出PWM控制充气泵,目标是快速把袖带压力提升到比收缩压高30到40mmHg左右,一般取180到190mmHg。如果充气太慢,测量时间长,用户手会酸;充气太快,传感器过冲,也会带来测量误差。
放气阶段是最讲究的,行业通用做法是放气速率控制在2到6mmHg每秒,推荐3到5mmHg每秒。为了达到这个目标,MCU需要每5ms读取一次当前压力值,和期望的放气曲线对比,然后微调泄气阀PWM。这是一个典型的PID控制回路,Kp、Ki、Kd的参数需要在样机上整定。温度变化会影响阀的物理特性,建议在算法里加入自适应补偿,实测发现温度变化时参数偏一点,放气曲线就容易出现阶梯状波动。
另外,充气泵的电机会产生较大电流瞬变,如果供电走线和传感器模拟信号走线共享,ADC读数会被明显干扰。我遇到过一例,充气泵一启动,压力波形里就叠加了一串高频毛刺,后来排查发现是电机的地和传感器模拟地在一颗芯片下面汇合了,把两者分开布地后毛刺消失。充气泵的控制PWM频率也不要选在人耳可听又容易被传感器拾取的频段,一般选20kHz以上,避开信号带宽。
3.2 核心算法落地:从ADC码值到血压值
算法的完整链路,我建议按阶段拆:采集阶段、有效脉搏波提取阶段、包络生成阶段、血压计算阶段。每一个阶段单独测试,不要等整个系统完成再一起调,否则出了问题根本定位不到。
采集阶段,MCU启动一次测量后,先打开充气泵,同时连续采样压力值。为了避免充气泵对传感器读数的干扰,我通常在PWM输出和ADC采集之间做一个时间交错:PWM高电平期间暂停采样,等低电平时再采集。这个技巧在低成本方案里很管用,实测能减少不少噪声。
有效脉搏波提取阶段,MCU要对每次心跳产生的振荡波做判断。判断条件有三个:振荡波峰值是否超过设定阈值、波的周期是否在每分钟40到120次的合理范围、波与波之间的间隔是否平稳。三者都满足才认为是有效波。这样能滤掉不少干扰,比如咳嗽、手臂突然动一下、袖带漏气引起的伪波。
包络生成阶段,每检测到一个有效波,就记录它的峰值幅度和对应的袖带压力值,形成一个峰值对。随着放气过程推进,所有峰值对连起来就是振荡包络。MCU实时更新最大峰值位置,放气结束后再对包络做一次平滑。
血压计算阶段,先定位最大峰值对应的袖带压力就是MAP,再分别向前后查找幅度为MAP幅度的50%和75%的位置,分别对应收缩压和舒张压。这里还要做边界保护,比如找不到50%点就按固定偏移估算,并且对结果做合理性校验,收缩压和舒张压差值小于15mmHg时视为异常,提示重测。
这里要特别提醒一下ADC的工作原理细节。MCU的逐次逼近型ADC在工作时,采样电容会在开关闭合瞬间从外部信号源抽取一个瞬态电流,如果外部信号源阻抗太高,电压建立时间不够,转换结果就会偏低。所以模拟输出压力传感器后面加一级电压跟随器做缓冲,是非常有必要的,别为了省一颗运放而导致ADC精度白白损失。
3.3 低功耗与启动流程、通信接口细节
血压计如果是电池供电,整机功耗要算得很细。测量阶段功耗高是正常的,关键在待机状态。待机时MCU进入低功耗停驻模式,关闭传感器供电,用外部中断唤醒。这里需要注意:唤醒后不能立刻开始测量,要等传感器上电稳定。压力传感器从上电到输出稳定通常需要几十到几百毫秒,具体看器件手册,我习惯在唤醒程序里留一个延时200ms,否则第一帧压力数据往往偏得离谱。
谈到MCU上电启动流程,千万别忽略时钟稳定时间。MCU上电后,如果直接从内部高速RC切到PLL,时钟没有稳定就初始化ADC和定时器,采样时间基准会漂,甚至外设寄存器配置丢失。我建议MCU启动后先等待PLL锁定标志,再做外设初始化。这个细节在常温下不容易暴露,但在低温或电源稳定性差的场景下,概率性死机就是这些细节累积出来的。
通信接口方面,如果BLE模块挂UART,那么串口接收引脚的上拉必须注意。很多BLE模块的空闲状态是高电平,若MCU引脚内部上拉并打开,而模块侧没有配置上拉,静态时电平还稳定,但一旦通信距离变长或者线缆有点寄生电容,波形沿会变差,出现丢字节。我习惯在PCB上给UART_RX和UART_TX都加上外部4.7k上拉,尤其是RX引脚,宁可多一颗电阻也不要赌模块内部的默认状态。
4. 常见问题与排查技巧实录
4.1 测量结果忽高忽低,先别怀疑算法
每次有人拿着血压计样机找我debug,说算法有问题,我第一步不是调算法,而是先检查物理环节。袖带尺寸有没有匹配?袖带绕手臂的松紧是否一致?袖带和气管接头处有没有慢性漏气?这些因素对结果的影响比滤波参数大得多。
举个例子,袖带每次绑的松紧不一样,相当于初始加压基线就不一样,放气过程中示波波的传递效率也会变化,最后算出来的血压值离散度自然大。实测下来,同样一个人,袖带绑得松一点和紧一点,收缩压可以差10mmHg以上。所以软件上可以做一件事:每次测量前检测袖带压力在充气初期的上升斜率,斜率偏低说明可能是漏气,斜率突变说明袖带可能没绑好。把这两类情况直接提示给用户,比让用户看一个异常数据有用得多。
4.2 ADC噪声导致的波形毛刺怎么定位
ADC噪声是血压计样机调试里最常见的问题之一。要定位噪声是来自电源还是来自PCB布线,我有个土办法:先用外接标准电源给传感器独立供电,看波形是否干净。如果干净了,说明问题在电源链路,优先查充气泵的电流回路,看看泵的地是否和主控地单点汇合;如果还是毛刺,说明PCB布线或者传感器本身有问题,换一颗传感器试一下。
软件层面,ADC过采样加均值是简单有效的办法。假如MCU的ADC采样率足够,可以对每个压力点连续采16次,去掉最大最小值后取平均。过采样加上均值,等效于把ADC的噪声均摊掉,实测可以把压力波形的峰峰值波动从几个码值降到1个码值内。不过要注意,过采样频率过高会占用MCU时间片,如果主循环里还有PID控制和显示刷新,记得合理安排采样时序,别让ADC中断把主逻辑堵死。
4.3 传感器校准与整机一致性验证
压力传感器出厂时每个个体都存在offset和gain误差。整机生产线上至少要标定两个点:一个零点、一个满量程点。做法是给每个产品灌入稳定的标准压力,记录ADC码值,然后在线烧录校准系数。这个工作不能省,尤其现在传感器价格压得很低,误差离散度反而比早年的贵料还大。
校准之后要做什么?一定要做整机对比验证。我通常的做法是找一台已经过计量校准的标准血压计(最好是水银柱式或经过校验的电子式),在同一人同一臂上交替测量,记录至少30组数据,计算平均偏差和标准偏差。行业一般要求平均偏差在正负5mmHg以内,标准偏差在8mmHg以内。达不到就要回头查算法参数和物理环节。不要跳过这一步直接把产品推向市场,血压数据是医疗健康数据,偏差会直接影响用户对产品的信任。
另外再分享一个小技巧:全流程自检。每次上电时,MCU可以做一个漏气自检,关闭泄气阀,充气泵启动一小段,看看压力衰减速率是否在正常范围。如果衰减过快,判断为袖带或气管未接好。这个功能看起来简单,但对用户体验的提升非常明显,用户还没开始测,设备就把故障提示出来了。
4.4 算法参数调参的常见弯路
很多团队把示波法算法当成黑盒,直接照抄公开论文里的比例参数。但公开论文使用的数据集、袖带形态、人群和你的产品不一定匹配,直接套用往往偏差很大。正确做法是:先固定硬件,采集足够多的临床对比数据,再用数据反推适合的幅度比参数。
调参时还有一个容易踩的坑:包络平滑的窗口太宽。滑动平均窗口设太大,包络过于平滑,峰值会偏移,MAP计算偏大;窗口太小,包络毛刺多,峰值定位会乱跳。我一般先用原始包络手动标出峰值位置,再反向验证平滑窗口是否合适,而不是凭感觉设一个窗口就完事了。
还有一点和MCU资源相关。有些项目为了节省RAM,把包络存储和波形存储共用一块缓冲区,结果放气还没结束,之前的包络数据就被覆盖了,等到计算阶段数据已经不全。这类问题在仿真环境里很难暴露,因为仿真时数据量是手动控制的。建议在写代码时把缓冲区大小和最大测量时长做一次乘法估算,比如200Hz采样、最多80秒测量、每个点2字节,那就是32KB,再留20%余量。别为了省内存把核心数据搞丢,这个亏我吃过一次之后就再也不敢了。
最后再分享一点我自己的体会。做血压测量方案,很多人喜欢把精力花在MCU选型和算法炫技上,但真正决定产品口碑的,往往是那些不起眼的细节:袖带的物理设计、充气阀的响应线性度、校准流程是否严格、产品在不同温湿度下的稳定性。MCU Sensor Hub把软件和硬件的边界压得很扁,好处是问题解决起来灵活,坏处是哪个环节出问题都会体现在最终数据上。所以调试时多留一点时间做整机一致性测试,比反复调算法参数更值。后续如果你想继续深入,可以在这个架构上扩展血氧、心电、体温等多生命体征融合,MCU Sensor Hub天然适合这种多传感器接入的场景。