资讯详情

基于51单片机的血压计课设:传感器、ADC与Keil4/Proteus仿真实现

📅 2026/9/15 13:11:34 | 华诺云谱 👁 阅读
基于51单片机的血压计课设:传感器、ADC与Keil4/Proteus仿真实现
简介以单片机为控制核心的电子血压计课程设计全套方案完整实现血压与体温二合一测量面向电子信息类学生课设、毕设或动手实践。方案涵盖压力传感器与温度传感器的信号采集、处理模块、显示模块及电源管理通过按键切换血压/体温显示。压缩包共22个文件以Keil工程文件为主体包含C语言源代码、A51启动文件、hex烧录文件、Proteus仿真图纸DSN/DBK/PWI及设计报告doc/docx等覆盖开发、仿真到文档撰写全流程lst/obj为编译中间文件plg/uvopt为工程配置整体约865KB。目前已有589人学习下载对快速上手51单片机外设与仿真调试具有参考价值。通过该包可获取完整的代码框架、仿真电路和报告范例帮助理解血压计信号链路与模块化编程思路为二次开发和课设答辩提供直接支撑。1. 从袖带压力到数字读数这套单片机血压计课设到底在做什么打开这份 zip里面没有复杂的 DSP 芯片也没有临床级别的无创血压算法论文而是一套能直接编出 hex 文件的 Keil4 工程搭配一份 Proteus 仿真。核心逻辑比想象中简单单片机读压力传感器的模拟电压按键切换后再读温度传感器将两组数值送到 LCD 显示。真正容易让人卡住的地方不是传感器型号而是“怎么从袖带压力波形里算出收缩压和舒张压”。课设里常见做法是把算法简化成阈值比较加状态机硬件上只保留充气泵、放气阀、压力传感器和温度传感器。这套资源适合正在做单片机课程设计的人也适合想快速补齐“传感器→ADC→算法→显示”这条完整链路、但暂时没有实物电路板的嵌入式爱好者。整理时我按源码和仿真把模块拆开重点讲哪些代码可以直接抄哪些参数必须按自己的传感器重新标定。2. 压力与温度信号链从传感器输出到 ADC 和单总线读数值2.1 示波法还是柯氏音法课设为什么选了阈值检测电子血压计临床常用的是示波法袖带放气过程中脉搏波振荡幅度先增大后减小包络峰值对应平均压峰值左侧某一比例点为收缩压右侧为舒张压。柯氏音法需要麦克风或听诊头而且对充放气速度很敏感课程设计里的硬件平台通常不具备稳定采集条件。所以这套工程的代码在放气—检测—显示这条流程上做了明显简化先充到固定压力再慢放气把 ADC 读到的压力序列里幅度差最大的位置当做脉搏波事件再根据经验系数折算收缩压和舒张压。仿真阶段不会有真实脉搏用电压源模拟特定波形也能跑通这一点在后面的调试章节会再提。这样选择的好处是算法代码量小51 单片机完全跑得动坏处是换成不同袖带和压力传感器后系数必须重新标定否则读数会偏移。2.2 压力传感器与温度传感器常见型号和信号特点压力传感器常见型号是 MPX5050GP量程 0~50 kPa5V 供电时零位输出约 0.2V满量程约 4.7V。血压测量范围通常在 0~250 mmHg1 mmHg 约等于 0.133 kPa所以 120 mmHg 对应约 16 kPa此时传感器输出电压约 0.2 16 / 50 × 4.5 ≈ 1.64V。这个电压要经过运放放大和直流偏置后送进 ADC否则直接接单片机内置 ADC 会丢失低位分辨率。温度部分常见 DS18B20单总线数字输出不需要 ADC但时序要求严格也有课设直接用 LM35 加 ADC 通道省去单总线协议。两者各有取舍DS18B20 测温精度高、代码稍长LM35 电路简单但要占用一路 ADC并且 5V 供电下 100℃ 时输出 1V需要软件换算。信号常见型号输出形式接口需要电路血压压力MPX5050GP模拟电压 0.2~4.7VADC 引脚运放、偏置、去耦体温DS18B20单总线数字普通 IO 加 4.7k 上拉无源上拉即可体温替代LM35模拟电压 10mV/℃ADC 引脚跟随器或直接连接我一般会按“压力模拟 温度数字”的方案设计压力信号走 ADC温度信号走单总线这样两个信号链互不干扰调试时也能分开定位。注意压力传感器供电必须单独并联 0.1μF 和 10μF 电容避免充气泵启动瞬间电源跌落导致 ADC 跳动。2.3 温度读取实现DS18B20 时序与 C 代码DS18B20 单总线协议分三个步骤复位、写入 ROM 命令、读写数据。课设中一般只有一个传感器直接发送跳过 ROM 的 0xCC 命令然后启动温度转换 0x44等待 750ms再读取暂存器的 0xBE 命令。以下代码是初始化函数放在 Keil4 的 ds18b20.c 中。sbit DQ P3^7; // 初始化DS18B20返回0表示存在1表示未检测到 uint8_t ds18b20_reset(void) { uint8_t presence 1; DQ 0; // 主机拉低总线 DelayUs(480); // 至少480us产生复位脉冲 DQ 1; // 释放总线 DelayUs(70); // 等待器件响应 presence DQ; // 若器件存在会拉低60~240us DelayUs(400); // 补足时序 return presence; }这段代码里的 DelayUs 必须精确我用 Keil 软件延时或定时器实现。presence DQ必须在释放总线后 60~240us 窗口内读取如果提前读会误判为不存在。初始化成功后再从总线读取温度的两个字节低字节是高四位为符号位的补码换算成十进制温度时要注意负温度处理。实际项目中 DS18B20 的供电最好用外部 3.3V而不是从单片机 VCC 直接拉否则长导线在转换大电流时会引起总线误动作。3. 系统硬件模块与 Proteus 建模LCD 显示、按键切换和电源处理怎么搭3.1 主控最小系统和电源模块主控芯片在这套工程里用的是 51 内核单片机仿真文件对应 AT89C51如果要做实物我一般会换成 STC12C5A60S2因为它内置 10 位 ADC可以省掉外扩 ADC0809 的连线。最小系统包含 12MHz 晶振、两个 30pF 负载电容、10k 上拉复位电路和电源滤波电容。电源模块是整个设计的薄弱点泵和阀启动电流约 300mA直接和单片机共用一只 7805 会拉低模拟电压导致压力采样跳动。实操时建议模拟部分和数字部分分开走线在压力传感器电源引脚处加 LC 滤波泵和阀用 PNP 三极管或 NMOS 驱动并在电机两端反并联二极管吸收浪涌。Proteus 仿真不需要这些细节但实物调试时不去做这一层很容易出现“液晶乱码、压力值随机波动”的问题。单片机最小系统的复位脚还要接一个 10uF 电容到 VCC按下复位键时低电平保持 10ms 左右705 周期复位信号才有效。3.2 LCD1602 显示驱动与按键切换显示模块用 LCD16028 位数据线接 P0 口RS 接 P2.0RW 接 P2.1E 接 P2.2。为了省 IO可以改成 4 线模式但课程设计里为了看明白时序多数工程保留 8 线全接。按键切换“血压”和“体温”两种模式我把按键接在 P3.2 外部中断引脚下降沿触发用中断标志变量切换模式。这样主循环不需要反复扫描按键也不会阻塞 ADC 采样。以下是写命令和写数据函数。#define LCD_RS P2_0 #define LCD_RW P2_1 #define LCD_E P2_2 #define LCD_DATA P0 void lcd_write_cmd(uint8_t cmd) { LCD_RS 0; // 命令模式 LCD_RW 0; // 写模式 LCD_DATA cmd; // 送入命令字节 LCD_E 1; DelayUs(50); LCD_E 0; // 下降沿锁存 } void lcd_write_data(uint8_t dat) { LCD_RS 1; // 数据模式 LCD_RW 0; LCD_DATA dat; LCD_E 1; DelayUs(50); LCD_E 0; }LCD 的 E 引脚下降沿才写入代码里先置 1 再清 0中间延时不能太短否则 P0 端口数据还没稳定就被锁存。每次写完命令后要等待 40us 以上清屏命令则需要 1.5ms。按键中断里我一般只改一个mode_flag不在中断函数中写 LCD避免中断里耗时过长影响 DS18B20 的时序和压力采样。按键消抖放在主循环每 10ms 检查一次这样能把 5ms 以内的毛刺滤掉同时不会出现按一下触发两次切换的情况。3.3 Proteus 仿真中的传感器替代方案电压源模拟压力曲线Proteus 里没有真实的 MPX5050GP 模型常见做法是用电位器或 RV1 可变电阻分压再经过一个电压跟随器接到 ADC 输入。这套工程的体温血压.DSN里也是这个思路压力传感器位置放一个 0~5V 的交互式电压源温度传感器用 DS18B20 仿真模型。调电压时打开 Proteus 的 “Interactive Voltage Control” 小窗口手动输入电压值观察液晶上的血压变化。充气泵和电磁阀分别用直流电机和开关代替只是为了看动作时序不参与算法计算。下面是仿真时需要放置的主要元件清单元件名与实际库一致元件Proteus 关键字数量用途单片机AT89C51 或 STC89C521主控LCD 液晶LM016L1显示温度传感器DS18B201测温压力模拟POT-HG1模拟压力电压运放LM3581电平跟随/放大独立按键BUTTON1切换模式直流电机MOTOR1模拟充气泵POT-HG 在仿真里只能手动拖动无法做到自动变化。想演示完整压力曲线可以在代码里加一个“测试模式”不读 ADC而是用一个数组存预置的 200 个压力点循环输出到 LCD。这样即使没有电压源答辩时也能展示收缩压和舒张压的变化过程。仿真时钟和代码里的 DelayUs 需要匹配系统默认 12MHz 晶振代码里如果按 11.0592MHz 算串口会差 1% 左右普通显示无明显问题但涉及 ADC 采样周期时会累积误差。4. Keil4 工程与软件状态机从 main.c 到可烧录 hex 的测量流程4.1 Keil4 工程文件拆解与编译设置zip 里的文件结构很典型STARTUP.A51是 Keil 自动生成的启动文件负责片内 RAM 清零和堆栈指针初始化main.c是主代码main.hex是编译产物main_uvopt.bak和main_uvproj.bak是工程备份文件。用 Keil4 打开main.uvproj后需要确认两点Target 选项里晶振频率填写 12.0MHzOutput 选项卡勾选 “Create HEX File”否则编译不生成 hexProteus 就加载不了。新建工程时我通常把 AT89C51 或 STC12C5A60S2 的器件库导入。如果芯片型号选错比如把 AT89C51 选成 AT89S51寄存器定义没有差别但烧录时的 ID 校验会失败。下面是一个常见的最小编译流程新建工程保存到独立文件夹添加 main.c、ds18b20.c、lcd1602.c 和 STARTUP.A51在 C/C 选项卡里添加头文件路径编译后查看 Build Output 窗口确认 “0 Error(s), 0 Warning(s)”如果出现 “target not created检查代码里是否有未定义的sbit或串口中断向量重复定义。Keil4 对代码优化等级默认是 8 级我一般改成 0 级调试等算法稳定后再拉高优化避免在优化下出现变量被提前更新的问题。main.c里有大量while循环和延时优化等级过高时空循环会被编译器删除导致实际速度变快血压计算随之中断。4.2 主程序状态机充气、测量、放气和显示血压测量流程不适合写成单线程顺序执行因为充气和放气期间还要同时采样 ADC、检测按键和刷液晶。用状态机可以让每个阶段的分工明确。我把状态定义为 S_IDLE、S_CHARGING、S_MEASURING、S_RELEASE、S_DISPLAY下面是状态表和主循环代码骨架。状态进入条件执行动作跳转条件S_IDLE系统上电显示“PRESS KEY”按键触发S_CHARGING按键按下打开充气泵ADC 采样压力 180mmHgS_MEASURING压力达标记录压力序列压力下降到 40mmHgS_RELEASE采集结束关闭泵打开放气阀压力 5mmHgS_DISPLAY泄压完成计算收缩压/舒张压并显示按键切换体温void main_loop(void) { switch (state) { case S_IDLE: if (start_flag 1) { pump_on(); state S_CHARGING; } break; case S_CHARGING: press read_pressure_adc(); if (press 180) // 目标压力阈值 { pump_off(); valve_off(); state S_MEASURING; sample_index 0; } break; case S_MEASURING: sample_buf[sample_index] read_pressure_adc(); if (sample_index 200) state S_RELEASE; break; case S_RELEASE: valve_on(); DelayMs(100); valve_off(); calc_blood_pressure(sample_buf, 200); state S_DISPLAY; break; case S_DISPLAY: display_result(); break; } }注意S_CHARGING里的read_pressure_adc()返回的是电压值我把它换算成 mmHg 再和阈值比较。换算公式是mmHg (adc_voltage - 0.2) / 0.09因为 1kPa 电压增量约 0.09V1kPa 约 7.5mmHg。不同传感器这个系数不一样MPX5050GP 的典型灵敏度是 0.09V/kPa温度变化还会影响零位所以实物上应当先在没有压力时读一次零点电压再在测量结果里减去。状态机里延时 100ms 是等放气阀完全开启实际项目可能改成检测阀门的限位开关以便在阀卡住时及时停止。计算血压前要先关闭状态切换否则测量中途按键会把液晶切到体温模式数据覆盖导致结果错乱。4.3 收缩压和舒张压的计算从压力序列里找脉搏波课设版算法不需要真正的傅里叶分析。常见做法是把 ADC 序列做一阶差分也就是diff[i] buf[i] - buf[i-1]然后找出连续正负变化形成的脉冲。脉搏波出现时袖带压力下降曲线会叠加一个小的波动差分后波动的幅度明显大于放气本身的斜率变化。为了抗抖动我一般给差分序列设一个自适应阈值先取序列中最大的差分值max_diff阈值设为max_diff * 0.4。从压力高到低扫描每次跨过阈值就记录当前压力值这就是一次脉搏波事件。把所有事件对应的压力值存放在pulse_press[]数组最后取最大值作为收缩压参考点取最小值作为舒张压参考点。uint8_t detect_pulses(uint16_t *buf, uint16_t *pulse_press, uint8_t len) { uint8_t i, n 0; int16_t max_diff 0; int16_t diff; for (i 1; i len; i) { diff (int16_t)buf[i] - (int16_t)buf[i - 1]; if (diff 0) diff -diff; if (diff max_diff) max_diff diff; } if (max_diff 30) return 0; // 无脉搏波可能袖带漏气 for (i 1; i len; i) { diff (int16_t)buf[i] - (int16_t)buf[i - 1]; if (diff 0) diff -diff; if (diff (uint16_t)(max_diff * 0.4)) { pulse_press[n] buf[i]; i 2; // 跳过脉冲尾部避免重复计数 } } return n; }max_diff * 0.4是用 40% 峰值作为自适应阈值能排除放气下降沿本身造成的慢变差分。i 2是常见跳变点目的是跳过同一个脉搏波里的二次抖动。最终把pulse_press[]的首位元素拿来显示再乘一个修正系数。这套代码在仿真里用一段叠加了正弦波的斜坡电压就能跑出曲线但在真实袖带上脉搏波幅度会随压力变化阈值算法会受到袖带松紧影响。更可靠的做法是记录每个脉搏波对应的峰值和相位但那是实际项目的后续工作课设里能显示出合理范围往往就够了。5. 仿真调试与参数标定让 Proteus 里的血压计接近实物的四个关键点5.1 晶振频率和代码延时不一致Proteus 默认单片机晶振 12MHz而 Keil 代码里如果用DelayMs(100)做 100ms 延时内部循环次数必须按 12MHz 计算。如果复制了网上 11.0592MHz 的延时函数实际延时变成约 108ms充气时间虽然长一点但 DS18B20 的 750ms 转换时间会被压缩温度读出偶尔变成 85℃。检查办法是编译后看仿真左下角时间轴用示波器观察一个 IO 的翻转周期再对照代码里的DelayMs。5.2 ADC 参考电压和传感器满量程匹配STC12C5A60S2 内置 ADC 参考电压是 VCC也就是 5V。MPX5050GP 满量程 4.7V 正好卡在量程边缘但压力超过 50kPa 时输出会超过 5V 或靠近 VCC读取值会有截断。我一般把传感器 VCC 接 4.5V 稳压管降一档或者用电阻分压把满量程压到 4.2V 再送 ADC。Proteus 里直接改电压源数值不用改动代码。5.3 按键消抖不要阻塞 ADC 采样在S_MEASURING期间每 10ms 一次的按键消抖延时会导致采样间隔不均匀压力波形出现锯齿。更好的方法是把按键检测放到定时器中断里中断每 5ms 置一个标志主循环只在sample_index为空时才扫描。也就是说状态机的每个状态不能随意调用DelayMs遍历按键。修改后可以在测量中途按键等测量完成后再切换到体温显示。5.4 验证技巧用恒定电压源做单点标定把 Proteus 里的压力电压源设成 1.64V对应 120mmHg观察 LCD 是否显示 120 附近。如果偏大说明零位电压 0.2V 没有在换算公式里减掉。下面这个简化代码可以直接烧录测试uint16_t voltage_to_mmhg(uint16_t adc_value) { uint32_t mv (uint32_t)adc_value * 5000UL / 1024UL; // 10位ADC uint32_t mmhg (mv - 200UL) * 100UL / 90UL; // 0.2V0, 0.09V/kPa return (uint16_t)mmhg; }10 位 ADC 的满量程是 0~1023对应 0~5000mV。mv - 200先减去零位输出再除以 0.09V 得到 kPa最后乘以 7.5 得到 mmHg合并后就是 100/90。给这个函数输入 1024 的一半时得到约 611mmHg显然超出传感器量程说明电压源设置不能超过 4.7V。建议把电压从 0.2V 到 4.0V 每隔 0.1V 打一次点记录 LCD 读数画一条直线看线性度如果读数呈现弯曲多半是 Proteus 的电位器模型没有接成线性分压。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。