Arduino 血氧心率模塊傳感器數(shù)據(jù)采集

開發(fā)環(huán)境:

Arduino-1.8.5-windows.exe、HXDZ-30102-ACC


硬件設(shè)備:

MAX30102
  • MAX30102是一個集成的脈搏血氧儀和心率監(jiān)測儀生物傳感器的模塊。
  • 它集成了一個紅光LED和一個紅外光LED、光電檢測器、光器件,以及帶環(huán)境光抑制的低噪聲電子電路。
  • 采用一個1.8V電源和一個獨(dú)立的5.0V用于內(nèi)部LED的電源,應(yīng)用于可穿戴設(shè)備進(jìn)行心率和血氧采集檢測,佩戴于手指、耳垂和手腕等處。
  • 標(biāo)準(zhǔn)的I2C兼容的通信接口可以將采集到的數(shù)值傳輸給Arduino、KL25Z等單片機(jī)進(jìn)行心率和血氧計(jì)算。
  • 該芯片還可通過軟件關(guān)斷模塊,待機(jī)電流接近為零,實(shí)現(xiàn)電源始終維持供電狀態(tài)。
  • 集成了玻璃蓋可以有效排除外界和內(nèi)部光干擾,擁有最優(yōu)可靠的性能。
心率血氧傳感器模塊(HXDZ-30102-ACC)

集成了LIS2DH12(ST的三軸加速傳感器,用于記錄運(yùn)動數(shù)據(jù))和MAX30102(血氧和心率檢測記錄)。

傳感器參數(shù):

電路板尺寸:38*16mm
電路板厚度:2.5mm
LED峰值波長:660nm/880nm
LED供電電壓:3.3v~5v
檢測信號類型:光反射信號(PPG)
輸出信號接口:I2C接口(數(shù)字接口)
通信接口電壓:3~5v
工作電路:1.5mA(3.3v 輸入)
心率精確度:+/- 5bpm,+/- 10bpm(動態(tài))
分辨率: 1bpm
采樣率:100Hz(STM32程序)/ 25Hz(arduino程序)

接口說明

VCC:LED電源輸入端,也是I2C總線上拉電平,可以接3.3v或者5v
GND:地線
SCL:I2C總線的時鐘引腳
SDA:I2C總線的數(shù)據(jù)引腳
I_L:LIS2DH12芯片的中斷引腳
I_M:MAX30102芯片的中斷引腳


工作原理

傳統(tǒng)的脈搏測量方法主要有三種:
1、從心電信號中提取
2、從測量血壓時壓力傳感器測到的波動來計(jì)算脈率
3、光電容積法

前兩種會限制病人的活動,長時間使用會加重病患的心理和生理負(fù)擔(dān),而光電容積法在實(shí)際中時普遍使用的一種有效方法,其特點(diǎn):方法簡單、佩戴方便、可靠性高。

光電容積法基本原理:

利用人體組織在血管搏動時造成透光率不同來進(jìn)行脈搏和血氧飽和度測量的。其使用的傳感器由光源和光電變換器兩部分組成,通過綁帶或夾子固定在病患的手指、手腕或耳垂上。光源一般采用對動脈血中氧合血紅蛋白(Hb02)和血紅蛋白(Hb)有選擇性的特定波長的發(fā)光二極管(一般使用660nm附近的紅光和900nm附近的紅外光)。當(dāng)光束透過人體外周血管,由于動脈搏動充血容積變化導(dǎo)致這束光的透光率發(fā)生改變,此時由光電變換器接收經(jīng)人體組織反射的光線,轉(zhuǎn)變?yōu)殡娦盘柌⑵浞糯蠛洼敵觥?/p>

由于脈搏是隨心臟的搏動而周期性變化的信號,動脈血管容積也周期性變化,因此光電變換器的電信號變化周期就是脈搏率。同時根據(jù)血氧飽和度的定義,其表示為:


計(jì)算公式.png
image.png

注意:
1、SaO2 :廣義上的氧飽和度,常指血液樣品中的氧含量對該樣品血液最大氧含量的百分比(SpO2是經(jīng)皮血氧飽和度, 而SaO2是動脈血氧飽和度,二者不同,但是相關(guān)性好,絕對值十分接近)。
2、HbO2:氧合血紅蛋白
3、Hb:還原血紅蛋白

MAX30102本身集成了完整的發(fā)光LED及其驅(qū)動部分,光感應(yīng)和AD轉(zhuǎn)換部分,環(huán)境光干擾消除及數(shù)字濾波部分,只將數(shù)字接口留給用戶,極大地減輕了用戶的設(shè)計(jì)負(fù)擔(dān)。用戶只需要使用單片機(jī)通過硬件I2C或者模擬I2C接口來讀取MAX30102本身的FIFO,就可以得到轉(zhuǎn)換后的光強(qiáng)度數(shù)值,通過編寫相應(yīng)的算法就可以得到心率值和血氧飽和度。

