简介:这份资料面向嵌入式开发初学者与医疗电子爱好者,系统讲解基于单片机的智能电子血压计从原理到落地的完整设计路径,帮助读者理解示波法测量血压的技术实现。压缩包共303个文件、约6.74MB,以C源码、头文件与编译中间文件为主,辅以汇编启动代码、hex烧录文件、工程配置及一份配套APP安装包,覆盖固件开发与手机端联调所需素材。内容围绕设计概要、工作原理说明、硬件选型(压力传感器、气泵气阀、LCD与蓝牙模块)、固件源码解析及APP数据管理功能展开,读者可据此掌握传感器数据采集、血压计算算法与蓝牙通信协议的编写思路。目前已有987人学习,适合作为课程设计或产品原型的参考蓝本。
1. 从一次“测不准”的返工说起:智能电子血压计到底要解决什么
去年帮一个做医疗器械的团队看他们的血压计样机,硬件焊接没问题、屏幕能亮、气泵能打气,但连续测同一只手臂,三次收缩压能差出 18 mmHg。这种“玄学”偏差在血压计项目里几乎是必经的翻车点,而它恰恰说明一件事:电子血压计不是把传感器、气泵、单片机拼起来就能跑的东西,它是一套围绕示波法测量原理构建的完整信号链工程。这套智能电子血压计设计资料要解决的,正是从压力信号采集、袖带充放气控制、脉搏波包络提取到结果计算与显示的全链路落地问题,适合正在做单片机课程设计、生物医学工程毕设,或者要交付一台可演示样机的从业者参考。关键词“单片机 电子血压计”背后,真正难的不是选哪颗芯片,而是怎么让一套低成本硬件稳定复现出可信的血压读数。
2. 需求与选型:为什么主控、传感器、气路要这样配
2.1 功能需求拆解成可验收的条目
动手画原理图之前,我一般会先把需求写成能打勾的清单,否则做到一半就会发现“能测”和“测得准”是两码事。这套方案的功能边界通常这样划定:自动充气到预设压力(一般 180~200 mmHg 区间可调)、按设定速率放气、在放气过程中同步采集压力与脉搏波、计算收缩压/舒张压/脉率、LCD 或 OLED 显示结果、按键完成测量与历史查看、超压或异常时自动泄气保护。把这些条目写成表格,验收时逐条对照,比口头说“功能都做了”靠谱得多。
| 需求项 | 指标要求 | 验收方式 |
|---|---|---|
| 压力测量范围 | 0~300 mmHg | 标准压力计对比 |
| 压力分辨率 | 不低于 1 mmHg | 静态加压读数 |
| 充气目标压力 | 180~200 mmHg 可设 | 观察实际停泵点 |
| 放气速率 | 约 3~5 mmHg/s | 秒表计时换算 |
| 心率测量范围 | 40~180 次/分 | 与指脉对比 |
| 超压保护 | 超过 300 mmHg 自动泄气 | 人为触发测试 |
| 单次测量耗时 | 40 秒以内 | 全程计时 |
这张表的价值在于,它把“智能”两个字落到了具体数字上。很多同学方案书写得漂亮,一问放气速率多少就卡壳,答辩时这是硬伤。
2.2 主控与传感器的选型逻辑
主控通常选 STC89C52 或 STM32F103 这一类。前者成本低、资料多,适合课设演示;后者带 12 位 ADC、定时器资源足,做包络算法更从容。选型的核心不是性能越高越好,而是看 ADC 位数和定时器精度够不够支撑脉搏波采样——脉搏波信号幅度只有压力信号的百分之几,8 位 ADC 在 200 mmHg 量程下分辨率约 0.8 mmHg,勉强够用但余量小,12 位就舒服很多。
压力传感器一般用内置电桥的袖带压力传感器模块,输出差分毫伏信号,需要仪表放大器或专用前端放大后再进 ADC。气泵选微型直流气泵,配合两位三通电磁阀完成充气、保压、放气三态切换。这里有个血泪经验:气泵和阀的响应速度直接决定放气曲线是否平滑,阀口径太小会导致放气速率不稳,包络提取时噪声明显增大。
2.3 信号链的整体走向
整条链路可以这样描述:袖带压力经传感器转换为差分电压,前级放大与滤波后送入单片机 ADC;单片机通过 PWM 加驱动管控制气泵与电磁阀;放气阶段以固定采样率记录压力序列,软件从中分离出缓慢下降的静压趋势和叠加其上的脉搏波振荡;对振荡幅度做包络拟合,找到包络最大值对应压力,再按经验系数推算收缩压与舒张压。这条链路里任何一环引入的噪声,最后都会变成读数偏差,所以滤波和采样时序的设计不能省。
3. 硬件与信号调理:把微弱脉搏波从压力基线里“捞”出来
3.1 前端放大与滤波电路的设计要点
传感器输出的差分信号幅度小、共模干扰大,通常用仪表放大器做第一级,增益设在 100~200 倍之间,把毫伏级信号抬到 ADC 能分辨的范围。放大之后必须跟一个低通滤波,截止频率设在 5~10 Hz 左右——脉搏波主频在 1~2 Hz,但充放气过程中的机械振动和工频干扰会混进来,滤不干净后面算法再聪明也白搭。
// 采样与软件滤波示例(STM32 风格伪代码,逻辑通用) #define SAMPLE_N 8 uint16_t adc_raw[SAMPLE_N]; uint16_t read_pressure_filtered(void) { uint32_t sum = 0; for (int i = 0; i < SAMPLE_N; i++) { adc_raw[i] = ADC_Read(PRESSURE_CH); // 读取压力通道原始值 sum += adc_raw[i]; } // 滑动平均抑制随机噪声,SAMPLE_N 越大越平滑但响应变慢 return (uint16_t)(sum / SAMPLE_N); }这段代码看着简单,但采样窗口长度是有讲究的:窗口太短滤波效果差,太长会把脉搏波的细节抹平。我一般按采样率来定,若放气阶段采样率取 100 Hz,8 点平均相当于 80 ms 窗口,既能压住高频噪声,又不会明显滞后于脉搏波变化。参数改动的判断依据是:如果包络曲线毛刺多,加大窗口;如果包络峰值位置漂移,减小窗口。
3.2 气路控制与超压保护
气路是电子血压计里最容易被低估的部分。充气阶段气泵全速运行,达到目标压力后停泵并进入保压,随后电磁阀按小占空比间歇开启实现缓慢放气。超压保护不能只靠软件判断,通常再加一路硬件比较器,压力超过阈值直接切断气泵驱动并打开泄气阀,这是安全底线。
// 充气与放气状态机核心逻辑 typedef enum { IDLE, INFLATE, HOLD, DEFLATE, DONE } bp_state_t; void bp_control_step(void) { uint16_t p = read_pressure_filtered(); switch (state) { case INFLATE: Pump_On(); if (p >= TARGET_PRESSURE) { // 达到目标压力 Pump_Off(); state = HOLD; hold_tick = 0; } break; case HOLD: if (++hold_tick > HOLD_MS) state = DEFLATE; // 保压稳定后放气 break; case DEFLATE: Valve_Pulse(DEFLATE_DUTY); // 间歇开阀,控制放气速率 record_sample(p); // 记录压力序列供包络分析 if (p <= STOP_PRESSURE) state = DONE; break; default: break; } }状态机的意义在于把充放气过程拆成互斥阶段,避免“边充边放”这种低级错误。DEFLATE_DUTY这个占空比是调放气速率的关键旋钮,实测偏大则放气过快、采样点稀疏,偏小则单次测量时间拉长,一般调到 3~5 mmHg/s 对应的值。STOP_PRESSURE通常设在 40~50 mmHg,低于它再采也没有有效包络信息。
3.3 电源与抗干扰
模拟前端和数字部分共用电源时,气泵启停造成的电压跌落会直接串进压力信号。常规做法是模拟部分单独经 LC 或磁珠隔离供电,ADC 参考电压加去耦电容,气泵驱动回路与信号地分开走线、单点汇合。这些细节在原理图上不起眼,但样机测不准时,十有八九要从这里查起。
4. 算法与软件架构:包络拟合才是读数的“黑匣子”
4.1 脉搏波包络的提取流程
放气过程中记录的压力序列,本质是“缓慢下降的直流基线 + 叠加的振荡波”。软件先做趋势分离,把基线去掉得到振荡分量,再对振荡分量做峰值检测,得到每个心动周期对应的振幅,这些振幅随袖带压力变化形成一条钟形包络曲线。包络最高点对应的袖带压力记为平均压,收缩压和舒张压则按包络幅度下降到最大值某一比例时对应的压力来判定,这个比例系数就是各家算法的经验参数,通常收缩压取 0.5~0.6、舒张压取 0.7~0.8 区间,需要结合实测标定。
// 包络峰值检测与比例判定的简化实现 #define ENV_MAX 128 uint16_t env_amp[ENV_MAX]; // 各压力点对应的振荡幅度 uint16_t env_prs[ENV_MAX]; // 对应袖带压力 int env_cnt = 0; void build_envelope(void) { // 对振荡分量做峰值检测,每检测到一个峰记录幅度与当前压力 for (int i = 1; i < sample_cnt - 1; i++) { if (osc[i] > osc[i-1] && osc[i] > osc[i+1] && env_cnt < ENV_MAX) { env_amp[env_cnt] = osc[i]; env_prs[env_cnt] = base_pressure[i]; env_cnt++; } } } uint16_t calc_systolic(void) { uint16_t max_amp = 0; int max_idx = 0; for (int i = 0; i < env_cnt; i++) if (env_amp[i] > max_amp) { max_amp = env_amp[i]; max_idx = i; } // 从包络峰值向高压侧找幅度降到 55% 的点 for (int i = max_idx; i > 0; i--) if (env_amp[i] < max_amp * 55 / 100) return env_prs[i]; return env_prs[0]; }这段代码是算法骨架,真正决定精度的是那几个百分比系数和峰值检测的阈值。系数不能拍脑袋定,通常的做法是拿标准血压模拟器或对照设备做一批样本,反推使误差最小的系数。峰值检测也要设最小间隔,防止把噪声当成脉搏波。
4.2 软件分层与主循环组织
软件按驱动层、算法层、应用层分开写,驱动层管 ADC、定时器、气泵阀、显示;算法层只处理数据,不碰硬件;应用层是状态机和界面逻辑。这样分层的好处是算法可以脱离硬件在 PC 上先用录好的数据验证,调参效率高很多。主循环里用定时器节拍驱动采样和状态机,避免delay阻塞导致采样间隔不均——采样间隔一乱,包络形状就失真。
4.3 显示、存储与交互
结果显示一般用 12864 或 OLED,同屏给出收缩压、舒张压、脉率,历史记录存 EEPROM 或 Flash,按键做短按测量、长按查看历史。交互上有个小细节:测量过程中要有明确的“正在充气/放气”提示,否则用户以为死机去拔袖带,数据全废。存储结构建议按固定长度记录,带校验字节,掉电不至于读出乱码。
5. 避坑与排查:样机测不准时先查这几处
5.1 读数重复性差、三次差十几 mmHg
现象是同一手臂连续测量结果离散大。原因多半在放气速率不稳或采样时序抖动,包络形状每次都不一样。解决办法是先把放气占空比固定、用示波器确认阀开启时间一致,再检查采样是否被显示刷新等任务打断,必要时把采样放进定时器中断。
5.2 包络曲线毛刺多、峰值找不到
现象是振荡分量噪声大,峰值检测误判。原因通常是前端滤波不足或气泵振动耦合进信号。解决上先加软件滑动平均,再检查传感器与气路的机械连接是否松动,必要时在放气阶段暂停其他外设降低干扰。
5.3 充气到目标压力后压力持续上升
现象是停泵后读数还在涨。原因多为电磁阀关不严或气路漏气方向判断错。排查时单独给阀通电测试密封性,检查管路接头,别一上来就怀疑软件。
5.4 超压保护不动作
现象是人为加压超过阈值气泵仍在转。原因可能是硬件比较器阈值设错或驱动逻辑与软件状态机冲突。解决上先单独验证比较器输出,再确认保护回路能独立切断驱动,不能只依赖主程序判断。
5.5 显示正常但脉率明显偏差
现象是血压值尚可、脉率对不上。原因常是峰值检测把干扰当心跳,或采样率不足以覆盖高心率。解决上给峰值检测加最小间隔约束,并核对采样率是否满足最高心率两倍以上。
6. 验收与答辩:用一组对照数据把方案讲圆
验收这件事,我一般建议提前一周就开始准备,而不是答辩前一晚临时抱佛脚。核心思路是:不要只说“我做出来了”,而要拿出一组能自证的数据。具体做法是找一台经过校准的对照血压计或血压模拟器,对同一受试者或同一模拟压力做 5~8 组平行测量,把本机读数与对照值列成表,算出每组的偏差和平均偏差。答辩时把这组数据往投影上一放,比任何形容词都有说服力。
| 测试组 | 对照收缩压 | 本机收缩压 | 偏差 | 对照舒张压 | 本机舒张压 | 偏差 |
|---|---|---|---|---|---|---|
| 1 | 118 | 121 | +3 | 76 | 74 | -2 |
| 2 | 120 | 118 | -2 | 78 | 80 | +2 |
| 3 | 116 | 119 | +3 | 75 | 73 | -2 |
| 4 | 122 | 120 | -2 | 79 | 81 | +2 |
偏差控制在 ±5 mmHg 以内,对课设和毕设级别的样机已经是能拿得出手的水平。答辩陈述按“需求—方案—实现—验证”四段走,重点讲清楚三件事:为什么这样选传感器和主控、包络算法里那几个系数怎么定的、超压保护如何独立生效。老师最爱追问的往往是“你这个系数凭什么取 55%”,这时候把标定过程和对照数据讲出来,问题就化解了。
还有个小技巧:现场演示时先测一次完整的,把充气、放气、出结果的全过程走完,再展示历史记录和超压保护触发,节奏控制在三分钟内。演示前务必给袖带留出余量、检查气路接头,我见过太多现场因为一个接头松了导致全程重来的情况。从那以后我每次交付样机前,都强制走一遍“空载充气—保压—放气—超压触发”的完整自检,再上演示台。希望这套结构和验收思路能帮到你,把这份智能电子血压计设计资料真正用成一份能交付、能答辩的完整方案。
本文还有配套的精品资源,点击获取