基于STM32的示波法电子血压计设计与实现全流程解析

📅 发布时间:2026/8/31 17:18:21
基于STM32的示波法电子血压计设计与实现全流程解析
简介本资源是一套完整的基于STM32的脉搏电子血压计高分毕业设计项目面向电子信息、嵌入式系统及相关专业本科生解决课程设计、期末大作业及毕业设计中硬件驱动开发、生理信号采集与算法实现等核心实践难题。压缩包共161个文件含35个C源码主控逻辑与传感器驱动、34个H头文件外设配置与函数声明、22个编译中间文件.d、21个调试符号文件.crf及Keil工程文件uvproj、uvopt等总大小仅2.22MB结构规范、模块清晰涵盖ADC采样、FFT脉搏分析、袖带加压控制、OLED人机交互等完整功能链。已有182人学习下载项目经实机严格调试代码全程中文注释含系统初始化、血压计算模型、数据存储与显示等关键模块可直接部署运行无需额外适配特别适合嵌入式初学者快速掌握STM32外设协同开发与医疗电子系统集成方法。 做毕业设计选嵌入式方向最容易“出彩但不作死”的题目其实不是追热门的人工智能也不是看起来复杂的四轴无人机而是一台踏踏实实能做出来、能测出真实数据的医用小设备——基于STM32的脉搏电子血压计。这项目麻雀虽小五脏俱全压力传感器、信号调理电路、ADC采样、数字滤波、症状识别算法、气泵阀控制、人机交互一个不落。STM32在这类项目里几乎是标配网上相关源码也确实不少但很多同学下载下来根本跑不通或者跑通了测出来的数据完全没法看。今天就把我从整体架构到信号处理算法再到调试阶段踩过的坑完整捋一遍。这篇东西既适合正在准备毕设答辩的在校生也适合想低成本入门嵌入式医疗设备开发的工程师参考。1. 这个项目到底在做什么一条完整测压链路的设计思路1.1 示波法测血压的原理以及为什么选它电子血压计的核心不是“测血压”而是“通过袖带压力变化反推血压”。目前主流方案有两种听诊法柯氏音法和示波法振荡法。听诊法在临床上被当作金标准但它是靠人耳分辨袖带放气过程中血流冲击血管壁产生的“柯氏音”来判定收缩压和舒张压。难点在于需要拾音传感器、需要精确找到第一声和最后一声音算法上极度依赖特征检测做不好就容易误判。毕设里做这个方案风险不小。示波法的思路完全不同袖带在放气过程中内部压力不仅会缓慢下降还会叠加一个随心跳搏动的小信号。这个“脉搏波”的幅度会随着袖带压力变化走一条先增后减的曲线。当袖带压力高到完全压闭血管时脉搏波幅值几乎为零压力逐渐降低时血流冲击血管壁的力度增大脉搏波幅度上升当袖带压力正好等于平均动脉压时血管壁处于最“松弛”状态脉搏波幅度达到峰值压力继续下降后血管完全开放脉搏波幅度减小并趋于稳定。通过分析脉搏波包络线可以找出三个关键点包络峰值对应的压力是平均动脉压峰值之前幅度上升到最大值的50%左右对应的压力是收缩压峰值之后幅度下降到最大值的70%左右对应的压力是舒张压。这个算法看似简单但做出来之后我最大的感受是它不需要高精度拾音传感器不需要复杂的时频分析只要压力传感器线性度足够、ADC采样率够、放气速度控制得当就能得到稳定可读的结果。对于嵌入式新手来说这几乎是性价比最高的方案。1.2 STM32在这个项目里的角色定位STM32扮演的角色通俗讲就是“大脑加管家”。它既要控制气泵充气、电磁阀放气又要以固定频率读取压力传感器的ADC值还要在采集过程中实时处理数据最终把测量结果送到OLED屏幕上显示。为什么选STM32而不是51单片机或者Arduino答案很实在51的处理能力和外设资源太紧张做20Hz以上的AD采样加上滤波算法就已经很费劲Arduino虽然上手快但ADC精度和定时器资源无法精细控制而且教授和评委对这种“拼积木”式的开发方式通常不太认可。STM32F103系列主频72MHz、12位ADC、多个定时器、丰富的中断资源应付这种数据采集加实时处理的任务绰绰有余而且资料极为丰富遇到问题一搜就能找到答案。我用的是STM32F103C8T6这颗经典芯片成本低、引脚够用、功耗也不高。核心板加外围电路一共不到三十块钱成本对毕设预算非常友好。2. 硬件部分传感器选型与驱动电路踩坑从这里开始2.1 压力传感器的选型国产与进口的取舍血压计对压力传感器的要求集中在两方面量程和线性度。人体血压范围一般在0到200mmHg袖带充气时压力会更高一些所以我选择量程在0到300mmHg以上的传感器比较稳妥留出余量。市面上常见的方案有几种我放在一张表里对比传感器型号输出方式量程优点缺点MPX5050GP模拟电压输出0~375mmHg集成度高、线性度好、经典方案价格略高、体积稍大XGZP6847I2C/模拟输出可选0~300mmHg国产、便宜、容易买到一致性一般需要标定血压计专用传感器模块模拟电压输出0~300mmHg厂家已校准、直接可用成本较高资料少我最后选了MPX5050GP原因是它的输出电压范围是0.2V到4.7V对应0到375mmHg线性误差在全量程范围内不超过2.5%而且自带温度补偿。这个传感器的原理是内部集成了一个压阻式压力桥和放大电路外部供电5V即可输出阻抗较低可以直接驱动ADC输入引脚。实际画板子的时候有个小经验压力传感器的气管接口方向和PCB布局方向一定要提前规划好不然装进外壳之后气嘴方向和袖带气管对不上就得重新飞线很狼狈。2.2 气泵、电磁阀、电源容易被忽视的“外围设备”很多人把注意力放在传感器和单片机上结果三个月后卡在气泵上。这个项目里气泵和电磁阀才是真正的“耗材级”部件选型不当直接导致整机测量失败。气泵负责给袖带充气。我用的是一种微型隔膜泵额定电压5V最大输出气压能到300mmHg以上。启动电流比较大能达到400mA左右所以不能用STM32的GPIO直接驱动必须通过三极管或MOS管扩流。我用的方案是NPN三极管2N2222加续流二极管配合一个PWM通道控制充气速度。电磁阀负责放气。常见的有两种两通开关阀和比例阀。开关阀只有“开”和“关”两种状态控制简单但放气速度没法精确调节比例阀可以通过PWM占空比控制开度从而控制放气速率但价格贵一些。我一开始图便宜用了开关阀结果放气速度太快一个心跳周期内压力降幅太大包络线采样点稀疏到无法正确找到峰值。后来换成比例阀配合PWM慢慢放气数据才稳定下来。电源树也要引起重视。整个系统里有数字电路STM32、模拟电路传感器放大、感性负载气泵、电磁阀如果不做隔离气泵启动瞬间会把电源电压拉低导致模拟电路输出抖动。我的做法是主电源用两节18650锂电池串联经过降压模块稳定到5V再用AMS1117把5V降到3.3V给STM32供电。模拟部分和数字部分的地线在PCB上单点汇合避免形成地环路。2.3 信号调理电路传感器的微弱信号如何进ADC压力传感器输出的模拟电压虽然已经是放大后的但还是要经过一级低通滤波才能送入STM32的ADC。原因是传感器输出中包含了高频噪声直接进ADC会导致采样值跳动明显。我用了一阶RC低通滤波R取1kΩC取0.1μF截至频率约1.6kHz。这个频率远高于脉搏波频率正常人心率范围是0.5Hz到3Hz所以对有用信号完全没有影响但对高频毛刺的抑制非常明显。如果想做得更讲究可以加一级由运算放大器构成的二阶低通滤波器比如Butterworth结构截至频率设置在20Hz左右。ADC参考电压也很关键。STM32内部有VREF引脚如果直接用3.3V电源做参考电压电源纹波会被直接引入到转换结果中。我使用了一个高精度基准电压源芯片REF3033把3.3V参考电压做得干干净净。这一改动效果非常显著ADC的跳动范围直接从几十个LSB降到了两三个LSB。ADC配置方面我使用定时器触发ADC采样频率设置为200Hz也就是每5ms采一次。这个频率经过实际测试既能捕捉到脉搏波的细节形状又不会让CPU忙于处理中断。采样使用了DMA方式ADC转换完成的数据自动搬运到内存数组中不占CPU时间。这样主循环可以专心处理控制逻辑和算法运算。3. 软件实现从ADC采集到血压算法全流程3.1 程序整体架构与状态机设计嵌入式程序最忌讳把所有逻辑堆在一个大while循环里血压计程序尤其如此。我用一个有限状态机来组织整个测量流程状态之间的切换非常清晰。状态定义如下IDLE空闲等待启动按键此时气泵和电磁阀都关闭INFLATE充气启动气泵持续检测袖带压力升压到预设值后停止MEASURE测量关闭气泵打开比例阀控制放气速度同步记录压力和脉搏波FINISH结束完成测量计算并显示结果快速放气ERROR错误检测到超时或异常压力安全放气后回到空闲状态状态机的好处在于每个状态内的代码职责清晰后续加功能比如存储多组记录、蓝牙上传数据时不会牵一发动全身。而且答辩的时候老师问起代码结构状态机这个思路本身就是评分亮点。充气预设值是动态计算的。我设定默认目标压力为180mmHg但在充气过程中会实时检测脉搏波是否开始出现。如果压力还没到180mmHg就已经出现明显的脉搏波说明用户血压可能较低可以提前停止充气避免袖带过度压迫用户手臂。这是从商用血压计上学到的策略虽然不是所有电子血压计都这么做但确实能提升使用体验。3.2 数字滤波与脉搏波提取ADC采到的原始数据是一个一维序列里面混合了两种成分一条缓慢下降的基线也就是袖带压力本身还有一条叠加在基线上的波动也就是脉搏波。要把这两者分离我用的是“低通滤波加减法”的思路简单有效。第一步用滑动平均滤波对原始ADC序列做平滑处理窗口大小设为5个点对应25ms用来去除随机噪声。第二步再用一阶低通数字滤波器提取基线滤波系数a取0.2这样基线跟随比较快能实时反映袖带压力变化。第三步原始信号减去基线信号得到的就是包含脉搏波的交流分量。脉搏波虽然出来了里面还是混着一些呼吸引起的慢波和肌肉抖动的干扰。算血压之前还需要再做一次带通滤波。我用了一个简单的二阶IIR带通滤波器通带设置为0.5Hz到8Hz。下限滤掉呼吸干扰上限滤掉高频肌肉伪差。说到这里必须提醒一下IIR滤波器的系数计算对新手来说有点门槛别自己硬推导直接用MATLAB的fdatool或者在线滤波器设计工具生成系数。我当年直接在MATLAB里设计好系数然后把它填入C语言数组里省了不少时间。注意浮点运算在STM32F103上虽然能跑但速度慢而且占用Flash很大。我的做法是先用浮点算好系数再把整个滤波器实现改为定点化牺牲一点动态范围换取运行速度。3.3 示波法算法的具体实现与参数标定脉搏波提取出来之后接下来的工作就是找包络线。我在代码里维护了一个结构体数组每个元素包含一个压力值和对应的脉搏波幅度。具体实现是对每个放气阶段的脉搏波信号取极值把相邻峰值的差值作为该压力点的脉搏波幅度。关键算法代码如下这个函数直接完成了从压力数组和幅度数组到收缩压、舒张压的映射// 示波法核心算法寻找包络峰值并计算收缩压与舒张压 // pressure[]: 袖带压力数据单位mmHg // amplitude[]: 对应压力点的脉搏波幅度 // count: 数据点数量 // sbp: 输出收缩压 // dbp: 输出舒张压 uint8_t oscillometric_alg(uint16_t *pressure, uint16_t *amplitude, uint16_t count, uint16_t *sbp, uint16_t *dbp) { uint16_t max_idx 0; for (uint16_t i 1; i count; i) { if (amplitude[i] amplitude[max_idx]) { max_idx i; } } // 平均压直接取包络峰值对应压力 uint16_t map_pressure pressure[max_idx]; // 收缩压从峰值往前找幅度首次降到峰值50%的位置 uint16_t sbp_thr amplitude[max_idx] / 2; uint16_t sbp_idx 0; for (int i max_idx; i 0; i--) { if (amplitude[i] sbp_thr) { sbp_idx i; break; } } // 舒张压从峰值往后找幅度首次降到峰值70%的位置 uint16_t dbp_thr amplitude[max_idx] * 7 / 10; uint16_t dbp_idx 0; for (uint16_t i max_idx; i count; i) { if (amplitude[i] dbp_thr) { dbp_idx i; break; } } *sbp pressure[sbp_idx]; *dbp pressure[dbp_idx]; return 0; }这段代码隐藏了一个细节阈值系数0.5和0.7不是随便写的。它们对应的是商用血压计中最常用的固定比例系数但不同人群的血压特征不一样比如老年人血管弹性较差包络比阈值应该适当调整。我在实际调试中发现0.5和0.7的默认值在20到30岁的测试者身上表现良好但对中老年测试者收缩压阈值取0.45更准确。标定的方法是用一台水银血压计或商用电子血压计作为参照分别测量同一人多个时间点的血压记录自己的算法输出和参照输出的差值然后做线性回归修正阈值参数。毕设论文里如果能把这个标定过程写进去内容的含金量会立刻不一样。算法还有一个边界情况要处理如果放气过快包络线峰值附近的采样点太少有可能峰值被漏掉或者位置偏移。所以我在算法前会做一次插值处理用三次样条把脉搏波幅度序列插值成两倍密度的数组这样峰值定位的精度就有保障了。4. 调试日记我在这个项目里踩过的坑与排查思路4.1 ADC数值飘得离谱先检查电源和地第一次把硬件焊好上电的时候我遇到的情况是传感器静止不动ADC读数却在500到1200之间大幅跳动。当时第一反应是传感器坏了后来用万用表量了一下传感器输出引脚发现模拟电压确实也在跳但幅度没有ADC读数那么夸张。排查了一圈问题出在两个地方。第一个是电源我用USB供电USB的5V经过AMS1117降到3.3V但AMS1117后面没有加足够大的滤波电容。气泵不工作时还好气泵一转电流骤增电源上就会叠加一个很大的纹波。解决方案是在3.3V和GND之间加了一个470μF的电解电容和一个0.1μF的陶瓷电容纹波立刻降下来了。第二个是参考电压直接用VDD做VREF芯片内部没有隔离电源纹波直接进入ADC。解决方案是换用REF3033基准源这个改动效果立竿见影。所以调试ADC类的项目先别急着调软件拿示波器看看电源轨的纹波、看看传感器输出端是否有毛刺往往能省下几个小时的时间。4.2 脉搏波时有时无问题可能出在袖带和放大软件写好之后第一次完整测量发现脉搏波提取结果非常不稳定有时候能看到明显的脉搏波有时候整段数据清一色都是直线。我仔细检查了代码逻辑排除了算法问题最后发现是袖带的问题。电子血压计袖带和普通医用袖带略有区别里面其实是一根连接气管的橡胶气囊。气囊通过气管与压力传感器相连袖带绑在手臂上充气后气囊内的空气压力变化会通过气管传到传感器。如果袖带绑得太松气囊和手臂之间存在空隙血管搏动就无法有效地传递到气囊内部导致传感器只能测到气压而测不到搏动。解决方案也简单绑袖带时确保气囊中心正好压在肱动脉上方松紧程度以“能插进一根手指”为准。这个经验需要在操作指南里写清楚因为测试者的使用方式直接影响测量结果。另外如果传感器输出经过放大电路之后脉搏波幅度仍然很小比如只有几十毫伏也不要急着改放大倍数。先用示波器确认传感器直接输出端有没有搏动信号如果有说明放大电路的地线布局有问题如果没有说明传感器连接的气路有漏气或者袖带放置不正确。4.3 测量结果与商用血压计对比偏差大参数怎么调有一段时间我的设备测出来的收缩压总是比商用血压计高15到20mmHg。这种整体偏差不是随机误差而是系统误差基本可以确定是算法参数的偏差。按照前面讲的方法我找了5个测试者分别用我的设备和商用设备测了30组数据然后跑了一次简单的统计分析。发现如果收缩压阈值从0.5降到0.45偏差明显缩小到±5mmHg以内。舒张压阈值从0.7改成0.72后也获得一定改善。调参的过程不复杂但需要耐心。我写了一个上位机辅助脚本通过串口把每次测量的压力序列和脉搏波序列导出来在Python里离线分析这样能快速迭代算法参数而不用每次烧录代码重新测一遍。如果你用的是Keil开发环境用串口打印原始数据再放到脚本里分析完全可以复刻这个流程。还有一个容易忽略的问题测量时用户的手臂位置。如果手臂与心脏不在同一高度水银血压计的读数本身就会出现偏差电子血压计也是同理。我最初测试时手放在桌上和手举高贴身读数差异能达到10mmHg以上。确保所有对比测试的姿势一致数据的可比性才成立。这里列出我在调试后期建立的一个排查速查表方便对照问题现象可能原因检查方法解决措施ADC数值跳动大电源纹波VREF不稳示波器查看3.3V纹波加大滤波电容改用基准源脉搏波幅度小袖带漏气或位置不对检查气路是否密封调整袖带更换气管脉搏波不定期消失放气速度过快检查放气阀控制波形改用PWM控制比例阀收缩压整体偏高算法阈值不合适与标准设备对比记录降低收缩压阈值测量结果不稳定测量姿势不一致规范测量动作固定姿势连续测3次取平均充气超时气泵老化或气管漏气听气泵声音检测压力上升速度更换气泵重新连接气路5. 毕设资料整理清单让这份代码真正成为你的加分项5.1 源码工程应该怎么组织很多同学拿到项目直接CtrlC、CtrlV到头来自己都没读过一遍代码这种方式即使通过了查重也过不了答辩。真正的做法是理解每一段关键代码的用途然后重构工程目录。我建议的工程目录结构如下Project/ ├── Core/ │ ├── Inc/ // 头文件 │ └── Src/ // 主函数、中断、系统时钟配置 ├── Hardware/ │ ├── Sensor.c // 压力传感器驱动 │ ├── Pump.c // 气泵控制 │ ├── Valve.c // 电磁阀控制 │ ├── OLED.c // 显示屏驱动 │ └── Key.c // 按键扫描 ├── Algorithm/ │ ├── Filter.c // 数字滤波实现 │ └── BP_Calc.c // 示波法血压算法 ├── Data/ │ └── history.c // 数据存储 └── main.c代码风格上每个函数前面都写了简洁的函数说明和输入输出参数说明全局变量尽最大努力减少模块间的接口用函数封装。这样做不仅答辩时加分后续扩展蓝牙模块或者增加WiFi传输时也会方便很多。5.2 从原理图到论文一份完整毕设资料的构成一个能拿高分的毕设交付的绝不仅仅是能跑的代码。完整的资料包至少包含六项源码工程、原理图、PCB文件、毕业设计说明书、演示视频、答辩PPT。原理图我用的Altium Designer画的但如果你更熟悉立创EDA也可以关键是所有元器件都标注清楚封装和数值方便别人照着购买和焊接。PCB走线要特别注意模拟信号走线要远离气泵和电磁阀驱动的功率走线晶振下方不要走任何信号线。毕业设计说明书的结构我建议这样组织第一章绪论写国内外电子血压计研究现状第二章讲示波法测量原理和系统总体设计第三章写硬件电路设计包括传感器选型和驱动电路第四章写软件设计包括滤波算法和核心血压判定算法第五章写系统测试与误差分析。论文里贴几张示波器抓到的脉搏波图和OLED显示的测量结果图很有说服力。答辩时老师最喜欢问的几个问题包括为什么选示波法不选听诊法压力传感器量程为什么选这个滤波器的截止频率是怎么确定的算法中0.5和0.7比例系数为什么是这个值这些问题我在正文里都已经给出了答案把原理吃透答辩时就能稳住。5.3 演示环节的准备让评委两分钟看懂你的项目毕设答辩的演示环节时间有限我的做法是提前录一段两分钟左右的视频把袖带绑在测试者手臂上按下开始键能看到OLED屏上显示“充气中”然后是一段实时压力变化曲线最后显示收缩压、舒张压和心率。同时用一台商用血压计同步测量做一次直观对比。这个对比的数据会直接展示误差范围比任何口头说明都有说服力。如果现场条件允许也可以让评委实际操作一次。不过要注意血压计是医疗设备需要提前说明使用禁忌和注意事项并且征得对方同意后再操作。写在最后关于这个项目的一点个人体会做完这个项目之后一个明显的感受是嵌入式医疗设备真正的技术含量并不在硬件本身而在信号处理与算法参数取舍这些“看不见”的地方。血压计看起来简单但要做到准确、稳定、可重复需要下不少功夫。另外想多说一句做毕设千万不要只做个“代码搬运工”。把示波法原理彻底弄懂、亲手跑过一遍数据、体验过从波形异常到找到原因的过程这些经历才是毕设真正留给你的东西。代码可能过两年就忘了但排查问题的思路和对一个完整闭环系统的掌控感会伴随你进入下一阶段的工作或学习。以后再做类似的设备哪怕是心率计、血氧仪你会发现核心的思路是相通的。本文还有配套的精品资源点击获取