ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于51单片机与Proteus的脉搏检测仿真:从信号调理到心率算法

2026/9/2 7:42:47 拓冰建站 浏览量
基于51单片机与Proteus的脉搏检测仿真:从信号调理到心率算法 简介本资源是一套基于Proteus平台的STM32脉搏心跳检测仿真设计方案面向嵌入式初学者、课程设计学生及单片机实验教学使用者解决硬件资源受限下心率检测原理验证与人机交互功能实现问题。压缩包共198个文件含33个编译中间文件.o/.d、32个头文件.h、31个C源码.c、8个汇编文件.s及1个可直接加载运行的.hex固件完整覆盖STM32F103底层驱动如ADC采样模拟、TIM定时、RCC时钟配置与LCD数码管双显示逻辑结构清晰便于模块化学习与调试。已有1271人学习下载资源提供可立即运行的Proteus电路图与Keil工程支持按键模拟脉冲输入、实时计数显示于数码管、系统时间同步呈现于LCD是理解生物信号仿真建模与嵌入式外设协同开发的典型教学案例。1. 项目概述从仿真到现实的脉搏检测最近在整理一些老项目翻到了当年做的一个基于单片机的脉搏心跳检测仿真设计。这个项目虽然听起来像是医疗电子领域的入门级课题但麻雀虽小五脏俱全它完整地串联了传感器信号调理、单片机数据采集处理、以及Proteus虚拟仿真验证这一整套流程。对于电子、自动化或者生物医学工程专业的学生或者刚入行的嵌入式工程师来说这是一个绝佳的练手项目能让你把书本上的模电、数电、单片机原理和C语言编程知识在一个具体的、有实际意义的场景里串起来。简单来说这个设计的核心目标就是在Proteus这个强大的电子设计自动化软件里搭建一个虚拟的硬件电路模拟人体脉搏信号一种微弱的、周期性的生理电信号或压力信号的采集、放大、整形然后由单片机比如经典的51内核单片机进行定时计数或频率计算最终得出心率值次/分钟并显示出来。它解决的核心问题是在不动用真实元器件、不焊接电路板的前提下低成本、零风险地验证你的硬件电路设计和软件算法逻辑是否可行。这特别适合项目前期方案论证、课程设计、毕业设计或者个人兴趣学习。整个流程会涉及几个关键环节首先你需要一个能“产生”脉搏信号的仿真元件其次需要设计前置放大和滤波电路来处理这个微弱的仿真信号然后单片机通过定时器/计数器来捕捉信号的周期最后通过计算并在虚拟的LCD或数码管上显示心率。下面我就结合我当时的实现过程和踩过的坑把这个项目的里里外外拆解清楚。2. 核心思路与方案选型背后的考量做任何一个嵌入式系统设计第一步永远不是打开软件就开始画图而是先想清楚“我要怎么做”以及“为什么这么做”。对于这个脉搏检测仿真核心思路可以概括为“信号模拟 - 信号调理 - 信号捕获 - 数据处理 - 结果展示”。每一个环节的选型都直接关系到仿真的真实性和最终结果的准确性。2.1 脉搏信号的仿真源选择在真实的项目中我们使用光电脉搏传感器如PPG传感器或压电式脉搏传感器。但在Proteus仿真环境中我们需要一个能持续产生类似脉搏波形的信号源。这里有几种常见选择信号发生器GeneratorProteus自带的信号发生器可以产生方波、正弦波、三角波等。我们可以用一个低频如1Hz对应60 BPM的方波来简单模拟心跳的节奏。优点是设置简单缺点是波形过于理想与真实的脉搏波具有一定上升沿和下降沿的类正弦波相差甚远无法测试后续滤波电路的真实效果。利用脚本控制的电压源通过编写脚本Script或使用基于DLL的模型可以生成更复杂的、接近真实脉搏波的波形。这需要一定的脚本编程能力但仿真效果最好。使用可编程脉冲源与RC电路整形这是一种折中且实用的方法。使用一个低频的时钟脉冲源如1Hz后面连接一个由电阻、电容构成的积分电路或滤波电路将方波的边沿“磨圆”产生一个近似的脉搏波形。这种方法既能体现信号的非理想性又不需要复杂的编程。实操心得对于初学者或希望快速验证核心计数逻辑的项目我推荐从方法1简单方波开始。先确保单片机的心率计算算法是正确的。当算法没问题后再切换到方法3脉冲源RC整形来验证你的放大滤波电路是否能够正确处理这种“不干净”的信号。这符合“由简入繁”的调试原则。2.2 单片机选型为什么是51内核热搜词里频繁出现“51单片机”这反映了它的经典和普及程度。在这个项目中选择AT89C51、AT89C52或STC89C52这类51内核单片机是非常合适的原因如下资源足够心率检测的核心是定时/计数。51单片机有2-3个定时器/计数器完全满足捕捉脉冲间隔的需求。计算心率所需的乘除法运算51的指令集也能胜任。仿真支持完善Proteus对51系列单片机的仿真支持是最好、最稳定的之一模型丰富调试方便。学习资料海量从郭天祥的教程到无数的网络博客任何你遇到的问题几乎都能找到答案学习成本极低。情怀与基础很多人的单片机入门就是从51开始的用它来做这个项目有一种“温故知新”的感觉。当然你也可以用STM32或GD32等更强大的ARM Cortex-M内核单片机它们精度更高、功能更强。但对于“脉搏检测”这个具体应用51单片机的性能是过剩的用它能更聚焦于算法和系统逻辑本身而不是纠结于复杂的外设驱动。2.3 显示方案选型计算出的心率需要输出。仿真中常用LCD1602字符液晶最经典的选择可以显示两行字符比如Heart Rate: 72 BMP。Proteus中有现成的、仿真效果很好的模型。编程需要初始化并实现字符写入函数。数码管4位或6位数码管直接显示数字如0072。编程更简单但显示信息单一。虚拟终端Virtual Terminal将数据发送到串口在虚拟终端上打印出来。这更像是在调试而非最终产品形态。我推荐使用LCD1602因为它更接近一个实际产品的显示方式而且学习其驱动也是嵌入式开发的基本功。3. 硬件电路设计细节与仿真要点有了方案我们就可以在Proteus中搭建电路了。这里的关键在于不仅要连对线还要理解每个部分为什么这么连。3.1 脉搏信号发生与调理电路设计我们采用上述的“方法3”来生成仿真脉搏信号。脉冲源从Proteus元件库中找出CLOCK元件将其频率设置为1.2 Hz对应72 BPM一个常见的静息心率。这个时钟信号会输出一个0V/5V的方波。波形整形电路在时钟信号输出端连接一个简单的RC低通滤波电路。例如串联一个10kΩ的电阻然后对地接一个10uF的电容。RC电路的时间常数 τ R*C 0.1秒它能够滤除方波中的高频成分陡峭的边沿使输出变成一个缓慢上升和下降的类三角波或近似正弦波更贴近真实的脉搏波波形。前置放大电路经过整形后的信号幅度很小可能只有几十到几百毫伏需要放大。使用一个运算放大器如LM358Proteus库里有搭建一个同相比例放大电路。放大倍数Au 1 Rf/R1根据仿真中信号的幅度可以将放大倍数设置为10-100倍。这里需要注意运放的供电如5V和GND和单电源供电下的虚地问题如果需要。电压抬升与滤波脉搏信号是交流信号可能含有负电压或基线不为零。为了方便单片机ADC采集如果采用ADC方式或后续比较器处理通常需要一个电压抬升电路如用运放搭建加法器将信号整体抬升到0V以上。同时可以加入一个带通滤波电路滤除高频噪声和极低频的基线漂移如呼吸引起的缓慢波动。一个简单的有源带通滤波器可以用运放实现。注意事项在Proteus中仿真运放电路时务必给运放元件正确连接电源引脚VCC和VCC-否则电路无法正常工作你会得到毫无意义的输出。这是新手最容易忽略的一点。3.2 单片机信号输入接口设计放大调理后的信号如何送给单片机有两种主流思路ADC采样法将模拟信号接入单片机的ADC输入引脚如果单片机自带ADC如STC12系列或者外接ADC芯片如ADC0804。单片机定期采样通过软件算法如寻找波峰计算脉冲周期。这种方法能获得完整的波形信息更灵活但算法稍复杂。比较器整形法将模拟信号接入一个电压比较器如LM393与一个设定的阈值电压可通过电位器调节进行比较。当脉搏波幅值超过阈值时比较器输出一个数字脉冲高电平。单片机将这个脉冲信号接入外部中断引脚如INT0或定时器的计数输入引脚。这种方法将模拟信号直接转为数字脉冲单片机只需测量脉冲间隔算法极其简单是仿真和入门项目的首选。我强烈推荐比较器整形法因为它硬件和软件都更简单易于理解和实现。完美契合51单片机强大的定时/计数器功能和外部中断功能。在Proteus中仿真稳定结果直观。电路连接示例比较器LM393的输出接至单片机的P3.2口外部中断0。同时可以在比较器输出端接一个LED脉冲来时闪烁便于直观观察。3.3 单片机最小系统与显示电路这部分是标准配置51单片机最小系统包括单片机芯片、复位电路10uF电容10k电阻、晶振电路12MHz晶振两个30pF电容。LCD1602显示电路数据口D0-D7接单片机P0口需加上拉电阻排因为P0口是开漏输出或P2口。控制线RS、RW、E分别接至单片机的三个I/O口。按键电路可选可以添加一个按键用于启动测量或复位心率值。4. 软件程序设计核心与算法实现硬件是躯体软件是灵魂。这个项目的软件核心在于精确测量两个相邻脉搏波之间的时间间隔。4.1 程序整体框架程序通常包含以下模块系统初始化设置定时器工作模式、中断优先级、LCD初始化等。中断服务程序这是核心。外部中断0服务程序当比较器输出脉冲上升沿或下降沿触发中断时进入此函数。它的主要任务是记录当前定时器的计数值并计算与前一个脉冲的时间差。主循环通常是一个空循环或执行一些低优先级的任务如按键扫描。大部分工作都在中断中完成。4.2 心率计算算法详解我们使用定时器T0工作在方式116位定时模式来提供一个高精度的时间基准。假设晶振为12MHz机器周期为1us。T0每计数一次是1us计满65536溢出。计算步骤变量定义定义两个全局变量unsigned int last_count, current_count用于存储定时器值一个float interval_ms用于存储时间间隔。中断触发第一个脉搏脉冲到来进入外部中断记录此时T0的计数值TL0和TH0合并为last_count。第二次中断第二个脉搏脉冲到来再次进入外部中断记录current_count。计算时间差时间差delta_count。这里要特别注意定时器溢出的情况如果current_count last_count说明定时器在两次脉冲间发生了溢出那么实际计数值应为delta_count 65536 - last_count current_count。否则delta_count current_count - last_count。转换为实际时间interval_ms delta_count * 1.0因为1计数1us。单位是微秒转换为毫秒需要除以1000。计算心率心率BPM, Beats Per Minute 60000 / interval_ms。因为1分钟60000毫秒。更新记录将current_count赋值给last_count为下一次计算做准备。输出与滤波将计算出的心率值发送到LCD显示。为了显示稳定可以对连续几次计算的心率值进行滑动平均滤波例如取最近5次值的平均值。// 伪代码示例 (Keil C51) #include reg52.h #include intrins.h #define LCD_DataPort P0 sbit LCD_RS P2^0; sbit LCD_RW P2^1; sbit LCD_E P2^2; unsigned int last_timer_val 0; unsigned int current_timer_val 0; long pulse_interval_us 0; int heart_rate_bpm 0; int hr_buffer[5] {0}; // 用于滤波的缓冲区 int buffer_index 0; void EXTI0_ISR() interrupt 0 // 外部中断0服务程序 { EA 0; // 关总中断防止打断 current_timer_val (TH0 8) | TL0; // 读取当前定时器值 // 计算时间间隔处理溢出 if(current_timer_val last_timer_val) { pulse_interval_us current_timer_val - last_timer_val; } else { pulse_interval_us 65536 - last_timer_val current_timer_val; } // 计算瞬时心率 int instant_hr (int)(60000000L / pulse_interval_us); // 注意单位是微秒60000000微秒1分钟 // 简单限幅滤波防止异常值如小于30或大于200 if(instant_hr 30 instant_hr 200) { hr_buffer[buffer_index] instant_hr; buffer_index (buffer_index 1) % 5; } // 滑动平均滤波 long sum 0; for(int i0; i5; i) { sum hr_buffer[i]; } heart_rate_bpm sum / 5; // 更新上一次的定时器值 last_timer_val current_timer_val; // 更新LCD显示这里调用一个更新显示的函数 update_heart_rate_display(heart_rate_bpm); EA 1; // 开总中断 } void main() { // 初始化定时器T0为方式1定时模式 TMOD 0xF0; // 清零T0控制位 TMOD | 0x01; // 设置T0为方式1 TH0 0; // 初始值从0开始计数 TL0 0; TR0 1; // 启动T0 // 初始化外部中断0为下降沿触发 IT0 1; // 下降沿触发 EX0 1; // 允许外部中断0 EA 1; // 开总中断 // 初始化LCD1602 LCD_Init(); // 显示初始信息 LCD_ShowString(1, 1, Heart Rate:); LCD_ShowString(2, 1, BPM); while(1) { // 主循环可以处理按键或其他任务 // 心率更新在中断中自动完成 } }关键技巧定时器T0从0开始自由运行永不中断。我们只是在中途“偷看”它的值。这种方式比每次脉冲到来后重启定时器更精确因为它避免了中断响应和重装初值带来的微小误差。5. Proteus仿真搭建与调试全流程设计好电路和程序后就到了在Proteus中“跑起来”看效果的阶段。5.1 工程创建与原理图绘制新建工程打开Proteus选择合适的设计模板。放置元件搜索并放置AT89C51。搜索CLOCK放置时钟源。搜索RES、CAP放置电阻电容。搜索LM358或LM393放置运放或比较器。搜索LCD1602放置液晶。搜索LED、BUTTON放置指示灯和按键。布线按照前面设计的电路图仔细连接各元件。Proteus支持自动连线但复杂部分建议手动调整以获得清晰的图纸。参数设置双击CLOCK将频率设置为1.2双击电阻电容设置正确的阻容值双击LM393设置正确的电源电压。5.2 程序编译与加载编写代码在Keil C51中新建工程选择正确的单片机型号如AT89C51编写上述C程序。编译生成HEX文件确保编译无误在Keil的输出文件夹中找到生成的.hex文件。加载HEX文件在Proteus中双击单片机元件在弹出的属性窗口中点击“Program File”右边的文件夹图标选择你刚才生成的.hex文件。将“Clock Frequency”设置为你的晶振频率如12MHz。5.3 运行仿真与信号观测点击运行点击Proteus左下角的“运行”按钮。观察信号在时钟源、RC电路输出、运放输出、比较器输出等关键节点可以右键选择“Place Voltage Probe”放置电压探针实时观察电压值。更直观的方法是使用“Virtual Instrument”中的示波器。点击左侧工具栏的“虚拟仪器”模式选择“OSCILLOSCOPE”示波器将其连接到你想观察的网络上。运行仿真后会弹出示波器窗口可以清晰地看到信号的波形变化从方波变成类脉搏波再被放大、比较成脉冲的过程。观察结果LCD1602上应该会显示出计算出的心率值比如“72”。同时接在比较器输出端的LED会以1.2Hz的频率闪烁。5.4 调试与优化心率显示不稳定可能是RC电路参数或比较器阈值设置不当导致脉冲触发点不稳定。调整RC常数或阈值电位器用示波器观察比较器输入端的波形和阈值线确保每个脉搏波峰都能可靠地超过阈值一次且仅一次。心率值偏差大检查定时器计算部分的代码特别是处理溢出的逻辑是否正确。检查晶振频率设置是否与Proteus中单片机属性里设置的一致。LCD不显示检查LCD的接线、初始化代码、以及数据传输时序。Proteus的LCD模型对时序要求比较严格确保你的延时函数是准确的。6. 常见问题排查与进阶思考即使按照步骤操作仿真中也难免遇到问题。这里记录几个我当年遇到的典型问题及解决方法。问题现象可能原因排查与解决方法仿真运行后电路无任何反应LCD不亮。1. 单片机未加载HEX文件。2. 晶振电路未正确连接或参数错误。3. 复位电路异常单片机一直处于复位状态。1. 双击单片机确认HEX文件路径正确。2. 检查晶振两端是否接到XTAL1/2电容是否接地。3. 用电压探针测复位引脚电压上电后应为高电平。LCD显示乱码或第一行有黑色方块。1. LCD初始化失败。2. 数据线接触不良虚断。3. 读写控制时序不对或使能信号E的脉冲宽度不足。1. 检查初始化指令序列是否正确发送。2. 在Proteus中检查连线是否有红色虚线表示连接冲突或未连接。3. 在初始化和数据写入函数中增加足够的延时。比较器输出LED常亮或不亮无脉冲。1. 比较器阈值电压设置不当。2. 前级运放电路未工作信号未放大。3. 运放/比较器电源未连接。1. 用示波器同时观察比较器正反相输入端的波形调整阈值电位器使其位于脉搏波幅值的中间偏上位置。2. 用电压探针逐级检查信号从时钟源开始确保每一级都有正确的输出。3. 这是最易错点务必确认LM358/LM393的VCC和VCC-或GND已接好。心率显示值跳动剧烈或为0/极大值。1. 外部中断被误触发噪声。2. 定时器溢出处理逻辑错误。3. 心率计算公式单位错误。1. 在中断服务程序入口添加软件去抖延时几个微秒或优化硬件滤波电路。2. 仔细检查计算delta_count的代码特别是if(current_count last_count)这个分支。3. 确认pulse_interval_us单位是微秒心率公式是60000000 / interval_us。示波器看不到预期的脉搏波形。1. 信号源未启动。2. 示波器通道未正确连接或未打开。3. 电路存在短路或断路。1. 确认CLOCK源已设置为“Digital”状态并指定了频率。2. 右键点击示波器选择“Digital Oscilloscope”确保连接正确。3. 使用Proteus的“电气规则检查”功能查找布线错误。进阶思考与扩展 这个基础仿真项目可以作为一个起点进行多方面的扩展提升其复杂度和实用性加入ADC采样改用单片机的ADC或外接ADC芯片来采样完整的脉搏波形。在软件中实现峰值检测、波形特征提取如计算脉搏波传导时间。实现心率变异性分析不止计算平均心率还可以记录一系列心跳间隔RR间期进行简单的时域分析如计算SDNN。添加无线传输模块在仿真中加入蓝牙如HC-05或Wi-Fi模块模型将心率数据发送到虚拟的串口助手或另一个仿真的上位机界面。设计更逼真的信号源使用Proteus的脚本功能或基于SPICE模型生成更接近真实PPG或ECG信号的波形增加仿真挑战。移植到真实硬件这是最终的一步。将Proteus中验证好的电路图转化为PCB设计采购真实的传感器如MAX30102、单片机、运放等元件焊接调试把仿真变成实物。你会发现实物调试中遇到的电源噪声、传感器接触、机械干扰等问题是仿真无法完全覆盖的但那又是另一个充满乐趣和挑战的领域了。这个基于Proteus的脉搏心跳检测仿真项目就像一座连接理论知识与工程实践的桥梁。它让你在安全的虚拟环境中系统地实践了一个完整的小型嵌入式系统开发流程。当你看到虚拟的LCD上稳定地显示出心率数字时那种成就感是单纯看书或写代码无法比拟的。希望这份详细的拆解能帮你少走弯路顺利搭起这座桥。本文还有配套的精品资源点击获取