基于STM32的AD8232心电采集装置设计

基于STM32的AD8232心电采集装置设计
目前ADC通道以DMA方式采集到心电数据并且转化为模拟电压值,利用画点函数画出了ECG波形
求下一步心率计算和PR间隙计算的keil代码

全套资料加说明

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    非常感谢您提供更详细的问题描述。针对您的需求,以下是关于心率计算和PR间隙计算的Keil代码:

    心率计算:

    在Keil中,我们可以通过计算心跳间隔(RR间隔)来计算心率。假设我们已经获取了一组连续的心电数据,存储在数组中。我们可以使用以下代码计算心率:

    #define SAMPLE_RATE 200 // 采样率,单位Hz
    #define RR_THRESHOLD 0.5 // RR间隔阈值,单位秒
    
    int i;
    float rr_sum = 0;
    int rr_count = 0;
    
    // 计算RR间隔
    for (i = 1; i < data_len; i++) {
        float current_sample = data[i];
        float previous_sample = data[i-1];
        if ((current_sample > 0) && (previous_sample <= 0)) { // 检测到R峰
            float rr = (i-1)/(float)SAMPLE_RATE; // 计算RR间隔
            if (rr > RR_THRESHOLD) { // 筛除错误值
                rr_sum += rr;
                rr_count++;
            }
        }
    }
    
    // 计算心率
    if (rr_count > 0) {
        float rr_average = rr_sum / rr_count;
        float heart_rate = 60.0f / rr_average;
    }
    

    该代码首先通过循环遍历心电数据数组,并在发现R峰时计算RR间隔。RR间隔的计算是通过相邻两次R峰出现时间的差值(单位为秒)实现的,采样率可以根据实际情况进行更改。这里还设置了RR间隔阈值,用于筛除错误值。最后,通过计算RR间隔的平均值,即可得到心率。

    PR间隙计算:

    PR间隙是指P波开始到R波开始之间的时间间隔,通常用于评估心脏节律的稳定性。下面是计算PR间隙的代码:

    #define SAMPLE_RATE 200 // 采样率,单位Hz
    
    int i;
    float pr_sum = 0;
    int pr_count = 0;
    
    // 搜索P波和R波
    for (i = 1; i < data_len; i++) {
        float current_sample = data[i];
        float previous_sample = data[i-1];
        if ((current_sample > 0) && (previous_sample <= 0)) { // 检测到R峰
            int j = i;
            while ((j > 0) && (data[j] > data[j-1])) { // 搜索P波
                j--;
            }
            if (j > 0) { // 找到了P波
                float pr = (i-j)/(float)SAMPLE_RATE; // 计算PR间隙
                pr_sum += pr;
                pr_count++;
            }
        }
    }
    
    // 计算PR间隙平均值
    if (pr_count > 0) {
        float pr_average = pr_sum / pr_count;
    }
    

    该代码首先在遍历心电数据数组时,搜索R峰,并向前搜索P波。P波的搜索是通过寻找电压上升(即斜率变为正数)的位置实现的。找到P波后,计算P波开始点到R波开始点的时间间隔,即为PR间隙。

    希望以上代码能够对您有所帮助。如果您还有其他问题或需要进一步的帮助,请随时联系我。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

思路分析:设定心电中间幅值,当采集到的值大于这个值是计数加一,只有当出现小于这个幅值后再采集到大于这个幅值计数才再加一。


#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
uint16_t ADC_Value = 0;
#define CRIT (1.8/3.3*4096) //作为计算心跳的电压临界值
void SystemClock_Config(void);
int main(void)
{
  uint8_t buff[1024] = {0};//作为数字信号的存储
  int time = 0;
  int count = 0;
  bool flag = FALSE;
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  while (1)
  {
      if(time == 6000){
          sprintf(buff, "V = %d /minute\r\n", count);
          time = 0;
          count = 0;
          HAL_UART_Transmit(&huart1, buff, strlen(buff), 5000);
      }
      else{
          HAL_Delay(10);
          time++;
          if(ADC_Value > CRIT){
              if(!flag){
                  flag = TRUE;
                  count++;
              }
          }
          else{
              if(flag){ //1.8V作为计算心电电压阈值
                  flag = FALSE;
              }
          }
      }
  }
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if(hadc == &hadc1){
      ADC_Value = HAL_ADC_GetValue(hadc);
  }
}

计算心率和PR间隙计算的示例代码,可在此基础上做修改:


#include "stm32f10x.h"  
#include "ad8232.h"  
  
#define FREQ_REF  (uint16_t)0x8000  // 参考频率  
#define N_SAMPLES 1000             // 采样点数  
  
uint16_t buffer[N_SAMPLES];        // 采样缓冲区  
uint16_t i;  
  
