简介:这是一份题为《基于单片机的脉搏测量仪》的毕业设计文档,内容完整,共1个doc文件,压缩包大小2.12MB,适合电子、通信及嵌入式方向的毕业生和初学者作为课程设计或毕业设计参考。设计以AT89C51单片机为核心,结合红外发光二极管与光敏三极管构成光电传感器,通过定时器计算时间和脉冲累加得到脉搏次数,并在显示模块上实时输出。文档从选题背景、系统硬件组成、工作原理、软硬件设计,到系统测试与性能分析均有阐述,目录结构清晰,并给出了完整的摘要、关键词和论文框架。已有82人学习下载,对于希望了解51单片机应用、光电检测及脉搏测量实现流程的读者,是一份可用于快速搭建方案、梳理设计思路和撰写论文的有价值参考资料。 又是单片机课设季,后台收到好几个同学在问“基于单片机的脉搏测量仪”这类题目怎么做。这题目在毕业设计和课程设计里确实算常青树了,既能覆盖模拟电路前端处理,又能把ADC采集、数字滤波、算法统计、外设驱动这些单片机核心技能串起来,工作量可观但难度可控,老师也爱看这种“软硬结合”的完整项目。
那这篇就把我当时做这个题目的完整思路、硬件选型、代码框架和踩坑记录整理出来,从原理到实现一次讲透,照着做基本都能跑通。
1. 整体方案设计与核心思路拆解
1.1 脉搏测量的两种主流技术路线
做脉搏测量仪,第一步不是选单片机,而是先定“怎么测脉搏”。目前常见的方案有两种,区别很大。
一种是压电式方案,用的是压电薄膜传感器,贴在手腕桡动脉处,靠脉搏搏动的机械压力产生电荷信号。这种方案的优点是抗环境光干扰强,戴在手腕上更像“手表”,体验好,但缺点也很明显:信号幅度极小(毫伏甚至微伏级),对运放和前级电路要求非常高,而且对传感器贴放位置极其敏感,稍微挪一下位置波形就没了。学生做课设用这个方案,很容易在“信号调理”这个环节耗掉大量时间。
另一种是光电式容积脉搏波方案(PPG),利用的是血液对光的吸收特性。发光管发出特定波长的光照射皮肤,光敏管接收透射或反射后的光。心脏收缩时血管血量增加、吸光量增大,光敏管接收到的光强就变弱;心脏舒张时反之,所以光敏管输出的电信号就呈现与心跳同步的周期性波动。
我做这个题目选的是光电式PPG方案,具体用的是透射式红外对管。原因很直接:电路相对简单、信号幅度大(几十到几百毫伏)、传感器固定方便(夹耳垂或手指),非常适合课程设计和毕业设计的时间节奏。如果非要做腕表式体验,那再考虑压电方案,但那基本是另一个量级的项目了。
1.2 系统整体架构与工作流程
整个系统的工作流程可以从信号流的角度来理解:传感器采集微弱生理信号,经模拟电路放大滤波后,送入单片机进行A/D转换和数字处理,最后计算心率并显示,超限时报警。
整套系统拆成四个功能单元来看:
| 功能单元 | 核心器件 | 作用 |
|---|---|---|
| 信号采集 | 红外发射管+光敏接收管 | 将脉搏搏动转换为电信号 |
| 信号调理 | 前置放大电路+滤波电路+主放大电路 | 将微弱信号放大到ADC可采集范围并滤除噪声 |
| 数据处理 | 单片机(STC89C52)内部ADC+算法 | 数字滤波、峰值检测、心率计算 |
| 人机交互 | LCD1602显示+按键+蜂鸣器 | 显示心率数值与报警提示 |
这里有个关键设计决策需要说明:为什么前级不直接用运放做很高的放大倍数?因为脉搏信号的噪声主要来自50Hz工频干扰、日光灯等环境光干扰以及手指抖动产生的低频干扰。如果前级放大倍数直接拉到1000倍,这些噪声也会被同比例放大,信号直接饱和削顶,什么都测不到。
正确的做法是多级放大加上中间滤波:小倍数前置放大,带通滤波滤除干扰,再二级放大到合适幅度。这个顺序很重要,先滤波再放大,比先放大再滤波的效果好得多。
2. 硬件电路细节与元器件选型要点
2.1 传感器选型与前端电路设计
传感器我选用的是红外对管ST188,这是一颗反射式红外传感器,发射管和接收管封装在一起,靠近手指时红外光经皮肤组织反射后被接收管采集。选它的主要原因是模块化程度高、资料多、价格便宜(两三块钱),而且发射波长在900nm左右,受可见光影响小。
也有同学用透射式的方案,让手指夹在发射管和接收管之间,好处是信号更强,但需要一个固定的手指夹结构,做起来麻烦一些。反射式最大的坑是安装距离:传感器表面到皮肤的距离要控制在5mm以内,太远了反射信号急剧衰减,太近了容易压死血管造成局部缺血,反而没信号。
前端电路的核心是一个跨阻放大或简单的电阻分压加射极跟随结构。我用的方案是:接收管集电极接上拉电阻到VCC,发射极接地,脉搏引起的光变化导致光敏管等效电阻变化,从而在集电极产生变化的电压信号。这个信号只有几十毫伏级别,需要进入调理电路处理。
2.2 信号调理电路的核心参数计算
信号调理部分是整个硬件电路中技术含量最高、也是很多同学最容易做砸的地方。原理上就三件事:放大有用信号、滤掉噪声、把信号幅度调到ADC合适范围。
运放选型上,课程设计用LM358就足够,虽然它带宽窄、噪声偏大,但脉搏信号本身就是低频信号,LM358完全够用且不容易自激振荡。想做得更好可以用NE5532或OP07,但要注意供电电压和单电源工作的共模输入范围。
具体电路采用两级结构:
第一级是同相比例放大,放大倍数设为10倍左右,把几十毫伏的信号放大到几百毫伏。R1取10k,反馈电阻R2取100k,放大倍数=1+R2/R1≈11倍。这一级输出接入一个有源低通滤波器,截至频率设计在5Hz左右。为什么是5Hz?人的正常心率范围是60~100次/分,剧烈运动时可达180次/分左右,对应频率是1~3Hz。把截至频率放在5Hz可以完整保留脉搏信号,同时把50Hz工频干扰和更高频的噪声一刀切掉。低通滤波的电容电阻取值按照RC截至频率公式计算:f=1/(2πRC),取R=33k、C=1uF,算下来约4.8Hz。
第二级放大倍数设计得更大一些,用可调电位器实现增益调节,范围为20~100倍。这样总放大倍数在200~1000倍之间可调,适应不同人的皮肤厚度、手指粗细差异。这里必须用可调增益,因为不同人的手指透光性差异非常大,固定增益要么信号太弱测不到,要么信号太大削顶失真。
2.3 单片机最小系统与显示模块连接
主控我用的是STC89C52RC,价格便宜、资料多、51基础知识通用,做课设完全够用。要是想上STM32也完全可以,但要注意STM32的ADC是12位,采样的分辨率和精度会更好,对应的代码逻辑也更复杂一些,需要根据自己掌握的程度选择。
最小系统的搭建有几个容易踩的坑:复位电路用10uF电解电容加10k电阻,晶振用11.0592MHz(主要是为了串口波特率准确),电源端一定要加100nF和10uF两个去耦电容。尤其是ADC采集时,电源纹波会直接耦合进采样结果里,在示波器上看波形毛刺很多,排查半天发现是电源没处理好,非常常见。
显示模块我用LCD1602,因为它显示字符方便、代码库多、接线简单,8个数据引脚加3个控制引脚,标准接法连到P0和P2口。要注意P0口内部没有上拉电阻,接LCD时必须在外部加上拉电阻,否则显示乱码。用4位模式接法可以省4个IO口,但代码上要稍微处理一下字节拆分。
3. 软件核心算法与代码实现
3.1 ADC采样与数字滤波处理
STC89C52内部集成8路10位ADC,对我们来说够用了。配置ADC寄存器开启P1.0通道采样,采样率设为100Hz(每秒100个点),这样2Hz的脉搏信号一个周期能采到50个点,波形还原度很好。
采样率也不是越高越好,太高了数据量大,MCU处理不过来;太低了波形细节丢失,峰值检测不准。100Hz是我测试下来比较合适的折中值。
采到的原始数据直接算心率是不行的,因为信号里还有高频毛刺和基线漂移。我在软件里做了两级处理:
第一级是滑动平均滤波,每采5个点取一次平均值。这个滤波会带来一定的波形延迟,但100Hz采样率下5个点才延迟50ms,对心率计算来说可以忽略。
第二级是去基线漂移。手指按压力度变化、呼吸等都会造成信号整体上下漂移,表现为波形在零点附近缓慢游走。处理方法是计算最近100个采样点的平均值,然后让当前值减去这个平均值,相当于一个数字高通滤波器,能把低频漂移去掉,让波形稳定在零轴附近。
3.2 心率计算逻辑:从波形到数字
这是整个软件的核心,我的方法分三步:
第一步是峰值检测。对滤波后的数据做一阶差分,即计算当前点与前一个点的差值。当差分值从正变负,且当前值大于设定阈值时,判定为一次脉搏峰值。阈值不能设成固定值,因为不同人的信号强度可能差一倍以上。我采用自适应阈值:阈值为当前时间段内信号最大值的60%。这样手指放上去信号强就自动适应高阈值,信号弱就自动降低标准,实测下来适应不同人很稳定。
第二步是不应期锁定。人的心率最快也就240次/分左右,对应峰间隔至少250ms。如果检测到两次峰值间隔小于250ms,后一个峰值直接判定为干扰,不计数。这能有效防止波形抖动造成的误触发。
第三步是心率计算。记录最近4次脉搏峰值的间隔时间,取平均值后换算成每分钟心跳次数。之所以用4次间隔的平均值而不是单次间隔,是为了平滑心率显示,让数字跳动不至于太突兀,更接近医用脉搏血氧仪的效果。
核心代码框架如下:
// 峰值检测与心率计算 #define PEAK_THRESHOLD_RATIO 0.6f // 自适应阈值比例 #define REFRACTORY_PERIOD_MS 250 // 不应期,毫秒 uint16_t peak_value = 0; // 当前周期内的峰值 uint16_t peak_count = 0; // 峰值计数 void process_pulse_data(uint16_t adc_value) { // 更新当前周期最大值(用于自适应阈值) if (adc_value > peak_value) { peak_value = adc_value; } // 差分判断:当前点比前一个点小,且前一个点是局部最大值 if (adc_value < previous_value && previous_value > threshold) { uint16_t interval = get_current_interval(); // 与上次峰值的间隔 if (interval > REFRACTORY_PERIOD_MS) { peak_count++; update_heart_rate(interval); // 更新心率 } } previous_value = adc_value; }3.3 显示驱动与按键交互
LCD1602的驱动代码网上很多,关键在于时序的把握。我建议直接使用4位数据线模式,初始化时序严格按照手册要求来,不然容易出现“刚开始显示正常、过一会儿乱码”的情况——这多半是初始化时序不够规范。
显示内容分两行:第一行显示“Heart Rate:”,第二行显示数值和单位“XX BPM”。每次心率更新后,只在原来的位置重写数字部分,不要整屏刷新,否则LCD会有闪烁感。
按键功能我做了两个:一个切换工作模式(实时显示模式/历史记录模式),一个设置报警阈值。报警逻辑很简单,心率高于设定值或低于设定值时,蜂鸣器以不同频率鸣叫,高报警用高频,低报警用低频,方便区分。
4. 常见问题与排查技巧实录
4.1 示波器看得到波形,心率却显示乱跳
这个问题十有八九出在阈值设置不合理或滤波强度不够上。
我调试时遇到过一种典型情况:手指放上去,LCD上的心率显示在120到220之间剧烈跳动,但示波器上明明看到规律波形。排查后发现是波形上有一些小毛刺,幅度虽然不大,但经过差分检测后也会被误判为峰值。解决方法是提高阈值比例(从60%提到75%),以及引入“连续两个点满足条件才算峰值”的确认机制。这种方法本质上是增加了检测的“去抖动”逻辑,比单纯调阈值更有效。
另外要检查手指位置是否稳定。PPG信号的波形形态与传感器和血管的相对位置有很大关系,手指微动一下,波形幅度和形状都会变化,心率自然就不稳定。让被测者手放平稳、不要用力握紧,是最简单但最有效的改善手段。
4.2 有信号但幅度太小,调大增益后波形反而消失
这个现象比较反直觉,原因在于电路饱和。信号在前级就被放大到接近电源电压,后级再放大时波形已经削顶变形,表现出来的就是“波形消失”。
判断方法是逐级测量:用示波器分别量第一级输出和第二级输出,看哪一级开始饱和。比如第一级输出已经到4V了,那问题就出在第一级,而不是盲目调第二级电位器。
实际中还有个容易被忽视的点:LM358运放在单电源供电下,输出不能真正到0V,最低只能到几十毫伏。如果信号接近地电位,就会被“卡”住,表现为波形底部被削平。解决方法是把前级偏置到VCC/2(比如2.5V)作为虚地,让信号在2.5V上下摆动,这样正负半周都有充足的空间。
4.3 程序烧录后简单上电无反应
烧录不进去或者上电没反应,不要先怀疑程序,按顺序排查以下环节的效率最高:
第一看电源。用万用表量单片机VCC和GND之间是否有5V电压,注意部分USB转串口模块输出的电压可能不稳,最好用万用表实际测量确认。
第二看晶振。示波器探针放在晶振引脚上,看是否有振荡波形。没有波形的话,检查两个22pF负载电容是否漏焊,或者晶振本身焊接时受热过高坏了。
第三看复位电路。STC单片机在冷启动时要求RST引脚经历一个由高到低的变化过程,如果复位电路不对或者一直处于复位状态,程序永远不会执行。测一下RST引脚电压,正常工作时应该是低电平。
第四看下载电路。STC单片机下载时需要先断电再上电触发下载动作,很多新手卡在这一步。正确顺序是:点下载按钮 -> 给板子上电(如果有独立电源开关) -> 等待提示下载成功。
4.4 常见问题速查表
| 现象 | 可能原因 | 排查顺序 |
|---|---|---|
| LCD无显示/乱码 | P0口未加上拉电阻、初始化时序不对、对比度电位器没调好 | 先测VL引脚电压,再查上拉,最后核对初始化时序 |
| 波形毛刺多 | 电源纹波、手抖动、环境光干扰 | 电源端增大电容、手放稳、给传感器做遮光处理 |
| 心率值翻倍 | 阈值太低导致误检测、不应期太短 | 提高阈值比例、增加不应期时间 |
| 心率值减半 | 阈值太高漏检、波形峰值不明显 | 降低阈值、重新调节传感器位置 |
| 蜂鸣器误报警 | 干扰引起心率突变 | 在心率更新时增加平滑处理,突变超过20%不更新 |
5. 实测效果与优化扩展
整套系统搭完后实际测试,在安静环境下,手指放入传感器夹子的透射式结构(如果你选用),或者在传感器上轻按手指(反射式),LCD显示的心率数值与手机上的PPG测心率软件对比,误差基本能控制在±3次/分以内,完全满足课程设计或毕业设计的指标要求。
从功耗角度看,STC89C52全速运行加LCD背光大概在50mA左右,如果用USB供电完全没问题,想做成便携设备的话换用电池供电就需要考虑休眠模式了。STC89C52有掉电模式,可以在两次采样间隔进入休眠,但考虑到课设场景通常是USB供电,这个优化做不做看个人精力。
想做得更深入的话,有几个扩展方向:一是换成OLED显示屏,UI界面能做得更漂亮;二是加入蓝牙模块HC-05,心率数据实时传到手机App,这个在答辩时特别加分;三是从51平台升级到STM32,用内部定时器做更精确的峰值间隔计时,同时可以加FFT算法做频域分析。如果追求更低功耗,可以考虑GD32等国产ARM芯片,在低功耗模式下整个系统可以做到5mA以内。
我对这个项目的一个核心体会是:**脉搏测量仪在硬件原理上没有太深奥的东西,真正的技术难点全在信号质量的处理上。**模拟前端滤波调好了,数字算法写起来就事半功倍;前级电路毛刺一堆,后面软件再怎么处理都像“烂地基上盖楼”。所以如果你正在做这个题目,多花点时间在示波器上观察各个节点的波形变化,把每级电路的输出都量一遍,这套基本功练下来,收获远不止一个课设高分。
本文还有配套的精品资源,点击获取