基于STM32的心电采集系统设计

一、系统概述

心电采集系统通过电极阵列 采集人体心电信号(ECG),经信号调理 (放大、滤波)后,由STM32微控制器 进行模数转换(ADC)数字滤波特征提取 (如心率、QRS波),最终实现实时显示数据存储无线传输 。系统需满足高增益(1000倍以上)低噪声(<1μV)抗干扰(工频/肌电噪声) 要求,适用于便携式监护仪远程医疗运动健康等场景。

二、系统架构与硬件设计

1. 系统架构

微弱信号 mV级
放大滤波后信号
数字信号
处理/分析
存储
传输
3.3V
3.3V
3.3V
3.3V
3.3V
3.3V
心电电极
前端调理电路
STM32 ADC
STM32主控
OLED显示
SD卡
蓝牙/Wi-Fi
电源管理

2. 关键硬件组件

模块 型号/参数 功能
主控 STM32F103C8T6(72MHz,12位ADC) 信号采集、滤波、心率计算、控制外设
前端调理 AD8232(仪表放大器,增益1000) 心电放大、带通滤波(0.5-40Hz)
ADC STM32内置12位ADC(1μs转换时间) 模拟信号→数字信号(采样率250Hz)
显示 0.96寸OLED(128×64,I2C) 实时显示ECG波形、心率值
存储 MicroSD卡(SPI接口,8GB) 存储ECG数据(CSV格式)
通信 HC-05蓝牙模块(UART,2.4GHz) 无线传输数据至手机APP
电源 锂电池(3.7V/500mAh)+TP4056充电 系统供电,支持充电与低功耗管理

3. 核心电路设计

(1)前端调理电路(AD8232)
  • 功能 :将心电电极采集的0.5-5mV微弱信号 放大至0-3.3V (STM32 ADC输入范围),同时滤除工频干扰(50Hz)肌电噪声(>100Hz)

  • 电路连接

  • 电极输入:右臂(RA)、左臂(LA)、右腿(RL,参考地)三导联;

  • 输出:AD8232的OUTPUT引脚接STM32的PA0(ADC1通道0);

  • 配置:增益=1000(通过GAIN引脚设置),带宽=0.5-40Hz(内部带通滤波)。

(2)STM32 ADC采集电路
  • 采样率:250Hz(心电信号最高频率100Hz,按Nyquist定理需≥200Hz);

  • 分辨率:12位(4096级量化,满足心电精度需求);

  • 触发方式:定时器TIM2触发(每4ms触发一次ADC转换,对应250Hz);

  • 数据传输:DMA(直接内存访问)将ADC数据自动传输至数组,减少CPU干预。

三、软件设计(C语言实现)

1. 主程序流程

c 复制代码
#include "stm32f10x.h"
#include "ad8232.h"
#include "adc_dma.h"
#include "filter.h"
#include "heart_rate.h"
#include "oled.h"
#include "sd_card.h"
#include "bluetooth.h"

// 系统状态
typedef struct {
  uint8_t is_sampling;    // 采样标志
  uint16_t adc_buffer[250]; // 1秒ADC数据(250Hz×1s)
  float ecg_signal[250];  // 滤波后心电信号
  uint8_t heart_rate;     // 心率值(bpm)
} SystemState;

int main(void) {
  // 1. 初始化硬件
  System_Init();         // 时钟、GPIO、中断
  AD8232_Init();         // 前端调理电路初始化
  ADC_DMA_Init(250);     // ADC+DMA初始化(250Hz采样)
  OLED_Init();           // OLED显示初始化
  SD_Card_Init();        // SD卡初始化
  Bluetooth_Init();      // 蓝牙初始化
  
  SystemState sys_state = {0};
  sys_state.is_sampling = 1;
  
  // 2. 主循环
  while (1) {
    if (sys_state.is_sampling) {
      // 2.1 启动ADC采样(DMA传输)
      ADC_Start_Conversion();
      
      // 2.2 等待采样完成(1秒数据)
      while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
      DMA_ClearFlag(DMA1_FLAG_TC1);
      
      // 2.3 数字滤波(去噪、基线校正)
      for (int i=0; i<250; i++) {
        sys_state.ecg_signal[i] = Filter_Process((float)sys_state.adc_buffer[i]);
      }
      
      // 2.4 心率计算(QRS波检测)
      sys_state.heart_rate = HeartRate_Calculate(sys_state.ecg_signal, 250);
      
      // 2.5 显示与存储
      OLED_Display_ECG(sys_state.ecg_signal, 250);  // 显示ECG波形
      OLED_Display_HR(sys_state.heart_rate);         // 显示心率
      SD_Card_Save_Data(sys_state.ecg_signal, 250);  // 存储至SD卡
      Bluetooth_Send_Data(sys_state.ecg_signal, 250); // 蓝牙传输
      
      // 2.6 低功耗管理(空闲时休眠)
      if (should_enter_sleep()) {
        Enter_Sleep_Mode(1000);  // 休眠1秒
      }
    }
  }
}

2. 关键模块实现

(1)ADC+DMA配置(信号采集)
c 复制代码
// ADC+DMA初始化(250Hz采样,12位分辨率)
void ADC_DMA_Init(uint16_t sample_rate) {
  ADC_InitTypeDef ADC_InitStruct;
  DMA_InitTypeDef DMA_InitStruct;
  TIM_TimeBaseInitTypeDef TIM_InitStruct;
  
  // 1. 使能时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  
  // 2. 配置ADC通道(PA0,ADC1通道0)
  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;  // 模拟输入
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  // 3. 配置ADC
  ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStruct.ADC_ScanConvMode = DISABLE;  // 单通道
  ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;  // 单次转换(由TIM触发)
  ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;  // TIM2触发
  ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStruct.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStruct);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
  ADC_Cmd(ADC1, ENABLE);
  ADC_DMACmd(ADC1, ENABLE);  // 使能ADC DMA
  
  // 4. 配置DMA(ADC1→内存)
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
  DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)sys_state.adc_buffer;
  DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStruct.DMA_BufferSize = 250;  // 250个采样点(1秒)
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  // 16位ADC数据
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;  // 循环模式
  DMA_InitStruct.DMA_Priority = DMA_Priority_High;
  DMA_Init(DMA1_Channel1, &DMA_InitStruct);
  DMA_Cmd(DMA1_Channel1, ENABLE);
  
  // 5. 配置TIM2触发(4ms周期,250Hz)
  TIM_InitStruct.TIM_Period = 72000/250 - 1;  // 72MHz/250=288kHz,周期=288k/250=1152? 修正:72MHz/250Hz=288000,TIM分频后计数
  TIM_InitStruct.TIM_Prescaler = 0;
  TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_InitStruct);
  TIM_OCInitTypeDef TIM_OCInitStruct;
  TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStruct.TIM_Pulse = 1;
  TIM_OC2Init(TIM2, &TIM_OCInitStruct);
  TIM_Cmd(TIM2, ENABLE);
}
(2)数字滤波(去噪与基线校正)

心电信号需滤除50Hz工频干扰基线漂移(<0.5Hz) ,采用IIR陷波滤波+移动平均滤波

c 复制代码
// 50Hz陷波滤波器(IIR)
#define NOTCH_FREQ 50.0f
#define FS 250.0f  // 采样率
#define Q 30.0f    // 品质因数
float notch_filter(float input) {
  static float x1=0, x2=0, y1=0, y2=0;
  float omega = 2 * 3.1415926f*NOTCH_FREQ/FS;
  float alpha = sin(omega)/(2*Q);
  float b0 = 1/(1+alpha);
  float b1 = -2*cos(omega)*b0;
  float b2 = b0;
  float a1 = -2*cos(omega)*b0;
  float a2 = (1-alpha)*b0;
  
  float output = b0*input + b1*x1 + b2*x2 - a1*y1 - a2*y2;
  x2 = x1; x1 = input;
  y2 = y1; y1 = output;
  return output;
}

// 移动平均滤波(窗口大小5)
#define MA_WINDOW 5
float ma_filter(float input) {
  static float buffer[MA_WINDOW] = {0};
  static uint8_t index=0;
  static float sum=0;
  
  sum -= buffer[index];
  buffer[index] = input;
  sum += input;
  index = (index+1)%MA_WINDOW;
  return sum/MA_WINDOW;
}

// 总滤波函数
float Filter_Process(float adc_value) {
  // 1. ADC值→电压(0-3.3V)
  float voltage = (adc_value / 4095.0f) * 3.3f;
  // 2. 去直流偏移(AD8232输出含0.5V偏置)
  voltage -= 0.5f;
  // 3. 陷波滤波(去50Hz工频)
  float notched = notch_filter(voltage);
  // 4. 移动平均滤波(去高频噪声)
  float filtered = ma_filter(notched);
  return filtered;
}
(3)心率计算(QRS波检测)

通过阈值法检测QRS波(心电图中幅度最大的波群),计算相邻QRS波时间间隔,换算为心率:

c 复制代码
// 心率计算(输入:滤波后心电信号,长度N;输出:心率bpm)
uint8_t HeartRate_Calculate(float* signal, uint16_t N) {
  #define THRESHOLD 0.5f  // 检测阈值(根据实际信号调整)
  #define MIN_INTERVAL 0.3f  // 最小RR间期(秒,对应200bpm)
  #define MAX_INTERVAL 2.0f  // 最大RR间期(秒,对应30bpm)
  
  uint16_t peak_indices[10] = {0};  // 存储QRS波位置
  uint8_t peak_count = 0;
  float max_val = 0;
  uint16_t max_index = 0;
  
  // 1. 寻找QRS波峰值(简单阈值法)
  for (int i=1; i<N-1; i++) {
    if (signal[i] > signal[i-1] && signal[i] > signal[i+1] && signal[i] > THRESHOLD) {
      if (peak_count < 10) {
        peak_indices[peak_count++] = i;
      }
    }
  }
  
  // 2. 计算平均RR间期(秒)
  if (peak_count < 2) return 0;  // 无有效峰值
  float rr_sum = 0;
  for (int i=1; i<peak_count; i++) {
    float interval = (peak_indices[i] - peak_indices[i-1]) / FS;  // 间隔(秒)
    if (interval > MIN_INTERVAL && interval < MAX_INTERVAL) {
      rr_sum += interval;
    }
  }
  float avg_rr = rr_sum / (peak_count - 1);
  
  // 3. 计算心率(bpm=60/avg_rr)
  uint8_t hr = (uint8_t)(60.0f / avg_rr);
  return (hr > 200) ? 0 : hr;  // 限幅
}

参考代码 基于STM32的心电采集系统(硬件+软件+上位机+设计报告等) www.youwenfan.com/contentcss/160880.html

四、系统测试与优化

1. 测试指标

参数 指标 测试方法
输入信号范围 0.5-5mV(心电电极) 函数发生器模拟心电信号(0.5-5mV@50Hz)
放大倍数 1000倍(AD8232) 输入1mV信号,测量输出电压(≈1V)
采样率 250Hz 示波器测量ADC触发信号周期(4ms)
心率测量误差 ±5bpm(静息状态) 对比医用ECG仪测量结果
工频抑制比 >40dB(50Hz) 输入50Hz干扰信号,测量输出衰减

2. 优化方向

  • 抗干扰 :使用屏蔽线 连接电极,STM32金属外壳接地,软件增加自适应滤波(如LMS算法);

  • 低功耗 :采样间隙关闭ADC、OLED背光,STM32进入停止模式(电流<10μA);

  • 算法优化 :采用Pan-Tompkins算法(更精确的QRS波检测),提升心率测量精度;

  • 数据存储:压缩ECG数据(如差分编码),延长SD卡存储时间。

五、总结

本设计基于STM32实现了心电信号的采集-滤波-分析-显示全流程,核心亮点:

  1. 前端调理:采用AD8232集成放大滤波,简化电路设计;

  2. 高效采集:ADC+DMA实现250Hz无丢失采样;

  3. 实时处理:数字滤波(陷波+移动平均)与QRS波检测算法实时计算心率;

  4. 便携扩展:支持OLED显示、SD卡存储、蓝牙传输,适用于便携式监护场景。

系统可进一步优化为多导联ECG (增加电极)、云端互联(通过ESP8266接入云平台),满足临床诊断需求。

相关推荐
笨笨饿2 小时前
26_为什么工程上必须使用拉普拉斯变换
c语言·开发语言·人工智能·嵌入式硬件·机器学习·编辑器·概率论
youcans_2 小时前
【STM32-MBD】(18)Clarke / Park 坐标变换链路
stm32·单片机·嵌入式硬件·matlab·代码生成
F137298015572 小时前
WD5208S 非隔离降压功率开关:集成650V MOSFET,220V降12V,5V,700MA
stm32·单片机·嵌入式硬件·51单片机
KOYUELEC光与电子努力加油3 小时前
JAE日本航空电子推出满足汽车市场小型防水最新需求的MX80系列连接器
服务器·科技·单片机·汽车
Zeku3 小时前
虚拟机网络设置
网络·stm32·freertos·linux驱动开发·linux应用开发
记录无知岁月3 小时前
【STM32】HAL库常用外设使用速查
stm32·单片机·cubemx
给点sun,就shine3 小时前
示波器入门
单片机·嵌入式硬件
panamera123 小时前
通信协议SPI、IIC、UART、CAN及编码
单片机·嵌入式硬件
MC_J3 小时前
Keil之在线调试,不用重启即可在线仿真
stm32·单片机