基于STM32的血氧仪开源设计方案

控制/MCU

1878人已加入

描述

基于STM32的血氧仪

一、简介

设计一款基于STM32的血氧仪,用于测量人体血氧饱和度和心率,并将测量结果显示在LCD屏幕上。

本产品由STM32F103C8T6单片机最小系统+MAX30102传感器+LCD显示模块+蜂鸣器模块组成。

1.选择合适的传感器模块,如MAX30102,用于采集红光和红外线信号,并通过单片机IIC总线读取。

蜂鸣器

2.使用STM32微控制器作为主控芯片,配置相应的时钟源和分频系数,开启需要使用的外设时钟,包括GPIO口、ADC、LCD等。

蜂鸣器

3.根据传感器模块和LCD屏幕的接口要求,进行相应的GPIO口配置和LCD初始化操作。

蜂鸣器

二、功能需求

采集功能:能够采集被测者的血氧饱和度和脉率信息,并进行数字化处理。

显示功能:通过LED数码管、LCD显示屏等方式直观地呈现被测者的血氧饱和度和脉率信息。

报警功能:当被测者的血氧饱和度低于设定阈值时,能够及时发出声音或光闪提示,提醒用户。

数据存储功能:能够将采集到的血氧饱和度和脉率数据保存在内部存储器中,并具有查询和导出功能。

操作简单:血氧仪的操作应简单易懂,可以通过触摸方式实现。

尺寸轻巧:血氧仪应小巧便携,方便随身携带,适用于家庭、医院、体育运动等场合。

高精度稳定性:对于血氧饱和度和脉率的精度和稳定性要求较高,需确保数据准确可靠。

高安全性:血氧仪应具有较高的安全性,避免对人体产生不良影响。

三、硬件设计

蜂鸣器

蜂鸣器

3.1电路分析

传感器:血氧仪需要使用光学传感器进行血氧饱和度和脉率的采集。传感器可以采用LED光源和光敏传感器进行测量,对传感器的灵敏度、响应速度等指标进行测试和优化。

信号放大与滤波:为提高信号的稳定性和精度,需要进行信号放大和滤波处理。可以采用运算放大器和低通滤波器进行信号处理,调整增益和截止频率以达到最佳效果。

显示屏:血氧仪需要配备显示屏进行数据显示。选择LCD显示屏作为显示模块。

控制器:血氧仪需要配备控制器进行系统控制和数据处理。选择STM32F103C8T6作为嵌入式微处理器。

3.2 MAX30102传感器原理

两个发光二极管,一个光检测器,携带氧气的红血球能吸收较多红外光(850-1000nm),未携带氧气的红血球则是吸收较多的红外光(600-750nm),利用不同红血球之吸收光谱的原理,来分析血氧饱和度。

蜂鸣器

四、软件设计

4.1软件设计框图

蜂鸣器

4.2 MAX30102驱动编写

4.2.1时钟配置

设置系统时钟源和分频系数,使得STM32能够正常工作。

__HAL_RCC_GPIOB_CLK_ENABLE();

4.2.2外设初始化

开启需要使用的外设时钟,并进行相应的GPIO口、LCD等外设初始化。

  //使用模拟SPI
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

LCD屏初始化

void max30100_init(void)
{
  max30100_Bus_Write(0x06, 0x0b);  //mode configuration : temp_en[3]      MODE[2:0]=010 HR only enabled    011 SP02 enabled


  max30100_Bus_Write(0x01, 0xF0); //open all of interrupt
  max30100_Bus_Write(INTERRUPT_REG, 0x00); //all interrupt clear
  max30100_Bus_Write(0x09, 0x33); //r_pa=3,ir_pa=3
  
max30100_Bus_Write(0x02, 0x00); //set FIFO write Pointer reg = 0x00 for clear it
  max30100_Bus_Write(0x03, 0x00);  //set Over Flow Counter  reg = 0x00 for clear it
  max30100_Bus_Write(0x04, 0x0F);  //set FIFO Read Pointer  reg = 0x0f for   
                      //waitting  write pointer eq read pointer   to   interrupts  INTERRUPT_REG_A_FULL
}

MAX30100驱动程序

单片机通过I2C总线与传感器模块通信,获取血氧、心率等数据。