工作原理.png


實(shí)現(xiàn)算法

心率和血氧飽和度算法流程圖:


算法流程圖.png

工作流程

首先連接開發(fā)板串口,波特率需要進(jìn)行必要設(shè)置,奇偶校驗(yàn)位無,上電后,復(fù)位MAX30102,并開始對MAX30102進(jìn)行功能初始化,此時Red LED和 IR LED交替點(diǎn)亮來檢測人體皮膚下血液的搏動和血氧含量(此時可以看到MAX30102有紅光亮起,說明初始化成功)。開發(fā)板將一段時間內(nèi)MAX30102采集的LED反射數(shù)據(jù)存儲在內(nèi)部RAM中,然后分別計(jì)算Red LED和 IR LED的直流成分(DC)和交流成分(AC),最后算出數(shù)值R并通過預(yù)先存儲在兩波峰之間的時間差T來確定,每分鐘心跳數(shù)BPM=60/T。(具體算法原理可以參考AN6409芯片手冊中29~31頁說明)

red和ir是紅色LED,紅外LED的原始數(shù)據(jù),HR表示心率值,HRvalid是心率是否有效標(biāo)識,SPO2是血氧數(shù)值,SPO2valid是血氧首付有效標(biāo)識

血氧模塊與Arduino連接說明:

接口連接說明:


Arduino和HXDZ-30102-ACC接口說明.png

實(shí)際連接圖:


實(shí)物連接圖.png

原理圖管腳說明:


Arduino UNO原理圖.png

實(shí)現(xiàn)代碼

/*
引腳連接關(guān)系
Arduino UNO  <--->  HXDZ-30102/HXDZ-30102-ACC
SDA          <--->   SDA
SCL          <--->   SCL
PIN 10       <--->   INT/I_M
5V           <--->   VCC
GND          <--->   GND
*/
#include <Arduino.h>
#include "algorithm.h"
#include "max30102.h"

//if Adafruit Flora development board is chosen, include NeoPixel library and define an NeoPixel object
#if defined(ARDUINO_AVR_FLORA8)
#include "adafruit_neopixel.h"

//to lower the max brightness of the neopixel LED
#define BRIGHTNESS_DIVISOR 8  
Adafruit_NeoPixel LED = Adafruit_NeoPixel(1, 8, NEO_GRB + NEO_KHZ800);
#endif

#define MAX_BRIGHTNESS 255
#define blinkPin 13

#if defined(ARDUINO_AVR_UNO)
//Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
//To solve this problem, 16-bit MSB of the sampled data will be truncated.  Samples become 16-bit data.
uint16_t aun_ir_buffer[100]; //infrared LED sensor data
uint16_t aun_red_buffer[100];  //red LED sensor data
#else
uint32_t aun_ir_buffer[100]; //infrared LED sensor data
uint32_t aun_red_buffer[100];  //red LED sensor data
#endif
int32_t n_ir_buffer_length; //data length
int32_t n_spo2;  //SPO2 value
int8_t ch_spo2_valid;  //indicator to show if the SPO2 calculation is valid
int32_t n_heart_rate; //heart rate value
int8_t  ch_hr_valid;  //indicator to show if the heart rate calculation is valid
uint8_t uch_dummy;

// the setup routine runs once when you press reset:
void setup() {

#if defined(ARDUINO_AVR_LILYPAD_USB)    
  pinMode(13, OUTPUT);  //LED output pin on Lilypad
#endif

#if defined(ARDUINO_AVR_FLORA8)
  //Initialize the LED
  LED.begin();
  LED.show();
#endif

  pinMode(blinkPin, OUTPUT);  //LED output pin on UNO

  digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
  delay(1000);
  digitalWrite(blinkPin,LOW); // turn on pin 13 LED
  delay(1000);
  digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
  delay(1000);
  digitalWrite(blinkPin,LOW); // turn on pin 13 LED
  delay(1000);
  digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
  delay(1000);
  digitalWrite(blinkPin,LOW); // turn on pin 13 LED
  delay(1000);
  
  maxim_max30102_reset(); //resets the MAX30102
  // initialize serial communication at 115200 bits per second:
  Serial.begin(115200);
  Serial.print(F("MAX30102 begins to start working"));
  pinMode(10, INPUT);  //pin D10 connects to the interrupt output pin of the MAX30102
  delay(1000);
  maxim_max30102_read_reg(REG_INTR_STATUS_1,&uch_dummy);  //Reads/clears the interrupt status register
  maxim_max30102_init();  //initialize the MAX30102
}

