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

发布者:快乐舞蹈最新更新时间:2024-01-25 来源: elecfans关键字:STM32  血氧仪  开源设计 手机看文章 扫描二维码
随时随地手机看文章

一、简介

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

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

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

06fa4b72-24ff-11ee-962d-dac502259ad0.jpg

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

071a9094-24ff-11ee-962d-dac502259ad0.jpg

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

072ada12-24ff-11ee-962d-dac502259ad0.jpg

二、功能需求

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

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

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

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

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

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

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

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

三、硬件设计

0744657c-24ff-11ee-962d-dac502259ad0.png

076b27ca-24ff-11ee-962d-dac502259ad0.png

3.1电路分析

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

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

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

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

3.2 MAX30102传感器原理

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

07859790-24ff-11ee-962d-dac502259ad0.png

四、软件设计

4.1软件设计框图

07ac8698-24ff-11ee-962d-dac502259ad0.png

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);

    }

  }

}


五、实物演示

07bab1aa-24ff-11ee-962d-dac502259ad0.jpg

 

07d569aa-24ff-11ee-962d-dac502259ad0.jpg


关键字:STM32  血氧仪  开源设计 引用地址:基于STM32的血氧仪开源设计方案

上一篇:STM32串口通信详解
下一篇:谈谈晶振的原理以及晶振和STM32的关系

推荐阅读最新更新时间:2024-11-09 18:13

STM32 基础系列教程 28 - USB_DFU
前言 学习stm32 USB接口使用,学会用CUBE工具快速创建USB设备工程及调试,关于usb的相关知道请读者提前准备并学习,当然如果不想深究其中原理的话,跟着本文来操作就可以实现基于USB的设备开发了。需要提示的是,stm32在使用usb接口功能是一般需要在DP引脚上上拉一个1.5K电阻到3.3V(部分MCU内部会上拉)。 示例详解 基于硬件平台: STM32F10C8T6最小系统板, MCU 的型号是 STM32F103c8t6, 使用stm32cubemx 工具自动产生的配置工程,使用KEIL5编译代码。 本示例所用的最小系统板原理图: 从本节开始,关于CUBEMX工具及KEIL工具的操作将不再细讲
[单片机]
<font color='red'>STM32</font> 基础系列教程 28 - USB_DFU
STM32基于固件库学习笔记(4)(通用定时器)TIM3定时1S中断
有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIME5 等通用定时器,还有 TIME6 和TIME7 等基本定时器。 通用定时器:是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成;可以用来测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等功能。 STM3 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:  1)16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。  2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。  3)4
[单片机]
STM32中RTC简介及使用方式
STM32H750 的实时时钟是一个独立的 BCD 定时器/计数器,且带了日历功能,它提供一个日历时钟、两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。 此外RTC 还有自动唤醒单元,RTC还可以补偿闰年闰月等等,还有备份区域(BKP)写保护,这些这里不细说了。 RTC 的简化框图 时钟和分频 STM32H750 的 RTC 时钟源(RTCCLK)通过时钟控制器,可以从 LSE、LSI、HSE 时钟三选一,如图所示,有两个预分频器RTC_PRER ck_spre 的时钟可由如下计算公式计算: Fck_spre = Frtcclk/ 图中,ck_apre 也可作为 RTC 亚秒递减计数器(RTC_SSR)的
[单片机]
<font color='red'>STM32</font>中RTC简介及使用方式
STM32学习记录——开发总流程
前期准备 建立标准库模板 步骤: 1、STM官网下载标准库(STM32F10x_StdPeriph_Lib_V3.5.0),解压打开之后 有用的就是Libraries文件夹和Project文件夹,复制相关文件,建立模板。 此文件夹就是工程模板,其中 CMSIS、STM32F10x_StdPeriph_Driver是复制官方Libraries文件夹下的 user中是Project文件夹的 lst放置listing文件 out放置输出文件,即相应的.hex文件 project放置工程文件。 2、新建工程 工程中文件的排版如图 开发流程 1、复制工程模板 2、在user下添加.c文件和.h
[单片机]
<font color='red'>STM32</font>学习记录——开发总流程
stm32独立看门狗和窗口看门狗的区别和联系
STM32有2个看门狗:独立看门狗和窗口看门狗。 独立看门狗IWDG:独立于系统之外,因为有独立时钟,所以不受系统影响的系统故障探测器,主要用于监视硬件错误。 窗口看门狗WWDG:系统内部的故障探测器,时钟与系统相同。如果系统时钟不走了,这个狗也就失去了作用了,主要用于监视软件错误。 简单的讲,看门狗就是检测系统故障的,如果因为系统故障而没有及时喂狗,则引发复位重启。 对于一般的独立看门狗,程序可以在它产生复位前的任意时刻刷新看门狗,但是这样有一个隐患,有可能程序跑乱了又跑回正常的地方,或者跑乱的程序正好执行了刷新看门狗操作,这样的情况下一按的看门狗就检测不出来故障了;但是如果使用窗口看门狗,程序员可以根据程序正常执行的时间设置刷
[单片机]
深度解析stm32编码器模式(一)
1、编码器原理 如果两个信号相位差为90度,则这两个信号称为正交。由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向、根据每个信号脉冲数量的多少及整个编码轮的周长就可以算出当前行走的距离、如果再加上定时器的话还可以计算出速度。 2、为什么要用编码器 从上图可以看出,由于TI,T2一前一后有个90度的相位差,所以当出现这个相位差时就表示轮子旋转了一个角度。但有人会问了:既然都是脉冲,为什么不用普通IO中断?实际上如果是轮子一直正常旋转当然没有问题。仔细观察上图,如果出现了毛刺呢?这就是需要我们在软件中编写算法进行改正。于是,我们就会想到如果有个硬件能够处理这种情况那不是挺好吗? 3、stm32编码器 还是
[单片机]
STM32单片机程序编译及下载配置
前言 当拿到STM32单片机开发板的时候,程序的编译和下载将是我们踏入STM32单片机开发的第一步。本章详细介绍程序的编译和下载。包括:Keil5工程编译、Keil5程序下载、DAPLINK U盘拖拽下载以及串口程序下载。本文以RY-STM32开发板为例,布局图如下所示,开发板自带下载器DAPLink,与计算机通过USB线连接即可。其他类型的开发板编译与下载类似,举一反三即可。 2.1 DAPLink下载器识别 将开发板通过USB线与计算机连接,并打开开发板供电开关,计算机将自动识别下载器。如下图所示,分别识别出:USB串行设备(COM3),USB大容量存储设备,WebUSB:CMSIS-DAP以及一个名称为DAPLINK的
[单片机]
<font color='red'>STM32</font>单片机程序编译及下载配置
STM32让printf通过串口打印及自定义printf函数
在嵌入式系统中,通过串口打印log是非常重要的调试手段,但是直接调用底层驱动打印信息非常不方便,在c语言中一般使用printf打印基本的显示信息,而默认printf的结果不会通过串口发送,所以需要对printf的输出进行重定向。 有时候需要同时从多个串口输出信息,如果仍然想通过printf函数输出信息,就需要自己写printf的实现。 一. 初始化端口和配置 对串口用到的GPIO进行配置,并对串口的参数进行初始化。 二. 宏定义并实现具体的发送函数 代码在编译时首先判断__GNUC__有无定义,之后将PUTCHAR_PROTOTYPE替换成具体的定义。在keil5中,使用fputc函数,所以其实
[单片机]
<font color='red'>STM32</font>让printf通过串口打印及自定义printf函数
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved