锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

使用 Arduino 测量血氧饱和度

时间:2022-11-20 22:30:00 传感器没5伏正极

我们所经历的,并且在某种意义上仍在经历的冠状病毒疫情,已经把间质性肺炎、肺呼吸机、重症监护和饱和度计等词放在了大家的嘴边。;新闻媒体每天都把东西带进我们家。幸运的是,这些东西对那些不是内部人员或直接涉及病人的人来说一直很奇怪。它让我们意识到我们可能永远不想知道的方面,但就像生活中的任何事件一样,COVID-19 学习和珍惜我们所见所闻的机会。鉴于此事的时事性,我们认为我们将积极评估一种流行的临床设备,因为它似乎在监测 COVID 患者健康状况的主要并发症之一——19,即呼吸衰竭:我们指的是饱和度计,它是一种能检测血液氧合水平的医疗设备,从而检测气体交换的质量和呼吸系统的效率;电子饱和度计的工作原理是分析指尖周围血管的透明度。指尖周围的血管由一束光束投射到手指的反射或交叉。到达光检测二极管的辐射质量表明氧含量,因为血液越黑,氧含量越少,反之亦然,血液越浅(亮红色),氧含量越高.

饱和度以百分比表示,最大值显然是 100%,而高于 92-93% 值很好。当然,检测到的百分比不仅取决于肺的状态,还取决于吸入空气的质量以及是否有可能减少空气中氧气供应的因素。

项目

所以让我们看看它是什么,分析我们展示的设备:为了创建我们建议的饱和度计,这显然是电子的,我们使用血氧计和心率探测器,基于集成的分线板上的光反射MAX30100;确切地说,我们谈论的是一种用于脉搏血氧仪的传感器,它能以非侵入性和组合的方式测量血液中与氧气结合的血红蛋白的量,以及通过脉搏血氧饱和度变化的心跳频率。血管直径。

传感器通过 I2C 总线传输饱和度数据和血脉数据(这将能够绘制图形类型的心电图,并推断心跳频率),因此我们使用它 Arduino 板获取这些信息,处理它们,并将它们转换为适合控制的小型信息 IPS 我们将在顶部看到显示器的格式 ECG(心电图),即使不像心电图仪那样完整,脉搏率在底部左侧(BPM,或者每分钟心跳次数,或者如果你更喜欢盎格鲁-撒克逊术语,那就是每分钟心跳……),右侧为氧饱和度百分比。

氧气和脉搏检测

已安装在分线板上 Maxim IC 你在传感器图 1 中看到的传感器。

与大多数用于指尖的饱和传感器不同,Maxim IC 两个传感器通过将光发射到芯片顶部工作 LED 一种是红色(波长为 660 nm 另一种是红外线(波长为 880 nm 红外发射器):将手指放在上面,部分穿透其中的光被反射,光电二极管捕获的反射光允许血流趋势和氧气百分比(饱和血红蛋白百分比)根据透明度和透明度的变化来确定。

图 1

具体来说,光电二极管产生的电信号发送到低噪声放大器和信号调节器阶段,然后进入模拟信号处理块,允许提取血氧饱和度和心率数据。后者是通过分析心室搏动和释放引起的外周血管扩张和收缩引起的血液流动模式的变化,导致血压升高和降低。

Maxim 当用户的手指不在传感器上时,该组件还具有接近检测传感器上的能量,减少可见光输出。

图 2为MAX30100器件操作示意图。

图2

通过信号处理模块数字信号,然后转换为数字 I2C 总线发送,我们的 Arduino Uno 读取它们,其固件使用特定于传感器的库(称为MAX30100.h),可计算心率和氧饱和度的百分比。

处理后的数据允许准备数据包和命令,然后我们使用这些数据包和命令来控制小型用户界面 OLED 显示屏,即我们将看到面板心脏的血压趋势图(因此脉搏的影响)传感器检测到的心率和饱和度;全部实时更新。

该MAX30100允许用户设置并通过I2C总线和初始化,采样速率,然后样品放置在模拟信号处理器下游的模拟/数字转换器必须执行单元的数量:更高频率的结果在更准确的分析和显示中,但会增加功耗,降低采样率(因此测量的准确性)会降低功耗;这是相当可观的,并代表你想要创建便携式饱和度计的应用程序中的妥协。

完整的电路

看接线图,我们看到了安装Maxim传感器的分线板通过三根线和五根线加地V电源(分别取自GND和Arduino Uno的5V引脚)连接Arduino Uno;三条线分别是I2C总线和INT的SCL和SDA,即开漏中断输出低电平有效,说明有数据可读。SDA 和 SCL 线路也是漏极开路,建议在分线板中提供上拉电阻 4.7 kohm,但端接在内部电源线上。

每条三条线都需要一条 4.7 kohm 上拉电阻到 5 V 正极,因为分线板在工作 5 V,而MAX30100工作在 1.8 和 3.3V 之间;这是因为小板上有一个用于组件的调节器。

因为这个原因 Arduino Uno 内部电压为 5 伏,并且 I/O 在此电压下运行(但仍能读取较低的逻辑) 1 电平),因此移除内部上拉电阻并应用外部连接到 Arduino Uno 5V 线上,如这些页面中建议的接线图所示。