//血液检测信息更新
void blood_data_update(void)
{
  uint16_t temp_num=0;
  uint16_t fifo_word_buff[1][2];
  
  temp_num = max30100_Bus_Read(INTERRUPT_REG);
  
  //标志位被使能时 读取FIFO
  if (INTERRUPT_REG_A_FULL&temp_num)
  {
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
    //读取FIFO
    max30100_FIFO_Read(0x05,fifo_word_buff,1); //read the hr and spo2 data form fifo in reg=0x05
    
    //将数据写入fft输入并清除输出
    for(int i = 0;i < 1;i++)
    {
      if(g_fft_index < FFT_N)
      {
        s1[g_fft_index].real = fifo_word_buff[i][0];
        s1[g_fft_index].imag= 0;
        s2[g_fft_index].real = fifo_word_buff[i][1];
        s2[g_fft_index].imag= 0;
        g_fft_index++;
      }
    }
    //信息更新标志位
    g_blooddata.update++;
  }
  else
  {
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);
  }
}

硬件初始化模块:包括时钟配置、外设初始化等。

数据处理模块:对采集到的数据进行处理,计算出血氧值和心率等指标,并将其显示在LCD等界面上。

通信模块:可以通过UART方式与其他设备进行通信,将数据上传至PC端进行分析。

4.2.3计算血氧值和心率值

根据采集到的SPO2数据和心率数据,进行相应的计算,得出血氧值和心率值。

4.2.3.1 双波长光吸收比值计算

双波长光吸收比值计算是血氧值计算算法的第一步,它通过传感器模块采集的红光和红外线信号,计算出其在不同波长下的吸收比值。一般需要进行以下几个步骤:

1.获取红光和红外线信号:

temp_num = max30100_Bus_Read(INTERRUPT_REG);

2.血氧饱和度计算:根据双波长光吸收比值和相关系数,计算出血氧饱和度。

    //解平方
    for(int i = 0;i < FFT_N;i++) 
    {
      s1[i].real=sqrtf(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag);
      s2[i].real=sqrtf(s2[i].real*s2[i].real+s2[i].imag*s2[i].imag);
    }

3.计算红光和红外线信号比值:将红光和红外线信号分别除以一个参考值(如环境光强度),得到其相对强度,再将两者相除,得到红光/红外线信号比值。

          //心率计算
      uint16_t Heart_Rate = 60 * SAMPLES_PER_SECOND * 
                            s2_max_index / FFT_N;
      
      g_blooddata.heart = Heart_Rate - 10;
      
      //血氧含量计算
      float sp02_num = (s2[s1_max_index].real * s1[0].real)
                      /(s1[s1_max_index].real * s2[0].real);
      
      sp02_num = (1 - sp02_num) * SAMPLES_PER_SECOND + CORRECTED_VALUE;
      
      g_blooddata.SpO2 = sp02_num;

4.对比值进行滤波

对红光/红外线信号比值进行直流滤波处理,降低采集噪声和干扰。

    //前8次求平均值
  for(int i = 0;i < 8;i++)
  {
    hbag  += s1[g_fft_index - 8 + i].real;
    hboag += s2[g_fft_index - 8 + i].real;
  }
    
  //直流滤波
  hbag_d = dc_filter(hbag,&hbdc) / 8;
  hboag_d = dc_filter(hboag,&hbodc) / 8;
  
  //高度数据
  float hbhight  = 0;
  float hbohight = 0;
  
  //比例与偏置
  hbhight  = (-hbag_d / 40.0) + 5;
  hbohight  = (-hboag_d / 40.0) + 5;
  
  //高度数据幅度限制
  hbhight = (hbhight > 27) ? 27 : hbhight;
  hbhight = (hbhight < 0) ?  0 : hbhight;
  
  hbohight = (hbohight > 27) ? 27 : hbohight;
  hbohight = (hbohight < 0) ?  0 : hbohight;
  
  //将数据发布到全局
  g_BloodWave.Hp = hbhight;
  g_BloodWave.HpO2 = hbohight;

4.2.4显示数据

将计算得到的血氧值和心率值,显示在LCD等界面上

//测试显示血液信息
void tft_test_display(void)
{
  uint8_t str[50];


  if (g_blooddata.display == 1)
  {
    g_blooddata.display = 0;
    
    //显示血氧信息
    sprintf((char *)str,"heart = %3d",g_blooddata.heart);
    Gui_DrawFont_GBK16(8,8,0x00FF,BLACK,str);
    
    //显示心率信息
    sprintf((char *)str,"SpO2 = %3.1f",g_blooddata.SpO2);
    Gui_DrawFont_GBK16(8,26,0x00FF,BLACK,str);
    
    //显示状态信息
    if(g_blooddata.state)
    {
      sprintf((char *)str,"ERROR     ");
      Gui_DrawFont_GBK16(8,44,0xF000,BLACK,str);
    }
    else
    {
      sprintf((char *)str,"NORMAL    ");
      Gui_DrawFont_GBK16(8,44,0x07E0,BLACK,str);
    }
  }
}

五、实物演示

蜂鸣器

 

蜂鸣器

编辑:黄飞

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分