使用 Arduino 测量血氧饱和度
?
我們所經歷的,并且在某種意義上仍在經歷的冠狀病毒疫情,已經把間質性肺炎、肺呼吸機、重癥監護和飽和度計等詞放在了大家的嘴邊。;?新聞媒體每天都會帶入我們家中的東西,幸運的是,對于那些不是內部人員或直接涉及患者的人來說,這些東西一直是陌生的。它讓我們意識到了我們可能永遠不想知道的方面,但就像生活中的任何事件一樣,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傳感器的分線板通過三根線加地和5V電源(分別取自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 <Adafruit_GFX.h> // Graphics library for drawin on screen #include <Adafruit_ST7735.h> // 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 displaytft.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 Arduinoif (!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 objectsensor.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 O2tft.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 resultsuint16_t ir, red; // raw results returned in thesestatic float lastx=1; // Last x position of tracestatic int lasty=TRACE_MIDDLE_Y_POSITION; // Last y position of trace, default to middlestatic float x=1; // current x position of traceint32_t y; // current y position of traceuint8_t BPM,O2; // BPM and O2 valuesstatic uint32_t tsLastReport = 0; // Last time BMP/O2 were checkedstatic 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 sensorsensor.update(); // request raw data from sensorif(sensor.getRawValues(&ir, &red)) // If raw data available for IR and Red {if(red<1000) // No pulsey=TRACE_MIDDLE_Y_POSITION; // Set Y to default flat line in middleelse{// Plot our new pointDiff=(ir-red); // Get raw difference between the 2 LEDSDiff=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 screenif(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 areay+=TRACE_HEIGHT/4; } if(y>TRACE_MAX_Y) y=TRACE_MAX_Y; // If going beyond trace box area then crop the traceif(y<TRACE_MIN_Y) y=TRACE_MIN_Y; // so it stays withintft.drawLine(lastx,lasty,x,y,ST7735_YELLOW); // Plot the next part of the tracelasty=y; // Save where the last Y pos waslastx=x; // Save where the last X pos wasx+=TRACE_SPEED; // Move trace along the displayif(x>126) // If reached end of display then reset to statt{tft.fillRect(1,TRACE_MIN_Y,126,TRACE_HEIGHT,ST7735_BLACK); // Blank trace display areax=1; // Back to startlastx=x; }if (millis() - tsLastReport > 1000) // If more than 1 second (1000milliseconds) has past{ // since getting heart rate and O2 then get some bew valuestft.fillRect(0,104,128,16,ST7735_BLACK); // Clear the old valuesBPM=round(pox.getHeartRate()); // Get BPMif((BPM<60)|(BPM>110)) // If too low or high for a resting heart rate then display in redtft.setTextColor(ST7735_RED);elsetft.setTextColor(ST7735_GREEN); // else display in greentft.setCursor(0,104); // Put BPM at this positiontft.print(BPM); // print BPM to screenO2=pox.getSpO2(); // Get the O2if(O2<94) // If too low then display in redtft.setTextColor(ST7735_RED);elsetft.setTextColor(ST7735_GREEN); // else greentft.setCursor(72,104); // Set print position for the O2 valuetft.print(O2); // print it to screentsLastReport = 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
?歡迎關注我的微信公眾號,學習更多電子和示波器使用技巧、知識:
?
總結
以上是生活随笔為你收集整理的使用 Arduino 测量血氧饱和度的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编译原理——java 词法分析【有穷自动
- 下一篇: JavaWeb实训项目:基于SSM框架的