为了显示心率、饱和度和心率轨迹的参数,我们使用了一个微型显示器 TFT/IPS 1.44“对角线 128×128 像素(图形区域为 25.5 x 26.5 毫米宽,所以实际上是正方形)具有串行接口到 SPI 类型巴士。

该显示器从MAX30100传感器接收的数据中接收由 Arduino Uno 草图准备的要显示的数据并显示它们。

为此,固件将 Arduino Uno I/O 初始化为四线 SPI 接口加复位。

该显示器采用全彩 IPS LCD 技术,提供出色的对比度、出色的色深和 ±80° 的宽视角。

其控制电子设备基于久经考验的 ST7735 控制器,配备 SPI 数据接口;Adafruit_ST7735.h 库简化了固件管理。

模块的供电电压在3-5.5V之间,通过底部的8个焊盘进行连接,由于它们的间距为2.54mm,因此可以焊接到普通引脚条上以方便连接。

图3

显示器连接焊盘的含义如下:

GND = 公共地;

VCC = 正电源;

SCL = SPI 时钟;

SDA = SPI 数据线;

RES = 复位;

DC = 数据/命令选择;

CS = 片选信号,逻辑 0 有效;

BLK = 背光控制。

最后一行允许您打开或关闭背光,如果您不想要背光,可以保持打开状态,而要打开背光,它必须设置为逻辑零。

我们的显示器由 Open Electronics 销售,部件号为 3085-144ST7735。

固件

好吧,现在让我们在草图上花几行来加载 Arduino Uno 以运行我们的饱和度计;为此,我们从 Xtronical (www.xtronical.com/ColourHeartMonitor) 的一个想法中汲取灵感,除了这些页面中解释的内容外,它还允许驱动带有电子设备的压电蜂鸣器,使其每次发出蜂鸣声检测到心跳,就像您正在执行心电图一样。例如,如果我们将仪器用作体育活动的监视器,则蜂鸣声可能很有用。

您可以在清单 1 中找到完整的草图;其中我们注意到包含用于管理分线板传感器的 MAX30100.h 库、用于设置传感器范围的 MAX30100_PulseOximeter.h、用于在显示屏上绘制心率图的图形库 Adafruit_GFX.h 以及Adafruit_ST7735.h 用于通过与 ST7735 控制器的接口与显示器本身进行通信。

清单 1