void ComputeHeartRate(void)  
{  
    uint32_t sum = 0;  
    uint32_t count = 0;  
    uint32_t min = 0xFFFF;  
    uint32_t max = 0;  
    uint32_t duration = 0;  
    uint16_t tachogram[N_SAMPLES];  
    uint16_t tachogram_size = 0;  
    uint16_t tachogram_duration = 0;  
    uint16_t tachogram_count = 0;  
    uint16_t tachogram_mean = 0;  
    uint16_t tachogram_stddev = 0;  
    float heart_rate = 0.0;  
  
    // 将采样缓冲区中的数据转换为心率图数据  
    for (i = 0; i < N_SAMPLES; i++)  
    {  
        if (buffer[i] > FREQ_REF)  
        {  
            tachogram[tachogram_size++] = buffer[i];  
        }  
    }  
  
    // 计算心率图中的峰值、谷值、持续时间和平均值、标准差等参数  
    for (i = 1; i < tachogram_size; i++)  
    {  
        if (tachogram[i] > tachogram[i-1] && tachogram[i] > tachogram[i+1])  
        {  
            count++;  
            if (tachogram[i] > max)  
            {  
                max = tachogram[i];  
            }  
            if (tachogram[i] < min)  
            {  
                min = tachogram[i];  
            }  
            duration += (max - min);  
        }  
        else if (tachogram[i] < tachogram[i-1] && tachogram[i] < tachogram[i+1])  
        {  
            count++;  
            if (tachogram[i] < max)  
            {  
                max = tachogram[i];  
            }  
            if (tachogram[i] > min)  
            {  
                min = tachogram[i];  
            }  
            duration += (max - min);  
        }  
    }  
    if (count > 0)  
    {  
        heart_rate = (float)duration / count * FREQ_REF / 60.0;  
    }  
    printf("Heart rate: %.2f bpm\r\n", heart_rate);  
}

心率计算和PR间隙计算的keil示例

#define SAMPLING_FREQ    1000    // 采样频率
#define SAMPLES_PER_BEAT 1500    // 每个心拍所需的样本数

uint32_t ecg_data[SAMPLES_PER_BEAT];  // 心电数据存储数组
uint32_t ecg_data_index = 0;  // 心电数据存储数组的索引

// 计算心率和PR间隙
void calc_hb_pr()
{
    uint32_t i = 0;
    uint32_t hb = 0;  // 心率
    uint32_t pr = 0;  // PR间隙
    uint32_t hb_count = 0;

    for (i = 0; i < (ecg_data_index - SAMPLES_PER_BEAT); i++)
    {
        if (ecg_data[i] > 1000 && ecg_data[i + SAMPLES_PER_BEAT] < 1000) // 判断是否有一个心拍开始
        {
            hb_count++;  // 计数器加1

            if (hb_count > 1)  // 心拍个数超过1个,计算平均心率
            {
                hb = SAMPLING_FREQ * 60 / (i - pr);
            }
            pr = i;  // 记录PR间隙
        }
    }
    if (hb_count == 1)  // 当心拍只有1个时,直接计算心率
    {
        hb = SAMPLING_FREQ * 60 / (pr - 0);
    }
}

基于STM32的AD8232心电采集装置设计中,已经使用DMA方式采集到了心电数据并转化为模拟电压值,然后利用画点函数画出了ECG波形。现在你希望进行下一步的心率计算和PR间隙计算,下面是一个示例的Keil代码,展示如何进行这些计算:

// 定义全局变量
#define ECG_SAMPLE_RATE 200  // 心电采样率为200Hz
#define ECG_BUFFER_SIZE 1000  // 心电数据缓冲区大小

uint16_t ecgBuffer[ECG_BUFFER_SIZE];  // 心电数据缓冲区
uint16_t ecgBufferIndex = 0;  // 当前心电数据索引

// 心率计算函数
uint16_t calculateHeartRate() {
  uint16_t peakCount = 0;
  uint32_t peakSum = 0;
  
  for (int i = 1; i < ECG_BUFFER_SIZE - 1; i++) {
    if (ecgBuffer[i] > ecgBuffer[i-1] && ecgBuffer[i] > ecgBuffer[i+1]) {
      peakCount++;
      peakSum += i;
    }
  }
  
  if (peakCount > 0) {
    uint16_t averagePeakIndex = peakSum / peakCount;
    uint16_t heartRate = ECG_SAMPLE_RATE * 60 / averagePeakIndex;
    return heartRate;
  }
  
  return 0;  // 若未检测到峰值,则返回0表示无法计算心率
}

// PR间隙计算函数
uint16_t calculatePRInterval() {
  // 在心电数据中检测QRS波峰位置,计算相邻峰值之间的样本点数,即为PR间隙
  
  // 假设QRS波峰位置存储在peakIndices数组中,其中包含了每个QRS波峰的索引位置
  
  uint16_t prInterval = 0;
  
  if (peakCount >= 2) {
    prInterval = peakIndices[1] - peakIndices[0];
  }
  
  return prInterval;
}

// 主循环函数
int main() {
  // 初始化代码
  
  while (1) {
    // 等待新的心电数据采样完成
    
    // 获取最新的心电数据
    uint16_t ecgData = ecgBuffer[ecgBufferIndex];
    
    // 更新心电数据缓冲区索引
    ecgBufferIndex = (ecgBufferIndex + 1) % ECG_BUFFER_SIZE;
    
    // 在屏幕上画出心电波形点
    
    // 计算心率
    uint16_t heartRate = calculateHeartRate();
    
    // 计算PR间隙
    uint16_t prInterval = calculatePRInterval();
    
    // 在屏幕上显示心率和PR间隙
    
    // 其他处理代码
    
  }
}

这段代码中,首先定义了一些必要的全局变量,包括心电数据缓冲区和当前数据索引。然后,提供了两个函数:calculateHeartRate用于计算心率,calculatePRInterval用于计算PR间隙。在主循环中,通过获取最新的心电数据,然后调用这两个函数进行心率和PR间隙的计算,并在屏幕上显示相应的结果。

请注意,以上代码只是一个示例,具体的实现可能需要根据你的具体需求和硬件配置进行调整。

引用chatgpt:
为了实现心率计算和PR间隙计算,我们需要首先获取ECG波形数据。以下是一个基于STM32的AD8232心电采集装置设计的基本步骤:

配置ADC通道以DMA方式采集ECG数据。

使用画点函数绘制ECG波形。

从ECG波形中提取心率和PR间隙数据。

计算心率和PR间隙。

在Keil中编写代码实现这些功能。



#include "stm32f10x.h"

#include "stm32f10x_adc.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_rcc.h"

#include "misc.h"



void GPIO_Config(void);

void ADC_Config(void);

void DMA_Config(void);

uint16_t ECG_Buffer[BUFFER_SIZE]; // 存储ECG数据的缓冲区

uint16_t ECG_Count = 0; // 当前读取到的数据点数

uint16_t HeartRate = 0; // 心率

uint16_t PRInterval = 0; // PR间隙

float RPeakValue = 0; // R峰值

float SPeakValue = 0; // S峰值

float TPeakValue = 0; // T峰值

float PPeakValue = 0; // P峰值

float QRSValue = 0; // QRS波幅

float STSegmentValue = 0; // ST段幅度

float TSegmentValue = 0; // T波幅度

float HRVValue = 0; // HRV指数



int main(void)

{

    uint16_t ECG_Data[BUFFER_SIZE]; // 存储ECG数据的数组

    uint32_t ECG_ReadCount = 0; // 当前读取到的数据点数

    uint32_t ECG_TotalCount = 0; // 总数据点数

    uint32_t ECG_StartTime = 0; // ECG信号开始时间

    uint32_t ECG_EndTime = 0; // ECG信号结束时间

    uint32_t ECG_IntervalTime = 0; // ECG信号间隔时间

    uint32_t ECG_HeartRateTime = 0; // 心率计算时间窗口

    uint32_t ECG_PPRIntervalTime = 0; // PR间隙计算时间窗口

    uint32_t ECG_HRVTimeWindow = 0; // HRV指数计算时间窗口

    uint32_t ECG_PPRIntervalCounter = 0; // PR间隙计数器

    uint32_t ECG_HRVIndex = 0; // HRV指数计数器

    uint32_t ECG_PPRIntervalCounterMax = BUFFER_SIZE/4; // PR间隙计数器最大值

    uint32_t ECG_HRVIndexMax = (BUFFER_SIZE/4)-1; // HRV指数计数器最大值

    uint32_t ECG_PPRIntervalCounterMin = BUFFER_SIZE/4*5; // PR间隙计数器最小值

    uint32_t ECG_HRVIndexMin = (BUFFER_SIZE/4)*5-1; // HRV指数计数器最小值

    uint32_t ECG_PPRIntervalCounterThreshold = (BUFFER_SIZE/4)*5/6; // PR间隙计数器阈值

    uint32_t ECG_HRVIndexThreshold = (BUFFER_SIZE/4)*5/6-1; // HRV指数计数器阈值

    uint32_t ECG_PPRIntervalCounterResetValue = (BUFFER_SIZE/4)*5/6*6; // PR间隙计数器重置值

    uint32_t ECG_HRVIndexResetValue = (BUFFER_SIZE/4)*5/6*6-1; // HRV指数计数器重置值

    uint32_t ECG_PPRIntervalCounterMaxLimit = (BUFFER_SIZE/4)*5/6*6*7/8; // PR间隙计数器最大限制值

    uint32_t ECG_HRVIndexMaxLimit = (BUFFER_SIZE/4)*5/6*6*7/8-1; // HRV指数计数器最大限制值

    uint32_t ECG_PPRIntervalCounterMinLimit = (BUFFER_SIZE/4)*5/6*6*7/8*9/10; // PR间隙计数器最小限制值

    uint32_t ECG_HRVIndexMinLimit = (BUFFER_SIZE/4)*5/6*6*7/8*9/10-1; // HRV指数计数器最小限制值

    uint32_t ECG_PPRIntervalCounterOverflowValue = (BUFFER_SIZE/4)*5/6*6*7/8*9/10*11/12; // PR间隙计数器溢出值

    uint32_t ECG_HRVIndexOverflowValue = (BUFFER_SIZE/4)*5/6*6*7/8*9/10*11/12-1; // HRV指数计数器溢出值

    uint32_t ECG_PPRIntervalCounterUnderflowValue = (BUFFER_SIZE/4)*5/6*6*7/8*9/10*11/12*13/14; // PR间隙计数器下溢值