手把手教你用STC15单片机+ST188传感器DIY一个心率监测仪(附LabVIEW上位机)
从零打造智能心率监测仪:STC15单片机与ST188传感器的实战指南
在创客圈子里,健康监测设备一直是热门DIY项目。想象一下,用不到百元的成本,自己动手制作一个能实时显示心率、存储历史数据甚至连接电脑分析波形的心率监测仪,是不是很有成就感?本文将带你完整实现这个项目,从元器件选购到LabVIEW上位机开发,每个环节都配有实用技巧和避坑指南。
1. 硬件准备与电路搭建
1.1 核心元器件选型指南
选择适合的元器件是项目成功的第一步。以下是经过实测验证的元器件清单:
| 元器件 | 型号/参数 | 数量 | 备注 |
|---|---|---|---|
| 单片机 | STC15F2K60S2 | 1 | 内置ADC和EEPROM,性价比高 |
| 光电传感器 | ST188 | 1 | 反射式,注意购买带透镜款 |
| OLED显示屏 | 0.96寸I2C接口 | 1 | SSD1306驱动芯片 |
| 运放芯片 | LM358 | 1 | 双运放,用于信号调理 |
| 蜂鸣器 | 有源5V | 1 | 报警提示用 |
| 三极管 | S8550 (PNP) | 1 | 蜂鸣器驱动 |
| 晶振 | 12MHz | 1 | 配合22pF电容 |
| 电阻电容包 | 常用值套装 | 1套 | 含10kΩ、1kΩ等 |
ST188传感器使用技巧:
- 选择带聚光透镜的版本,提高信号质量
- 工作电流建议设置在20-30mA之间
- 传感器与被测部位距离保持在3-5mm最佳
1.2 电路焊接实战要点
电路焊接是DIY过程中最容易出问题的环节。按照以下顺序焊接可降低失误率:
电源模块先行:
- 先焊接USB接口和电源开关
- 用万用表测量各点电压正常后再继续
核心器件焊接:
- STC15单片机建议使用IC座,方便更换
- ST188传感器引脚较细,焊接时间控制在3秒内
信号处理电路:
[ST188输出] → [10kΩ上拉电阻] → [LM358放大电路] → [10μF滤波电容] → [单片机ADC输入]- 运放增益建议设置在50-100倍
- 低通滤波截止频率设为5Hz左右
常见问题:ST188输出信号不稳定 解决方法:检查电源是否稳定,尝试在传感器供电端并联100μF电容
2. 单片机程序开发
2.1 开发环境配置
使用Keil uVision进行STC15开发需要额外步骤:
- 安装STC-ISP烧录软件
- 在Keil中添加STC15器件支持包
- 配置编译选项:
// 内存模式选择Small // 优化等级建议设为Level 2 // 勾选"Create HEX File"
2.2 核心算法实现
心率计算采用峰值检测算法,关键代码如下:
#define SAMPLE_RATE 100 // 100Hz采样率 #define BUFFER_SIZE 200 // 2秒缓存 uint16_t adc_buffer[BUFFER_SIZE]; uint8_t heart_rate = 0; void Timer0_ISR() interrupt 1 { static uint16_t index = 0; adc_buffer[index++] = ADC_Read(0); if(index >= BUFFER_SIZE) index = 0; } void Calculate_HR() { uint16_t max_val = 0, min_val = 1023; uint8_t peak_count = 0; // 寻找波峰波谷 for(uint16_t i=0; i<BUFFER_SIZE; i++) { if(adc_buffer[i] > max_val) max_val = adc_buffer[i]; if(adc_buffer[i] < min_val) min_val = adc_buffer[i]; } // 动态阈值检测 uint16_t threshold = (max_val + min_val) / 2; uint16_t last_val = adc_buffer[0]; uint8_t last_state = (last_val > threshold); for(uint16_t i=1; i<BUFFER_SIZE; i++) { uint8_t current_state = (adc_buffer[i] > threshold); if(current_state && !last_state) { peak_count++; } last_state = current_state; } // 转换为每分钟心跳数 heart_rate = peak_count * 30; // 2秒数据乘以30 }2.3 OLED显示优化
使用U8g2库驱动OLED可大幅简化开发:
#include <U8g2lib.h> U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); void Display_Init() { u8g2.begin(); u8g2.setFont(u8g2_font_6x10_tf); u8g2.setFontRefHeightExtendedText(); u8g2.setDrawColor(1); u8g2.setFontPosTop(); } void Show_HeartRate() { char str[20]; u8g2.clearBuffer(); u8g2.drawStr(0, 10, "Heart Rate Monitor"); sprintf(str, "BPM: %d", heart_rate); u8g2.drawStr(0, 30, str); u8g2.sendBuffer(); }3. LabVIEW上位机开发
3.1 串口通信配置
LabVIEW与STC15通信参数设置:
| 参数 | 值 |
|---|---|
| 波特率 | 9600 |
| 数据位 | 8 |
| 停止位 | 1 |
| 校验位 | None |
| 流控 | None |
数据格式:
[起始符0xAA][数据长度][心率数据][波形数据...][校验和]3.2 波形显示实现
使用LabVIEW的波形图表控件显示实时心率波形:
前面板设计:
- 添加Waveform Chart控件
- 设置X轴范围为10秒
- Y轴范围设为0-1023(对应ADC原始值)
程序框图代码:
[VISA资源] → [属性节点(设置波特率)] → [While循环] → [VISA读取] → [解包数据] → [波形图表]
性能优化技巧:设置每次读取100字节,使用队列处理数据
3.3 数据存储功能
将采集的数据保存为TDMS格式:
- 创建文件路径
- 设置文件写入属性:
[创建TDMS文件] → [添加通道组] → [添加波形通道] - 循环写入数据
4. 系统调试与优化
4.1 信号质量提升技巧
硬件层面:
- 在ST188供电端增加LC滤波电路
- 使用铜箔包裹传感器线缆减少干扰
- 调整运放反馈电阻优化信号幅度
软件层面:
// 数字滤波算法示例 #define FILTER_DEPTH 5 uint16_t Digital_Filter(uint16_t raw) { static uint16_t buffer[FILTER_DEPTH] = {0}; static uint8_t index = 0; uint32_t sum = 0; buffer[index++] = raw; if(index >= FILTER_DEPTH) index = 0; for(uint8_t i=0; i<FILTER_DEPTH; i++) { sum += buffer[i]; } return sum / FILTER_DEPTH; }
4.2 常见问题排查表
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| OLED不显示 | I2C地址错误 | 尝试0x3C或0x3D |
| 心率值跳动过大 | 信号干扰或接触不良 | 检查传感器连接,增加滤波 |
| LabVIEW接收数据乱码 | 波特率不匹配 | 检查双方波特率设置 |
| 蜂鸣器不响 | 三极管引脚接反 | 确认S8550引脚对应关系 |
| 上位机波形卡顿 | 串口缓冲区溢出 | 增加超时设置,优化数据处理 |
4.3 项目扩展方向
蓝牙传输模块:
- 使用HC-05替换有线串口
- 开发手机APP显示心率数据
运动状态识别:
// 简单运动检测算法 if(heart_rate > 100) { Display_Status("运动状态"); } else { Display_Status("静止状态"); }数据云端存储:
- 通过ESP8266上传数据到物联网平台
- 实现长期心率趋势分析
在完成基础功能后,尝试用3D打印一个外壳,将设备佩戴在手腕上实测。实际测试中发现,手指测量时信号最稳定,手腕测量需要适当增加传感器压力。整套系统电流约50mA,使用500mAh的锂电池可连续工作10小时��上
