十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AT89S52数字心率计设计:从光电脉搏波到数码管显示的完整实现

AT89S52数字心率计设计:从光电脉搏波到数码管显示的完整实现 简介这份毕业设计文档面向电子信息、自动化等专业的本科毕业生提供一套基于AT89S52单片机的数字心率计完整设计方案可用于课程设计、毕业答辩或嵌入式入门实践。资源包内含1个doc文件约2.38MB即论文正文涵盖摘要、总体方案、元器件选型、硬件电路图、程序流程图与系统测试等章节。设计以AT89S52为核心采用红外光电传感器OPT101采集人体微弱信号经OP07与LM324N双重放大、A/D转换后由单片机计算最终通过四位数码管实时显示心率并采用主程序、信号采集、放大处理、显示等模块化结构便于扩展与维护。文中还给出硬件电路与软件编程思路可帮助读者理解从信号采集到数字显示的完整链路并参考其测试与误差分析方法。目前已有50人学习适合需要低成本、高精度心率测量方案参考的读者。1. 从光电脉搏波到数码管读数AT89S52 数字心率计到底在做什么心率计的核心不是“算心跳”而是把一段微弱的、带直流偏置的模拟脉搏波变成单片机可以稳定计数的方波。AT89S52 在这套方案里承担的角色很明确它不负责模拟前端只负责定时、计数、换算和显示。真正决定成败的是 OPT101 光电接收、LM324N 信号调理和 ADC0809 采样这三段模拟链路。很多人做毕业设计时把精力全放在写显示程序上结果板子焊完发现数码管数字乱跳。原因通常不在 8051 代码而在光电信号没有经过正确的隔直和整形。OPT101 输出的是叠加在约 1V 直流上的脉搏交流分量幅度可能只有几十毫伏直接送 ADC0809 会被直流淹没。所以这套标题对应的完整链路是OPT101 采集 → LM324N 隔直放大与滤波 → 比较器整形 → AT89S52 用定时器/计数器测周期 → 换算 BPM → 数码管显示。适合电子、自动化、生物医学工程方向的本科毕业设计也适合想复习 51 单片机定时器与外部中断配合的工程师。2. AT89S52 与 ADC0809 的硬件链路怎么搭2.1 OPT101 与 LM324N 的信号调理电路OPT101 内部集成了光电二极管和跨阻放大器输出阻抗低直接接 LM324N 的同相输入端即可。但它的输出含直流分量必须先用高通滤波隔直。常见做法是用 1μF 电容串联 10kΩ 电阻构成一阶高通截止频率约 16Hz刚好让 0.8Hz 到 3Hz 的脉搏波通过同时抑制直流。LM324N 在这里用两级第一级做同相放大增益设为 100 倍左右把几十毫伏的交流分量抬到伏级第二级做二阶低通截止频率设在 5Hz 附近滤掉工频和运动伪迹。LM324N 是四运放单电源供电时要注意输入共模范围同相端偏置在 VCC/2 附近最稳。# 用 LTspice 或 Multisim 验证高通截止频率的快速估算 # f_c 1 / (2 * pi * R * C) # R 10k, C 1uF f_c ≈ 15.9 Hz # 放大倍数 Av 1 Rf/R1Rf100k, R11k Av101参数说明Rf 和 R1 决定增益增益不是越大越好。增益过大会让 LM324N 输出饱和脉搏波的收缩峰和舒张峰被削平后续比较器无法区分。建议先用示波器看 LM324N 输出调到峰峰值 1V 到 2V 之间再往下接。2.2 ADC0809 与 AT89S52 的接口时序ADC0809 是 8 位逐次逼近型 ADC8 通道这里只用 IN0。它和 AT89S52 的连接分三组数据线 D0-D7 接 P0 口控制线 START、ALE、OE 接 P2 口EOC 接 P3.2 外部中断。时钟端 CLK 需要 500kHz 左右可以用 AT89S52 的 ALE 输出经 74LS74 二分频得到。信号ADC0809 引脚AT89S52 引脚作用START6P2.0启动转换ALE22P2.1通道地址锁存OE9P2.2输出使能EOC7P3.2/INT0转换结束中断CLK10ALE/2500kHz 时钟D0-D717-14,8-5P0.0-P0.7数据总线启动转换的代码要严格按手册时序先送通道地址再给 ALE 脉冲再给 START 脉冲然后等待 EOC 变高。#include reg52.h #include absacc.h sbit START P2^0; sbit ALE P2^1; sbit OE P2^2; sbit EOC P3^2; unsigned char adc_read() { unsigned char val; ALE 0; START 0; OE 0; ALE 1; // 锁存通道地址 START 1; // 启动转换 ALE 0; START 0; while(EOC 0); // 等待转换结束 OE 1; // 使能输出 val P0; // 读取 8 位结果 OE 0; return val; }逻辑说明ALE 上升沿锁存 P0 口低三位作为通道号START 上升沿启动转换EOC 从低变高表示转换完成OE 拉高后 P0 口输出有效数据。参数上ADC0809 转换时间约 100μs500kHz 时钟下约 128μswhile 等待不会太久但不要在主循环里频繁调用否则会拖慢显示刷新。2.3 用 AT89S52 定时器测周期间的取舍测心率有两种思路测频率和测周期。脉搏波频率低0.8Hz 到 3Hz直接测频率在 1 秒闸门内只有 1 到 3 个脉冲分辨率太差。所以常见做法是测周期用 INT0 捕获脉搏波整形后的上升沿记录两次中断之间的定时器计数值再换算成 BPM。AT89S52 的定时器 0 工作在模式 116 位计数机器周期 1μs 时最大计 65536μs约 65ms。脉搏周期在 333ms 到 1250ms 之间会溢出。解决办法是定时器 0 设 50ms 中断一次在中断里累加溢出次数INT0 中断里读取总时间。unsigned int overflow 0; unsigned int period 0; unsigned char flag 0; void timer0_isr() interrupt 1 { TH0 0x3C; TL0 0xB0; // 50ms 重装 overflow; } void int0_isr() interrupt 0 { unsigned int now overflow * 50000 (TH0 8 | TL0); static unsigned int last 0; if (last ! 0) { period now - last; flag 1; } last now; }参数说明TH0/TL0 重装值 0x3CB0 对应 50ms12MHz 晶振。overflow 每 50ms 加一now 的单位是微秒。period 算出后BPM 60000000 / period。注意 INT0 中断里不要做除法除法放在主循环否则中断响应会变慢丢失下一个脉冲。3. 从 ADC 采样到 BPM 显示的完整程序流程3.1 主循环的状态机设计主循环不要写成 delay 堆砌用状态机更稳。状态分三个等待脉搏、计算 BPM、刷新显示。ADC 采样只在等待状态里做用来判断信号是否有效避免噪声触发 INT0。void main() { unsigned int bpm; init_timer0(); init_int0(); while(1) { if (flag) { flag 0; if (period 300000 period 1500000) { // 40-200 BPM bpm 60000000UL / period; display_bpm(bpm); } } // 用 ADC 做信号质量监测阈值可调 if (adc_read() 30) { display_error(); } } }逻辑说明period 的有效范围限制在 300ms 到 1500ms对应 40 到 200 BPM超出范围视为噪声丢弃。ADC 读值低于 30 说明 OPT101 没检测到手指或信号太弱显示错误提示。参数上阈值 30 是 8 位 ADC 的经验值实际要根据 LM324N 输出偏置调整。3.2 数码管动态扫描与 BPM 换算四位共阳数码管用 P1 口段选、P2.3-P2.6 位选。动态扫描频率要高于 50Hz否则会闪。定时器 1 设 2ms 中断一次每次刷新一位。unsigned char code seg[] {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; unsigned char disp[4]; void timer1_isr() interrupt 3 { static unsigned char idx 0; P2 (P2 0x87) | (1 (idx 3)); // 位选 P1 seg[disp[idx]]; idx (idx 1) % 4; } void display_bpm(unsigned int bpm) { disp[0] bpm / 1000; disp[1] bpm / 100 % 10; disp[2] bpm / 10 % 10; disp[3] bpm % 10; }参数说明seg 数组是共阳段码0 到 9 对应 0xC0 到 0x90。P2 口高三位用于其他控制所以位选时要先屏蔽再置位。定时器 1 重装值对应 2ms12MHz 晶振下 TH10xF8, TL10x30。BPM 超过 999 时千位显示 1实际心率不会超过 200所以 disp[0] 通常为 0。3.3 串口输出调试数据到上位机调试阶段用串口把 period 和 bpm 打到上位机比盯着数码管快得多。AT89S52 串口用定时器 1 做波特率发生器时定时器 1 就不能同时做显示扫描了。常见做法是调试时用串口定型后再切回显示扫描。void uart_init() { TMOD | 0x20; // 定时器1模式2 TH1 0xFD; TL1 0xFD; // 9600bps 11.0592MHz SCON 0x50; // 模式1允许接收 TR1 1; } void uart_send(unsigned char dat) { SBUF dat; while(TI 0); TI 0; }逻辑说明11.0592MHz 晶振下 TH10xFD 对应 9600bps误差为 0。12MHz 晶振下 9600bps 误差约 8.5%会乱码所以串口调试建议换 11.0592MHz 晶振。发送前等 TI 清零发送后手动清 TI这是 51 串口的固定套路。4. 信号质量差、读数乱跳时的排查顺序4.1 用示波器逐级定位模拟链路读数乱跳先别改代码按 OPT101 输出、LM324N 第一级输出、LM324N 第二级输出、比较器输出这个顺序看波形。OPT101 输出应该是带直流偏置的脉搏波幅度 50mV 到 200mV。如果这里就是一条直线检查手指是否遮住 OPT101 窗口或者供电是否正常。LM324N 第一级输出应该是放大后的脉搏波峰峰值 1V 到 2V。如果削顶减小 Rf。如果还是直线检查高通电容是否焊反或虚焊。第二级输出应该更干净工频干扰明显减小。比较器输出应该是干净的方波上升沿陡峭。如果方波占空比随手指压力变化说明比较器阈值没设好用可调电阻分压做阈值。提示LM324N 是低速运放压摆率约 0.5V/μs放大 100 倍后带宽只剩几十 kHz处理脉搏波够用但不要用它做高频比较器。4.2 定时器溢出与中断优先级的坑INT0 和定时器 0 同时开中断时如果 INT0 中断服务程序执行时间过长会丢失定时器 0 的溢出。AT89S52 的中断优先级里INT0 默认高于定时器 0所以 INT0 里只读 TH0/TL0 和 overflow不做除法执行时间控制在 20μs 以内。另一个坑是定时器 0 重装值。如果 TH0/TL0 在中断里重装而 INT0 中断又读了 TH0/TL0可能读到重装一半的值。解决办法是在 INT0 里先关定时器 0读完再开。void int0_isr() interrupt 0 { TR0 0; unsigned int now overflow * 50000 (TH0 8 | TL0); TR0 1; // ... 后续处理 }参数说明TR0 是定时器 0 启动位关掉后 TH0/TL0 不再变化读到的值一致。这个操作只增加几个机器周期不影响脉搏周期测量精度。4.3 ADC0809 参考电压与量化误差ADC0809 的参考电压直接决定量化精度。如果 VREF 接 5V8 位 ADC 的量化单位是 19.5mV。脉搏波交流分量放大到 2V 峰峰值时量化误差约 1%够用。但如果 LM324N 输出只有 0.5V 峰峰值量化误差就到 4%BPM 会有几个字的跳动。常见做法是把 VREF 降到 2.5V用 TL431 产生这样量化单位降到 9.8mV。注意 VREF 不能低于 2V否则 ADC0809 线性度变差。另外 ADC0809 的模拟输入范围是 0 到 VREFLM324N 输出偏置要设在 VREF/2 附近否则波形下半周被削掉。问题现象可能原因排查手段数码管全灭位选或段选接反用万用表测 P1/P2 电平BPM 固定 0INT0 没触发示波器看比较器输出BPM 跳动 ±20信号噪声大加大低通滤波电容串口乱码晶振不是 11.0592MHz换晶振或改 TH1ADC 读数不变EOC 没接或 OE 时序错查 P3.2 电平和 OE 脉冲5. 把心率计做成可演示作品的三个进阶技巧5.1 用滑动平均滤波稳住 BPM 读数单次周期测量受噪声影响大连续测 4 次取平均读数会稳很多。但要注意如果手指移动导致某次周期异常平均值会被拉偏。所以先做中值滤波再做平均连续测 5 次去掉最大最小剩下 3 次取平均。unsigned int buf[5]; unsigned char cnt 0; unsigned int filter() { unsigned int max 0, min 0xFFFF, sum 0; for (unsigned char i 0; i 5; i) { if (buf[i] max) max buf[i]; if (buf[i] min) min buf[i]; sum buf[i]; } return (sum - max - min) / 3; }逻辑说明buf 存最近 5 次周期值去掉最大最小后取平均。这个滤波器计算量小51 单片机跑得动。参数上5 次窗口对应约 4 秒延迟演示时能接受。如果要求响应快改成 3 次窗口。5.2 用 AT89S52 的看门狗防止程序跑飞AT89S52 内置看门狗定时器通过 WCON 寄存器控制。演示现场电机、继电器干扰大时程序可能跑飞导致数码管卡死。开看门狗后主循环里定期喂狗跑飞后自动复位。#include at89s52.h void wdt_init() { WCON 0x00; // 看门狗溢出周期约 16ms // 喂狗指令 WCON 0x40; WCON 0x00; }参数说明WCON 的 bit6 是喂狗位写 1 再写 0 完成喂狗。溢出周期由 WCON 低两位决定00 对应 16ms01 对应 32ms10 对应 64ms11 对应 128ms。主循环执行时间要小于溢出周期否则会不断复位。喂狗放在主循环开头不要放在中断里。5.3 用 Proteus 仿真验证时序再焊板Proteus 里有 AT89S52、ADC0809、LM324N 的模型可以先把程序跑通再焊板。仿真时注意 ADC0809 模型需要手动给 EOC 信号或者用 Proteus 的激励源模拟。脉搏波信号可以用 PWL 源生成频率设 1.2Hz幅度 100mV叠加 1V 直流。仿真通过后焊板时先焊电源和单片机最小系统用串口确认单片机跑得起来。再焊 ADC0809用可调电阻给 IN0 一个已知电压看串口读数是否线性。最后焊模拟前端用信号发生器代替 OPT101 调试。这样分段调试比一次焊完再排查快得多。本文还有配套的精品资源点击获取
返回列表