#include “MAX30100.h” // Libraries required for the
#include “MAX30100_PulseOximeter.h” // MAX30100 range sensors
#include  // Graphics library for drawin on screen
#include  // Hardware-specific library
// Recommended settings for the MAX30100, DO NOT CHANGE!!!!, refer to the datasheet for further info
#define SAMPLING_RATE MAX30100_SAMPRATE_100HZ // Max sample rate
#define IR_LED_CURRENT MAX30100_LED_CURR_50MA // The LEDs currents must be set to a level that 
#define RED_LED_CURRENT MAX30100_LED_CURR_27_1MA // avoids clipping and maximises the dynamic range
#define PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS // The pulse width of the LEDs driving determines
#define HIGHRES_MODE true // the resolution of the ADC
// Create objects for the raw data from the sensor (used to make the trace) and the pulse and oxygen levels
MAX30100 sensor; // Raw Data
PulseOximeter pox; // Pulse and Oxygen
// The following settings adjust various factors of the display
#define SCALING 12 // Scale height of trace, reduce value to make trace height
 // bigger, increase to make smaller
#define TRACE_SPEED 0.5 // Speed of trace across screen, higher=faster 
#define TRACE_MIDDLE_Y_POSITION 41 // y pos on screen of approx middle of trace
#define TRACE_HEIGHT 64 // Max height of trace in pixels 
#define HALF_TRACE_HEIGHT TRACE_HEIGHT/2 // half Max height of trace in pixels (the trace amplitude) 
#define TRACE_MIN_Y TRACE_MIDDLE_Y_POSITION-HALF_TRACE_HEIGHT+1 // Min Y pos of trace, calculated from above values
#define TRACE_MAX_Y TRACE_MIDDLE_Y_POSITION+HALF_TRACE_HEIGHT-1 // Max Y pos of trace, calculated from above values
// Pins to use with the 7735 display
#define TFT_CS 10 // Chop select
#define TFT_RST 9 // Reset
#define TFT_RS 8 // Register select
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_RS, TFT_RST);
 void onBeatDetected()
{
 // beep the beeper
}
void setup()
{
 tft.initR(INITR_144GREENTAB); // initialize a ST7735S chip, for 128x128 display
 tft.fillScreen(ST7735_BLACK);
 tft.setTextSize(1);
 tft.setTextColor(ST7735_WHITE);
 pox.setOnBeatDetectedCallback(onBeatDetected);
 // Initialize the sensor. Failures are generally due to an improper I2C wiring, missing power supply
 // or wrong target chip. Occasionally fails on startup (very rare), just press reset on Arduino
 if (!sensor.begin()) {
 tft.print(“Could not initialise MAX30100”);
 for(;;); // End program in permanent loop
 }
 tft.setCursor(0,0);
 if (!pox.begin()) {
 tft.println(“Could not initialise MAX30100”);
 for(;;); // End program in permanent loop
 }
 // Set up the parameters for the raw data object
 sensor.setMode(MAX30100_MODE_SPO2_HR);
 sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT);
 sensor.setLedsPulseWidth(PULSE_WIDTH);
 sensor.setSamplingRate(SAMPLING_RATE);
 sensor.setHighresModeEnabled(HIGHRES_MODE);
 // Display BPM and O2 titles, these remain on screen, we only erase the trace and the 
 // BPM/O2 results, otherwise we can get some flicker 
 tft.setTextSize(2);
 tft.setCursor(0,86);
 tft.print(“BPM O”);
 tft.setCursor(92,86);
 tft.print(“%”);
 tft.setTextSize(1);
 tft.setCursor(84,94);
 tft.print(“2”); // The small subscriper 2 of O2
 tft.setCursor(1,0); 
 tft.print(“XTronical Health Care”);
 tft.setTextSize(2);
 tft.drawRect(0,TRACE_MIN_Y-1,128,TRACE_HEIGHT+2,ST7735_BLUE); // The border box for the trace 
}
void loop()
{
 int16_t Diff=0; // The difference between the Infra Red (IR) and Red LED raw results
 uint16_t ir, red; // raw results returned in these
 static float lastx=1; // Last x position of trace
 static int lasty=TRACE_MIDDLE_Y_POSITION; // Last y position of trace, default to middle
 static float x=1; // current x position of trace
 int32_t y; // current y position of trace
 uint8_t BPM,O2; // BPM and O2 values
 static uint32_t tsLastReport = 0; // Last time BMP/O2 were checked
 static int32_t SensorOffset=10000; // Offset to lowest point that raw data does not go below, default 10000
 // Note that as sensors may be slightly different the code adjusts this
 // on the fly if the trace is off screen. The default was determined
 // By analysis of the raw data returned 
 pox.update(); // Request pulse and o2 data from sensor
 sensor.update(); // request raw data from sensor
 if(sensor.getRawValues(&ir, &red)) // If raw data available for IR and Red 
 {
 if(red<1000) // No pulse
 y=TRACE_MIDDLE_Y_POSITION; // Set Y to default flat line in middle
 else
 {
 // Plot our new point
 Diff=(ir-red); // Get raw difference between the 2 LEDS
 Diff=Diff-SensorOffset; // Adjust the baseline of raw values by removing the offset (moves into a good range 
for scaling)
 Diff=Diff/SCALING; // Scale the difference so that it appears at a good height on screen
 // If the Min or max are off screen then we need to alter the SensorOffset, this should bring it nicely on screen
 if(Diff<-HALF_TRACE_HEIGHT)
 SensorOffset+=(SCALING*(abs(Diff)-32));
 if(Diff>HALF_TRACE_HEIGHT)
 SensorOffset+=(SCALING*(abs(Diff)-32));
 
 y=Diff+(TRACE_MIDDLE_Y_POSITION-HALF_TRACE_HEIGHT); // These two lines move Y pos of trace to approx middle of display 
area
 y+=TRACE_HEIGHT/4; 
 } 
 if(y>TRACE_MAX_Y) y=TRACE_MAX_Y; // If going beyond trace box area then crop the trace
 if(y126) // If reached end of display then reset to statt
 {
 tft.fillRect(1,TRACE_MIN_Y,126,TRACE_HEIGHT,ST7735_BLACK); // Blank trace display area
 x=1; // Back to start
 lastx=x; 
 }
 if (millis() - tsLastReport > 1000) // If more than 1 second (1000milliseconds) has past
 { // since getting heart rate and O2 then get some bew values
 tft.fillRect(0,104,128,16,ST7735_BLACK); // Clear the old values
 BPM=round(pox.getHeartRate()); // Get BPM
 if((BPM<60)|(BPM>110)) // If too low or high for a resting heart rate then display in red
 tft.setTextColor(ST7735_RED);
 else
 tft.setTextColor(ST7735_GREEN); // else display in green
 tft.setCursor(0,104); // Put BPM at this position
 tft.print(BPM); // print BPM to screen
 O2=pox.getSpO2(); // Get the O2
 if(O2<94) // If too low then display in red
 tft.setTextColor(ST7735_RED);
 else
 tft.setTextColor(ST7735_GREEN); // else green
 tft.setCursor(72,104); // Set print position for the O2 value
 tft.print(O2); // print it to screen
 tsLastReport = millis(); // Set the last time values got to current time
 }
 }
}

结论

好吧,我们相信我们已经解释了正确制作和使用饱和度计所需的一切;以及在家里,作为一种固定的诊断工具,您可以将其安装在橡胶顶针上,在户外运动中使用它,将 Arduino Uno 替换为要放置的 Arduino Micro 或 Nano,例如,放在一个盒子上夹克或应用于衬衫(用细多线电缆连接所有东西)以创建带有集成饱和度计的真实心率监测器,也许能够存储在训练课程中进行的身体活动的轨迹。

用到的模块:

Arduino UNO R3

1.44寸彩色TFT模组ST7735

脉搏血氧仪和心率模块 MAX30100

欢迎关注飞多学堂微博:https://weibo.com/u/7586574130

 欢迎关注我的微信公众号,学习更多电子和示波器使用技巧、知识:

 

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章