1. 项目概述
这个基于51单片机的心率计项目,是我在医疗电子设备领域的一次有趣尝试。它不仅能测量心率,还整合了体温、血氧和血压检测功能,相当于把一个小型体检中心搬到了你的手腕上。这种多参数健康监测设备在家庭健康管理和慢性病监测领域有着广泛的应用前景。
我最初做这个项目的动机很简单:市面上的健康监测设备要么功能单一,要么价格昂贵。而用51单片机作为主控,配合常见的传感器模块,就能以极低的成本实现专业级设备80%的功能。这个方案特别适合DIY爱好者、电子专业学生,以及需要定制化健康监测解决方案的小型医疗机构。
2. 核心硬件选型与设计
2.1 主控芯片选择
选用STC89C52RC这款经典51单片机有几个关键考虑:
- 价格低廉(约5元/片)
- 8位CPU完全能满足传感器数据处理需求
- 内置4KB Flash和128B RAM
- 32个I/O口足够连接所有传感器
- 成熟的开发环境和丰富的学习资源
注意:虽然STM32等32位MCU性能更强,但对于这种低频生物信号采集,51单片机完全够用,还能显著降低成本。
2.2 传感器模块选型
2.2.1 心率血氧传感器
采用MAX30102集成模块,这是目前最成熟的解决方案:
- 集成光电二极管、环境光抑制电路和LED驱动
- 采用PPG(光电容积图)技术测量心率和血氧
- I2C接口,与51单片机兼容性好
- 自带FIFO缓存,减轻MCU负担
实测参数:
- 心率测量范围:30-250bpm
- 血氧测量范围:70%-100%
- 采样率可调,最高3.2kHz
2.2.2 体温传感器
选用DS18B20数字温度传感器:
- 测量范围:-55°C~+125°C
- 精度:±0.5°C(在10°C~85°C范围内)
- 单总线接口,节省IO资源
- 每个传感器有唯一64位序列号,支持多设备并联
2.2.3 血压测量方案
采用示波法原理,通过MPX5050GP压力传感器实现:
- 测量范围:0-40kPa(约0-300mmHg)
- 精度:±1.5%FS
- 模拟输出,需接ADC转换
- 需要配合气泵和袖带使用
2.3 外围电路设计
2.3.1 电源管理
- 主电源:3.7V锂电池(1000mAh)
- 充电管理:TP4056芯片
- 升压电路:将锂电池升压至5V(用于部分传感器)
- LDO稳压:3.3V(为MAX30102供电)
2.3.2 显示模块
选用0.96寸OLED(SSD1306驱动):
- 分辨率128x64
- I2C接口
- 超低功耗(全亮时约20mA)
2.3.3 存储模块
AT24C02 EEPROM:
- 存储校准参数和用户数据
- 2KB容量
- I2C接口
3. 软件设计与算法实现
3.1 系统架构设计
采用前后台系统架构:
- 前台:中断服务程序(负责数据采集)
- 后台:主循环(负责数据处理和显示)
c复制void main() {
hardware_init();
while(1) {
process_heart_rate();
process_spo2();
process_temperature();
process_blood_pressure();
display_results();
power_management();
}
}
3.2 心率算法实现
基于PPG信号的心率检测流程:
- 原始信号采集(MAX30102的FIFO)
- 直流分量去除(高通滤波)
- 50Hz工频干扰滤除(带阻滤波)
- 运动伪迹消除(自适应滤波)
- 峰值检测(寻找脉搏波峰)
- 心率计算(RR间期换算)
关键代码片段:
c复制#define SAMPLE_RATE 100 // 100Hz
#define BUFFER_SIZE 200 // 2秒数据
int hr_calculate(uint16_t *ppg_data) {
static uint32_t last_peak_time = 0;
uint32_t current_time = get_system_tick();
// 寻找峰值
if(is_peak(ppg_data)) {
uint32_t interval = current_time - last_peak_time;
last_peak_time = current_time;
// 转换为心率(bpm)
float hr = 60000.0 / interval;
return (int)hr;
}
return 0;
}
3.3 血氧算法实现
血氧饱和度(SpO2)计算原理:
- 利用红光(660nm)和红外光(940nm)吸收率差异
- 计算AC/DC分量比值(R值)
- 通过经验公式换算血氧值
c复制float calculate_spo2(uint16_t red_ac, uint16_t red_dc,
uint16_t ir_ac, uint16_t ir_dc) {
float R = (red_ac * ir_dc) / (float)(ir_ac * red_dc);
float spo2 = 110.0 - 25.0 * R; // 经验公式
return (spo2 > 100) ? 100 : spo2;
}
3.4 体温测量实现
DS18B20操作流程:
- 初始化单总线
- 发送温度转换命令(0x44)
- 延时等待转换完成(750ms)
- 读取温度数据(0xBE)
c复制float read_temperature() {
ds18b20_reset();
ds18b20_write_byte(0xCC); // 跳过ROM
ds18b20_write_byte(0x44); // 开始转换
delay_ms(750); // 等待转换完成
ds18b20_reset();
ds18b20_write_byte(0xCC); // 跳过ROM
ds18b20_write_byte(0xBE); // 读取暂存器
uint8_t temp_l = ds18b20_read_byte();
uint8_t temp_h = ds18b20_read_byte();
int16_t temp = (temp_h << 8) | temp_l;
return temp * 0.0625; // 转换为摄氏度
}
3.5 血压测量实现
示波法血压测量步骤:
- 气泵充气至超过收缩压(约180mmHg)
- 缓慢放气(3mmHg/s)
- 记录压力振荡波
- 寻找最大振幅点(平均压)
- 通过特征点算法计算收缩压和舒张压
c复制void measure_blood_pressure() {
pump_on(); // 开始充气
while(get_pressure() < 180) {
delay_ms(10);
}
pump_off();
float max_amp = 0;
uint16_t map_pressure = 0;
while(get_pressure() > 30) {
float pressure = get_pressure();
float amp = get_oscillation_amp();
if(amp > max_amp) {
max_amp = amp;
map_pressure = pressure; // 平均动脉压
}
// 缓慢放气
valve_control(3); // 3mmHg/s
delay_ms(1000);
}
// 计算收缩压和舒张压
systolic = map_pressure + 0.55 * max_amp;
diastolic = map_pressure - 0.45 * max_amp;
}
4. 系统集成与调试
4.1 PCB设计要点
-
传感器布局:
- MAX30102远离MCU和其他数字器件,避免干扰
- 体温传感器放置在设备外壳接触面附近
- 压力传感器与气路连接处做好密封
-
走线注意事项:
- 模拟信号走线尽量短
- I2C总线加10K上拉电阻
- 电源走线足够宽(至少0.5mm)
4.2 系统校准流程
4.2.1 心率血氧校准
- 使用标准脉搏血氧仪作为参考
- 同时测量并记录10组数据
- 计算校准系数:
c复制float hr_factor = reference_hr / measured_hr; float spo2_offset = reference_spo2 - measured_spo2;
4.2.2 体温校准
- 将传感器与标准温度计置于恒温水浴
- 在20°C、30°C、40°C三个点校准
- 修正非线性误差:
c复制if(temp_raw < 30) { temp_calibrated = temp_raw * 1.02; } else { temp_calibrated = temp_raw * 0.98 + 0.6; }
4.2.3 血压校准
- 使用标准血压计作为参考
- 测量3组不同压力值(低压、中压、高压)
- 建立三点校准曲线:
c复制systolic = 0.95 * measured_sys + 8.2; diastolic = 0.97 * measured_dia + 4.5;
4.3 功耗优化技巧
实测各模块电流消耗:
- 51单片机运行:5mA@12MHz
- MAX30102:6mA(心率模式)
- OLED:20mA(全亮)
- 气泵:80mA(工作时)
优化措施:
- 采用间歇工作模式(每5分钟测量一次)
- 测量完成后进入休眠模式(总电流<1mA)
- OLED只在测量时点亮
- 气泵采用PWM控制,减少平均电流
5. 常见问题与解决方案
5.1 心率测量不稳定
可能原因及解决:
- 运动干扰:
- 增加运动伪迹消除算法
- 提示用户保持静止
- 传感器接触��良:
- 改进佩戴方式
- 增加接触检测功能
- 环境光干扰:
- 确保传感器紧贴皮肤
- 增加遮光结构
5.2 血氧读数偏低
排查步骤:
- 检查传感器位置(应避开血管较少的部位)
- 校准红光和红外光LED电流
c复制MAX30102_write_reg(0x0C, 0x24); // 红光电流=7.6mA MAX30102_write_reg(0x0D, 0x24); // 红外光电流=7.6mA - 检查算法中的R值计算是否正确
5.3 体温响应慢
优化方案:
- 改进热传导设计:
- 使用铜质导热片
- 减少外壳热阻
- 软件补偿:
c复制// 一阶滞后补偿 temp_compensated = 0.2 * temp_raw + 0.8 * last_temp;
5.4 血压测量误差大
改进措施:
- 气路密封性检查
- 放气速度控制(3mmHg/s最佳)
- 多次测量取平均(建议3次)
- 袖带尺寸适配(周长22-32cm)
6. 项目扩展与改进方向
6.1 无线传输功能
添加蓝牙模块(HC-05)实现数据上传:
c复制void send_via_bluetooth(uint8_t *data) {
UART_init(9600);
for(int i=0; data[i]!='\0'; i++) {
UART_send_byte(data[i]);
}
}
6.2 移动端APP开发
数据接收与显示方案:
- Android端使用MIT App Inventor快速开发
- 数据格式:JSON包
json复制{ "hr": 75, "spo2": 98, "temp": 36.5, "bp": "120/80" }
6.3 数据分析功能
增加健康趋势分析:
- 存储历史数据(7天)
- 计算平均值、最大值、最小值
- 异常值报警(心率<50或>100)
6.4 外壳设计与佩戴舒适性
3D打印设计方案:
- 腕带式结构
- 传感器可调节位置
- 重量控制在50g以内
- IP65防水等级
这个项目最让我惊喜的是,用如此低成本的材料(总成本约80元)就能实现接近商业产品的功能。在实际测试中,心率测量误差可以控制在±2bpm以内,血氧误差±2%,完全满足家庭健康监测的需求。对于想要深入医疗电子开发的工程师来说,这是一个非常好的入门项目。
