基于STM32的数据采集+心率检测仪设计

一、系统概述

基于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实现了双模式心率检测 (光电+心电),整合了数据采集、信号处理、显示、通信 等功能,具备高集成度、低功耗、智能分析 等特点。系统可扩展为多参数健康监测仪 (如血压、血糖),为远程医疗、运动健康、老年护理等场景提供核心支撑。

相关推荐
没有医保李先生2 小时前
mcu中cpu通用和特殊寄存器
单片机·嵌入式硬件
C^h2 小时前
RT thread中断管理学习记录
单片机·嵌入式硬件·学习
桌面运维家2 小时前
Windows 10 USB鼠标失灵:驱动、电源问题排查指南
windows·单片机·计算机外设
思茂信息3 小时前
基于 CST 的方向图可重构天线仿真分析
网络·人工智能·单片机·算法·重构·cst·电磁仿真
senijusene3 小时前
从启动到中断:基于i.MX6UL的ARM Cortex-A7中断系统详解
arm开发·嵌入式硬件
天选硬件打工人3 小时前
第二十九篇:【硬件工程师筑基系列 6-2】样板上电前全检查与安全上电流程 | 避免炸板的核心防线
单片机·嵌入式硬件·安全·硬件架构·硬件工程·射频工程
蓝凌y14 小时前
51单片机之外部中断
c语言·单片机·嵌入式硬件
冲,干,闯15 小时前
矩阵按钮部件
单片机
12.=0.16 小时前
【stm32_2.2】【快速入门】对GPIO解析、外设的初始化和配置、细节分析GPIO
stm32·单片机·嵌入式硬件