简介:本资源是一套完整的基于51/52单片机的心率监测系统毕业设计实践方案,面向电子类、自动化及物联网专业本科生与课程设计/毕设初学者,解决心率实时采集、阈值报警与人机交互等典型嵌入式开发问题。压缩包共64个文件,涵盖Keil源程序工程(含C代码、hex、uvproj等)、Proteus仿真工程(含dsn、mp4操作视频、JPG/PDF仿真图)、电路原理图(sch、JPG、PDF)、元器件清单(xls)及配套技术手册(PDF)、设计说明(txt/doc)、答辩资料(doc/docx)等,类型丰富且分工明确,便于从硬件搭建、软件调试到论文撰写的全流程学习。资源包大小为11.15MB,结构清晰,关键文档均标注“必读”提示,降低入门门槛。已有131人学习下载,提供从传感器选型(ST188红外对管、LM358运放)、信号调理、液晶显示(1602)、按键设置阈值到蜂鸣器报警的完整实现路径,兼具教学性与工程参考价值。
1. 为什么用51单片机+ST188做心率监测,反而比商用模块更适合作为毕业设计载体?
很多同学拿到心率项目第一反应是找MAX30102或AD8232模块——精度高、资料多、接上就能跑。但真到答辩现场,老师一句“你讲讲ST188怎么把光信号转成有效脉搏波”,立刻卡壳。这个基于ST188+LM358+51单片机的系统,恰恰卡在工程实践最硬的关节上:从原始模拟信号到数字脉搏计数的全链路闭环。它不回避噪声、不跳过放大、不绕开阈值判别,而是把光电传感器输出的微弱毫伏级变化,经LM358两级放大与滤波后,送入51单片机的外部中断引脚,再用定时器精确测量相邻脉冲间隔,最终换算为BPM(每分钟心跳次数)。整个流程里,ST188的发射管电流控制、LM358的同相/反相放大配置、51单片机INT0中断服务程序中去抖逻辑、1602液晶的4位数据总线时序——全是课程设计必考细节。它不是“能测就行”的玩具,而是把《模拟电子技术》《单片机原理》《嵌入式系统设计》三门课的知识点拧成一股绳的典型载体。尤其适合需要展示硬件选型依据、电路调试过程、软件状态机设计能力的本科毕设场景。
2. ST188+LM358信号链设计:为什么必须用两级放大而非单级?参数怎么配?
2.1 ST188工作原理与原始信号特征
ST188是红外反射式对管,由红外LED发射管和硅光敏三极管接收管组成。当手指置于其上方时,动脉搏动引起皮下血容量周期性变化,导致反射红外光强度随之波动。接收端输出的是毫伏级交流信号(峰峰值约1–5mV),叠加在数百毫伏的直流偏置上,且混有工频干扰、运动伪影和热噪声。直接送入单片机ADC或比较器会因信噪比过低而无法稳定触发。因此,必须先进行直流偏置提取→交流耦合→带通放大→整形四步处理。
提示:ST188手册明确标注其接收管输出为电流源模式,需外接负载电阻转换为电压。常见错误是直接将接收端接VCC或GND,导致无输出或饱和。
2.2 LM358双运放典型应用电路配置
本系统采用LM358(双运放)构建两级处理链:第一级为高增益同相放大+高通滤波,第二级为带通滤波+施密特触发整形。电路结构如下(对应原理图PDF第3页):
// 第一级:同相放大 + 一阶高通(fc ≈ 0.5Hz) // R1=10k, R2=470k → 增益 Av1 = 1 + R2/R1 ≈ 48 // C1=10uF, R1=10k → 高通截止频率 f_c = 1/(2π*R1*C1) ≈ 1.59Hz(实际取值兼顾去基线漂移) // 第二级:反相带通 + 施密特触发(迟滞约±0.2V) // R3=10k, R4=100k → 反相增益 Av2 = -R4/R3 = -10 // C2=0.1uF, R5=10k → 低频截止 f_L = 1/(2π*R5*C2) ≈ 159Hz(抑制高频噪声) // R6=1M, R7=10k → 施密特正向阈值 V_th+ = Vcc * R7/(R6+R7) ≈ 0.05V,负向阈值 V_th- ≈ -0.05V关键参数说明:
- 第一级增益48倍:将1mV信号抬升至48mV,避开51单片机内部比较器输入范围下限(通常≥100mV才可靠触发);
- 高通截止1.59Hz:滤除呼吸波(0.1–0.5Hz)和缓慢基线漂移,保留0.8–3Hz心率频段;
- 第二级带通中心频率≈1.2Hz:由C2/R5与后续RC网络共同决定,抑制50Hz工频干扰;
- 施密特触发迟滞±50mV:防止噪声在阈值附近反复翻转,确保每个真实脉搏仅产生一个干净下降沿。
注意:LM358供电必须为单电源(+5V),其输出无法达到轨到轨。实测中若第二级输出摆幅不足,需检查R6/R7分压比是否过大——此处R6=1M过大会导致迟滞过小,建议调整为470kΩ以获得±0.15V迟滞。
2.3 Proteus仿真验证关键步骤
在Proteus 8.13中加载仿真源文件.DSN后,执行以下操作验证信号链有效性:
# 1. 在ST188接收端探针处放置虚拟示波器(XSC1) # 2. 运行仿真,观察原始信号:应为叠加在~2.5V直流上的微弱波动(峰峰值<5mV) # 3. 将探针移至LM358第一级输出端(U1A OUT):信号幅度应达~100mV,基线稳定 # 4. 移至第二级输出端(U1B OUT):应看到规则方波,频率对应设定心率(如60BPM=1Hz) # 5. 若方波占空比异常或频率跳变,检查C1容值——增大C1可降低高通截止频率,但会引入相位延迟失败时排查重点:
- ST188发射管限流电阻R_led是否为100Ω?过大则红外功率不足,反射信号微弱;
- LM358第4脚(V-)是否接地?第8脚(V+)是否接+5V?接反会导致运放失效;
- 施密特触发反馈电阻R6是否虚焊?万用表量测R6两端阻值应为标称值。
3. 51单片机核心逻辑实现:如何用定时器+外部中断精准计算BPM?
3.1 硬件资源分配与引脚定义
根据51工程文件\STARTUP.A51及main.c头文件,关键引脚映射如下:
| 功能 | 单片机引脚 | 说明 |
|---|---|---|
| 脉搏信号输入 | P3.2 (INT0) | 下降沿触发,接LM358第二级输出 |
| 液晶数据总线 | P0.0–P0.3 | 4位模式,D4–D7 |
| 液晶控制线 | P2.0(RS) | 寄存器选择 |
| P2.1(RW) | 读写控制(固定接地) | |
| P2.2(EN) | 使能脉冲 | |
| 报警蜂鸣器 | P1.0 | 低电平驱动(共阴极) |
| 设置按键 | P1.1–P1.3 | KEY_UP / KEY_DOWN / KEY_SET |
提示:KEY3为三按键结构,非矩阵键盘。P1.1–P1.3默认上拉,按键按下时对应引脚拉低,需在
key_scan()函数中加入10ms软件消抖。
3.2 外部中断+定时器协同计时算法
心率计算本质是测量相邻两个脉搏下降沿的时间间隔,再换算为每分钟次数。51单片机资源有限,不能依赖长延时函数,必须用定时器溢出中断配合外部中断标志。核心代码逻辑如下(摘自pulse_count.c):
#include <reg52.h> #define uchar unsigned char #define uint unsigned int uchar pulse_cnt = 0; // 脉冲计数器(用于60秒内计数) uint time_cnt = 0; // 定时器T0计数值(单位:ms) bit pulse_flag = 0; // 脉冲捕获标志 uint last_time = 0; // 上次脉冲时刻(ms) uint interval_ms = 0; // 当前间隔(ms) void Timer0_Init() { TMOD |= 0x01; // T0为16位定时器 TH0 = (65536-50000)/256; // 50ms定时(11.0592MHz晶振) TL0 = (65536-50000)%256; ET0 = 1; // 开T0中断 TR0 = 1; // 启动T0 } void EX0_Init() { IT0 = 1; // INT0下降沿触发 EX0 = 1; // 开外部中断0 EA = 1; // 开总中断 } void main() { Timer0_Init(); EX0_Init(); while(1) { if(pulse_flag) { pulse_flag = 0; if(time_cnt > last_time) interval_ms = time_cnt - last_time; else interval_ms = 0xFFFFFFFF - last_time + time_cnt; // 处理定时器溢出 last_time = time_cnt; if(interval_ms > 300 && interval_ms < 2000) { // 排除误触发(<300ms为抖动,>2s为停搏) uint bpm = 60000 / interval_ms; // 换算BPM if(bpm > 40 && bpm < 200) show_bpm(bpm); // 显示并限幅 } } } } void timer0() interrupt 1 { TH0 = (65536-50000)/256; TL0 = (65536-50000)%256; time_cnt += 50; // 每50ms累加一次 } void ex0_int() interrupt 0 { pulse_flag = 1; // 置位标志,避免在中断中执行耗时操作 }参数说明:
interval_ms:两次脉冲间毫秒数,60000ms ÷ interval_ms = BPM;300–2000ms过滤区间:对应200–30BPM,覆盖正常人体心率范围(静息60–100,运动可达180);time_cnt为全局变量,需声明为uint(16位)并注意溢出处理——当time_cnt从65535回绕至0时,last_time > time_cnt成立,此时真实间隔 =0xFFFFFFFF - last_time + time_cnt。
3.3 1602液晶显示驱动关键时序
本系统采用4位数据总线模式以节省IO口。lcd_write_com()函数中关键时序要求(依据HD44780手册):
| 操作 | 最小时间 | 实现方式 |
|---|---|---|
| E脉冲宽度 | ≥450ns | E=1; _nop_(); _nop_(); E=0; |
| E上升沿到数据建立 | ≥40ns | 数据写入P0后延时1个机器周期 |
| 指令执行时间 | 1.64ms | 写入指令后需delay_ms(2) |
void lcd_write_com(uchar com) { RS = 0; RW = 0; P0 = com & 0xF0; // 高4位 E = 1; _nop_(); _nop_(); E = 0; // 使能脉冲 delay_us(200); P0 = (com << 4) & 0xF0; // 低4位 E = 1; _nop_(); _nop_(); E = 0; delay_ms(2); // 等待指令执行 }注意:
delay_us(200)不可省略,否则低4位可能未被正确锁存;delay_ms(2)必须大于1.64ms,否则下一条指令可能被覆盖。
4. 报警阈值设置与蜂鸣器驱动:KEY3三按键状态机设计要点
4.1 KEY3按键状态机逻辑
KEY3包含UP/DOWN/SET三个独立按键,需实现阈值上下限独立设置+确认保存功能。状态机设计为三级嵌套:
| 主状态 | 子状态 | 操作逻辑 |
|---|---|---|
IDLE | — | 显示当前BPM及阈值,等待SET键按下 |
SET_MODE | SET_LOW | UP/DOWN调节下限,SET确认进入上限设置 |
SET_HIGH | UP/DOWN调节上限,SET返回IDLE并保存EEPROM |
状态切换关键代码(key_process.c):
typedef enum {IDLE, SET_LOW, SET_HIGH} set_state_t; set_state_t cur_state = IDLE; uchar low_th = 60, high_th = 100; // 默认阈值 void key_scan() { static uchar key_pre[3] = {1,1,1}; // 上次状态 uchar key_cur[3]; key_cur[0] = KEY_UP; // P1.1 key_cur[1] = KEY_DOWN; // P1.2 key_cur[2] = KEY_SET; // P1.3 for(uchar i=0; i<3; i++) { if(key_cur[i] == 0 && key_pre[i] == 1) { // 下降沿 switch(cur_state) { case IDLE: if(i == 2) cur_state = SET_LOW; // SET键进入设置 break; case SET_LOW: if(i == 0) low_th = (low_th < 120) ? low_th+1 : 40; // UP加1 if(i == 1) low_th = (low_th > 40) ? low_th-1 : 120; // DOWN减1 if(i == 2) { cur_state = SET_HIGH; lcd_show("HIGH:"); } // SET切上限 break; case SET_HIGH: if(i == 0) high_th = (high_th < 180) ? high_th+1 : 60; if(i == 1) high_th = (high_th > 60) ? high_th-1 : 180; if(i == 2) { save_to_eeprom(); cur_state = IDLE; } // SET保存退出 break; } } key_pre[i] = key_cur[i]; } }提示:
save_to_eeprom()调用STC89C52内置EEPROM写入函数,地址0x2000存储low_th,0x2001存储high_th。写入前需校验地址有效性,避免擦写寿命耗尽。
4.2 BZ蜂鸣器驱动电路与软件控制
蜂鸣器型号为TMB-12A05(有源型),其内部已集成振荡电路,只需提供直流电压即可发声。原理图中P1.0经1kΩ限流电阻驱动,低电平导通(共阴极接法):
void beep_on() { P1_0 = 0; // 拉低导通 delay_ms(500); // 持续500ms } void beep_off() { P1_0 = 1; // 拉高关断 } // 主循环中实时检测 if(bpm > high_th || bpm < low_th) { beep_on(); lcd_show_alert(); // 显示"ALERT!" } else { beep_off(); }关键约束:
- 有源蜂鸣器不可用PWM驱动,否则可能损坏内部振荡器;
delay_ms(500)期间CPU被阻塞,若需同时处理其他任务,应改用定时器中断标志轮询;- 实际PCB布线时,蜂鸣器走线需远离模拟信号路径(如ST188接收端),避免电磁干扰。
5. 从仿真到实物:焊接调试与常见故障定位实战技巧
5.1 万能板焊接关键工艺控制点
本系统采用洞洞板(万能板)手工焊接,而非PCB,需特别注意三点:
- 电源去耦:在LM358第4脚(GND)和第8脚(VCC)就近焊接0.1μF陶瓷电容,否则运放易自激振荡;
- ST188间距控制:发射管与接收管中心距严格保持3mm(用游标卡尺校准),过近导致直射光饱和,过远则反射信号衰减;
- 液晶排线长度:1602数据线(P0.0–P0.3)与控制线(P2.0–P2.2)应等长布线,长度≤10cm,否则4位模式下时序偏移导致乱码。
提示:焊接LM358时,烙铁温度设为350℃,单点焊接时间≤2秒,避免热损伤运放内部晶体管。
5.2 分阶段调试法:信号链逐级验证表格
| 调试阶段 | 测试点 | 正常现象 | 异常处理方案 |
|---|---|---|---|
| 电源层 | LM358第8脚 | 对地电压=4.95–5.05V | 检查7805输入电容是否虚焊 |
| 模拟层 | ST188接收端 | 万用表DC档读数≈2.4V,AC档≈2mV | 若DC偏置偏离,调整LM358第一级R1阻值 |
| 放大层 | LM358 U1A输出 | 示波器观测到清晰正弦波(幅值≈100mV) | 若失真,检查R2是否接触不良 |
| 整形层 | LM358 U1B输出 | 方波频率=心率值(如60BPM→1Hz) | 若无输出,用万用表测U1B第7脚电压是否≈2.5V |
| 数字层 | P3.2引脚 | 逻辑分析仪捕获下降沿,间隔稳定 | 若无边沿,检查INT0中断使能位EX0是否为1 |
5.3 心率值跳变/归零的终极排查清单
当实测BPM频繁跳变或恒为0时,按此顺序检查:
- ST188物理接触:手指是否完全覆盖发射/接收窗口?指甲盖反光会导致信号丢失;
- LM358供电:用万用表测第4脚(GND)与第8脚(VCC)间电压,若低于4.8V,更换7805稳压芯片;
- INT0中断优先级:确认
PX0=1(外部中断0优先级最高),避免被其他中断抢占; - 定时器初值计算:晶振频率是否为11.0592MHz?若误用12MHz晶振,
TH0/TL0需重算为(65536-46080); - 液晶背光电路:检查LED+与LED-间是否串接了47Ω限流电阻,电阻开路会导致屏幕全黑,误判为程序死机。
最后一步技巧:在ex0_int()中断服务程序首行插入P1_7 = ~P1_7;(翻转P1.7),用示波器观测该引脚波形。若P1.7有规律翻转,证明INT0中断正常触发;若无翻转,则问题在硬件信号链前端。
本文还有配套的精品资源,点击获取