// the loop routine runs over and over again forever:
void loop() {
  uint32_t un_min, un_max, un_prev_data, un_brightness;  //variables to calculate the on-board LED brightness that reflects the heartbeats
  int32_t i;
  float f_temp;
  
  un_brightness=0;
  un_min=0x3FFFF;
  un_max=0;
  
  n_ir_buffer_length=100;  //buffer length of 100 stores 4 seconds of samples running at 25sps

  //read the first 100 samples, and determine the signal range
  for(i=0;i<n_ir_buffer_length;i++)
  {
    while(digitalRead(10)==1);  //wait until the interrupt pin asserts
    maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i));  //read from MAX30102 FIFO
    
    if(un_min>aun_red_buffer[i])
      un_min=aun_red_buffer[i];  //update signal min
    if(un_max<aun_red_buffer[i])
      un_max=aun_red_buffer[i];  //update signal max
  }
  un_prev_data=aun_red_buffer[i];
  //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
  maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid); 

  //Continuously taking samples from MAX30102.  Heart rate and SpO2 are calculated every 1 second
  while(1)
  {
    i=0;
    un_min=0x3FFFF;
    un_max=0;

    //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
    for(i=25;i<100;i++)
    {
      aun_red_buffer[i-25]=aun_red_buffer[i];
      aun_ir_buffer[i-25]=aun_ir_buffer[i];

      //update the signal min and max
      if(un_min>aun_red_buffer[i])
        un_min=aun_red_buffer[i];
      if(un_max<aun_red_buffer[i])
        un_max=aun_red_buffer[i];
    }

    //take 25 sets of samples before calculating the heart rate.
    for(i=75;i<100;i++)
    {
      un_prev_data=aun_red_buffer[i-1];
      while(digitalRead(10)==1);
      digitalWrite(9, !digitalRead(9));
      maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i));

      //calculate the brightness of the LED
      if(aun_red_buffer[i]>un_prev_data)
      {
        f_temp=aun_red_buffer[i]-un_prev_data;
        f_temp/=(un_max-un_min);
        f_temp*=MAX_BRIGHTNESS;
        f_temp=un_brightness-f_temp;
        if(f_temp<0)
          un_brightness=0;
        else
          un_brightness=(int)f_temp;
      }
      else
      {
        f_temp=un_prev_data-aun_red_buffer[i];
        f_temp/=(un_max-un_min);
        f_temp*=MAX_BRIGHTNESS;
        un_brightness+=(int)f_temp;
        if(un_brightness>MAX_BRIGHTNESS)
          un_brightness=MAX_BRIGHTNESS;
      }
#if defined(ARDUINO_AVR_LILYPAD_USB)  
      analogWrite(13, un_brightness);
#endif

#if defined(ARDUINO_AVR_FLORA8)
      LED.setPixelColor(0, un_brightness/BRIGHTNESS_DIVISOR, 0, 0);
      LED.show();
#endif

      //send samples and calculation result to terminal program through UART
      Serial.print(F("red="));
      Serial.print(aun_red_buffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.print(aun_ir_buffer[i], DEC);
      
      Serial.print(F(", HR="));
      Serial.print(n_heart_rate, DEC);
      
      Serial.print(F(", HRvalid="));
      Serial.print(ch_hr_valid, DEC);
      
      Serial.print(F(", SPO2="));
      Serial.print(n_spo2, DEC);

      Serial.print(F(", SPO2Valid="));
      Serial.println(ch_spo2_valid, DEC);
    }
    maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid); 
  }
}
 

運(yùn)行效果

初始化:


MAX30102初始化.png

無采集狀態(tài):


無采集數(shù)據(jù).png

image.png

數(shù)據(jù)采集狀態(tài):


數(shù)據(jù)開始采集.png

ps:這里由于整體軟件和硬件的標(biāo)準(zhǔn)沒有像醫(yī)療設(shè)備的標(biāo)準(zhǔn)一樣,所以只是驗(yàn)證性測試。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、前言 這幾年智能穿戴設(shè)備大火,尤其是手環(huán)類,從Apple Watch到榮耀手環(huán),再到不知名的某些品牌,智能穿戴...
    借東西閱讀 729評論 1 2
  • 假期最后一天,選擇與父母在一起,陪他們到紫竹苑踏青賞花。經(jīng)歷了前天的暴雪,昨天的狂風(fēng),今天天氣晴朗,萬里無云,陽光...
    水星2018閱讀 232評論 0 0
  • 感恩,快遞送來的快件 感恩,媽媽給我打電話,媽媽辛苦啦 感恩,老公辛苦賺錢 感恩,兩兒子唱歌給我聽 感恩,鄰居對兩寶好
    梁瓊?cè)A閱讀 66評論 0 0
  • 親愛的,晚安!
    玉潤閱讀 220評論 0 0
  • 皇皇Heddy閱讀 79評論 0 0

友情鏈接更多精彩內(nèi)容