一、系统概述
基于STM32微控制器 ,结合光电传感技术 (MAX30102模块)与心电传感技术 (AD8232模块),实现无创心率检测 与有创心电采集 的双模式数据融合,支持实时显示、无线传输、云端存储 等功能,适用于便携式监护、远程医疗、运动健康等场景。
核心特点:
-
双模式检测:同时支持光电(指尖/手腕)与心电(胸部贴片)两种检测方式,覆盖不同用户需求;
-
高集成度:采用模块化设计,整合传感器、信号处理、控制、显示、通信于一体;
-
智能分析:内置心率变异性(HRV)分析算法,提供睡眠质量、压力水平等健康评估;
-
低功耗:采用STM32低功耗模式(Stop Mode),配合动态电源管理,续航时间>72小时。
二、系统架构与硬件设计
1. 系统架构
I2C
ADC
I2C
UART
SPI
Wi-Fi ESP8266
3.3V
3.3V
3.3V
3.3V
3.3V
3.3V
3.3V
光电传感器 MAX30102
STM32主控
心电传感器 AD8232
OLED显示
蓝牙模块 HC-05
SD卡存储
云平台 OneNET
电源管理 TP4056
2. 关键硬件组件
| 模块 | 型号/参数 | 功能 |
|---|---|---|
| 主控 | STM32F103C8T6(72MHz,12位ADC) | 信号采集、滤波、心率计算、控制外设 |
| 光电传感器 | MAX30102(心率/血氧,I2C) | 无创采集指尖/手腕心率信号 |
| 心电传感器 | AD8232(仪表放大器,增益1000) | 采集胸部心电信号(mV级) |
| 显示 | 0.96寸OLED(128×64,I2C) | 实时显示心率、血氧、心电波形 |
| 通信 | HC-05(蓝牙,UART)/ESP8266(Wi-Fi) | 无线传输数据至手机/云端 |
| 存储 | MicroSD卡(SPI,8GB) | 存储历史数据与异常事件 |
| 电源 | 锂电池(3.7V/500mAh)+TP4056 | 系统供电,支持充电与低功耗管理 |
3. 核心电路设计
(1)光电传感电路(MAX30102)
-
连接:SCL→PB10(I2C2),SDA→PB11(I2C2),INT→PA7(中断,低有效);
-
配置 :采用SpO2模式(同时采集红光与红外光),采样率100Hz,LED脉冲宽度400μs,增益设置为"高"(适应不同肤色);
-
信号调理 :内置环境光抑制 (ALS)与运动伪影抑制(MAP),输出数字信号(通过I2C读取)。
(2)心电传感电路(AD8232)
-
连接:OUTPUT→PA0(ADC1通道0),RA→右臂电极,LA→左臂电极,RL→右腿电极(参考地);
-
配置 :增益=1000(通过
GAIN引脚设置),带宽=0.5-40Hz(内部带通滤波),输出偏置电压=0.5V(适配STM32 ADC输入范围); -
信号调理 :采用三导联设计,减少肌电噪声(EMG)干扰,输出模拟信号(通过ADC采集)。
(3)电源管理电路
-
充电 :采用TP4056锂电池充电芯片,支持5V USB充电,充电电流=500mA;
-
供电 :采用AMS1117-3.3V稳压芯片,将锂电池电压(3.7V)转换为3.3V,供给所有模块;
-
低功耗 :STM32进入Stop Mode(电流<10μA),仅在采集数据时唤醒,延长续航时间。
三、软件设计(C语言实现)
1. 主程序流程
c
#include "stm32f10x.h"
#include "max30102.h"
#include "ad8232.h"
#include "oled.h"
#include "bluetooth.h"
#include "sd_card.h"
#include "algorithm.h"
// 系统状态
typedef struct {
uint8_t mode; // 0:光电模式, 1:心电模式
uint8_t is_sampling; // 采样标志
float hr; // 心率值(bpm)
float spo2; // 血氧饱和度(%)
float ecg_signal[250];// 心电信号(250Hz×1s)
uint8_t hr_valid; // 心率有效标志
uint8_t spo2_valid; // 血氧有效标志
} SystemState;
int main(void) {
// 1. 初始化硬件
System_Init(); // 时钟、GPIO、中断
MAX30102_Init(); // 光电传感器初始化(I2C2)
AD8232_Init(); // 心电传感器初始化(ADC1)
OLED_Init(); // OLED显示初始化(I2C1)
Bluetooth_Init(); // 蓝牙初始化(UART1)
SD_Card_Init(); // SD卡初始化(SPI1)
Algorithm_Init(); // 心率/血氧算法初始化
SystemState sys_state = {0};
sys_state.mode = 0; // 默认光电模式
sys_state.is_sampling = 1;
// 2. 主循环
while (1) {
if (sys_state.is_sampling) {
// 2.1 采集数据(根据模式)
if (sys_state.mode == 0) {
// 光电模式:采集MAX30102数据
MAX30102_Read_Data(&sys_state.hr, &sys_state.spo2, &sys_state.hr_valid, &sys_state.spo2_valid);
} else {
// 心电模式:采集AD8232数据(250Hz,1秒)
AD8232_Read_Data(sys_state.ecg_signal, 250);
// 心电心率计算(QRS波检测)
sys_state.hr = Algorithm_ECG_HeartRate(sys_state.ecg_signal, 250);
sys_state.hr_valid = 1;
}
// 2.2 显示数据
OLED_Display_Data(sys_state.hr, sys_state.spo2, sys_state.ecg_signal, sys_state.mode);
// 2.3 存储数据(SD卡)
SD_Card_Save_Data(&sys_state);
// 2.4 无线传输(蓝牙/ Wi-Fi)
if (sys_state.hr_valid) {
Bluetooth_Send_Data(sys_state.hr, sys_state.spo2);
// ESP8266_Send_To_Cloud(sys_state.hr, sys_state.spo2); // 可选
}
// 2.5 低功耗管理(空闲时休眠)
if (should_enter_sleep()) {
Enter_Sleep_Mode(1000); // 休眠1秒
}
}
}
}
2. 关键模块实现
(1)光电传感器驱动(MAX30102)
c
// MAX30102 I2C地址(写:0xAE,读:0xAF)
#define MAX30102_WRITE_ADDR 0xAE
#define MAX30102_READ_ADDR 0xAF
// 寄存器地址
#define REG_INTR_STATUS_1 0x00
#define REG_FIFO_DATA 0x07
#define REG_MODE_CONFIG 0x09
#define REG_SPO2_CONFIG 0x0A
#define REG_LED1_PA 0x0C
#define REG_LED2_PA 0x0D
// MAX30102初始化
void MAX30102_Init(void) {
// 复位
MAX30102_Write_Reg(REG_MODE_CONFIG, 0x40);
HAL_Delay(100);
// 配置模式:SpO2模式(红光+红外光)
MAX30102_Write_Reg(REG_MODE_CONFIG, 0x03);
// 配置SpO2:采样率100Hz,脉冲宽度400μs,ADC范围4096nA
MAX30102_Write_Reg(REG_SPO2_CONFIG, 0x27);
// 配置LED电流:红光7mA,红外光7mA
MAX30102_Write_Reg(REG_LED1_PA, 0x24);
MAX30102_Write_Reg(REG_LED2_PA, 0x24);
// 使能中断:FIFO满中断
MAX30102_Write_Reg(REG_INTR_ENABLE_1, 0x80);
}
// 读取MAX30102数据(心率/血氧)
void MAX30102_Read_Data(float *hr, float *spo2, uint8_t *hr_valid, uint8_t *spo2_valid) {
uint8_t data[6];
uint32_t red_value, ir_value;
// 读取FIFO数据(6字节:红光3字节+红外光3字节)
MAX30102_Read_Reg(REG_FIFO_DATA, data, 6);
// 解析红光值(18位)
red_value = (data[0] << 16) | (data[1] << 8) | data[2];
red_value &= 0x03FFFF; // 取低18位
// 解析红外光值(18位)
ir_value = (data[3] << 16) | (data[4] << 8) | data[5];
ir_value &= 0x03FFFF; // 取低18位
// 计算心率与血氧(调用算法库)
*hr = Algorithm_PPG_HeartRate(red_value, ir_value, hr_valid);
*spo2 = Algorithm_PPG_SpO2(red_value, ir_value, spo2_valid);
}
(2)心电传感器驱动(AD8232)
c
// AD8232 ADC配置(12位,250Hz)
void AD8232_Init(void) {
ADC_InitTypeDef ADC_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
// 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA0为模拟输入(ADC1通道0)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置ADC1
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; // 单通道
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; // 连续转换
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStruct);
// 配置ADC通道0(PA0),采样时间55.5 cycles
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
// 使能ADC1
ADC_Cmd(ADC1, ENABLE);
// 校准ADC1
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
// 启动ADC转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
// 读取AD8232数据(250Hz,1秒)
void AD8232_Read_Data(float *ecg_signal, uint16_t len) {
for (int i = 0; i < len; i++) {
// 等待ADC转换完成
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
// 读取ADC值(12位)
uint16_t adc_value = ADC_GetConversionValue(ADC1);
// 转换为电压(0-3.3V)
float voltage = (adc_value / 4095.0f) * 3.3f;
// 去直流偏移(AD8232输出含0.5V偏置)
ecg_signal[i] = voltage - 0.5f;
// 启动下一次转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
}
(3)心率/血氧算法(Algorithm.c)
c
// 光电心率计算(PPG,峰值检测法)
float Algorithm_PPG_HeartRate(uint32_t red_value, uint32_t ir_value, uint8_t *valid) {
#define THRESHOLD 0.5f // 检测阈值(根据实际信号调整)
#define MIN_INTERVAL 0.3f // 最小RR间期(秒,对应200bpm)
#define MAX_INTERVAL 2.0f // 最大RR间期(秒,对应30bpm)
static uint16_t peak_indices[10] = {0}; // 存储QRS波位置
static uint8_t peak_count = 0;
static float last_peak_time = 0;
// 1. 寻找峰值(简单阈值法)
if (ir_value > THRESHOLD && ir_value > red_value) { // 红外光信号更强
if (peak_count < 10) {
peak_indices[peak_count++] = HAL_GetTick(); // 记录峰值时间(ms)
}
}
// 2. 计算RR间期(秒)
if (peak_count < 2) {
*valid = 0;
return 0.0f;
}
float rr_interval = (peak_indices[peak_count-1] - peak_indices[peak_count-2]) / 1000.0f;
// 3. 验证RR间期(是否在合理范围)
if (rr_interval < MIN_INTERVAL || rr_interval > MAX_INTERVAL) {
*valid = 0;
return 0.0f;
}
// 4. 计算心率(bpm=60/RR间期)
float hr = 60.0f / rr_interval;
*valid = 1;
return hr;
}
// 心电心率计算(ECG,QRS波检测法)
float Algorithm_ECG_HeartRate(float *ecg_signal, uint16_t len) {
#define QRS_THRESHOLD 0.8f // QRS波阈值(根据实际信号调整)
#define REFRACTORY_PERIOD 0.2f // refractory期(秒)
static uint16_t last_peak_index = 0;
static float last_peak_time = 0;
float max_value = 0.0f;
uint16_t max_index = 0;
// 1. 寻找QRS波峰值(最大值法)
for (int i = 1; i < len-1; i++) {
if (ecg_signal[i] > ecg_signal[i-1] && ecg_signal[i] > ecg_signal[i+1] && ecg_signal[i] > QRS_THRESHOLD) {
// 检查refractory期(避免重复检测)
if ((i - last_peak_index) / 250.0f > REFRACTORY_PERIOD) {
max_value = ecg_signal[i];
max_index = i;
last_peak_index = i;
}
}
}
// 2. 计算心率(bpm=60/ RR间期)
if (max_index == 0) return 0.0f;
float rr_interval = (max_index - last_peak_index) / 250.0f; // 250Hz采样率
float hr = 60.0f / rr_interval;
// 3. 更新last_peak_time
last_peak_time = max_index / 250.0f;
return hr;
}
参考代码 基于STM32的数据采集+心率检测仪 www.youwenfan.com/contentcss/160897.html
四、系统测试与优化
1. 测试指标
| 参数 | 指标 | 测试方法 |
|---|---|---|
| 心率测量误差 | ±3bpm(静息状态) | 对比医用ECG仪测量结果 |
| 血氧测量误差 | ±2%(90-100% SpO2) | 对比指夹式血氧仪测量结果 |
| 心电信号质量 | 信噪比>20dB(0.5-40Hz) | 输入标准心电信号(1mV@10Hz),测量输出 |
| 续航时间 | >72小时(连续采集) | 锂电池(3.7V/500mAh)供电,测量电流 |
| 通信距离 | >10米(蓝牙) | 空旷环境测试 |
2. 优化方向
-
抗干扰 :采用屏蔽线 连接心电电极,STM32金属外壳接地,软件增加自适应滤波(如LMS算法);
-
低功耗 :采样间隙关闭ADC、OLED背光,STM32进入Stop Mode(电流<10μA);
-
算法优化 :采用Pan-Tompkins算法(更精确的QRS波检测),提升心电心率测量精度;
-
数据存储:压缩心电数据(如差分编码),延长SD卡存储时间(>30天)。
五、总结
本设计基于STM32实现了双模式心率检测 (光电+心电),整合了数据采集、信号处理、显示、通信 等功能,具备高集成度、低功耗、智能分析 等特点。系统可扩展为多参数健康监测仪 (如血压、血糖),为远程医疗、运动健康、老年护理等场景提供核心支撑。