血氧感測儀

// 注意事項:1. 手指輕放,勿按壓。 2. 手指盡量不要移動。

#include <Wire.h>

#include "MAX30105.h"               //MAX3010x 函式庫


MAX30105 particleSensor;

double avered = 0;

double aveir = 0;

double sumirrms = 0;

double sumredrms = 0;

double SpO2 = 0;

double ESpO2 = 90.0;                // 初始值

double FSpO2 = 0.7;                 //SpO2 預估參數

double frate = 0.95;                // 消除 IR/ 紅色 LED 值的低雜訊的低通濾波器以消除交流分量,越小濾掉的雜訊越多

int i = 0;

int Num = 30;                       // 取樣 30 次才計算 1 次

#define FINGER_ON 7000              // 紅外線最小量(判斷手指有沒有放上感測器)

#define MINIMUM_SPO2 90.0           // 血氧最小量

double Spo2_re[30]; // 取樣30次修改時要一起修改此處

double Spo2_ave = 0;

int num = 0; 


void setup() {

  Serial.begin(9600);

  delay(2000); 

  Serial.println("======== 血氧測試儀 ========");

  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) 

  {

    Serial.println(" 找不到血氧感測器,請檢查線路 !");

    while (1);

  }

  particleSensor.setup(); 

  particleSensor.enableDIETEMPRDY();

  particleSensor.setPulseAmplitudeRed(0x0A);  // 紅色 LED 燈亮

  particleSensor.setPulseAmplitudeGreen(0);   // 綠色 LED 燈熄滅

  Serial.println("***** 請將手指放上血氧感測器 *****");

}


void loop() {

  long irValue = particleSensor.getIR();      // 讀取紅外線值,以確認手指是否放上

  if (irValue > FINGER_ON ) {                 // 手指已放在感測器上

    uint32_t ir, red ;

    double fred, fir;

    particleSensor.check();                   // 檢查傳感器,最多讀取 3 個樣本

    if (particleSensor.available()) {         // 血氧感測器讀取到資料

      i++;

      red = particleSensor.getFIFOIR();       // 讀取紅光

      ir = particleSensor.getFIFORed();       // 讀取紅外線

      fred = (double)red;                     // 轉 double

      fir = (double)ir;                       // 轉 double

      avered = avered * frate + (double)red * (1.0 - frate);// 使用低通濾波器平均紅色電位

      aveir = aveir * frate + (double)ir * (1.0 - frate);   // 使用低通濾波器平均紅外線電位

      sumredrms += (fred-avered) * (fred-avered);           // 紅色電位交替分量的平方和

      sumirrms += (fir-aveir) * (fir-aveir);                // 紅外線電位交替分量的平方和

      if ((i % Num) == 0) {

        double R = (sqrt(sumredrms) / avered) / (sqrt(sumirrms) / aveir);

        SpO2 = -23.3 * (R - 0.4) + 100;

        ESpO2 = FSpO2 * ESpO2 + (1.0 - FSpO2) * SpO2;       // 低通濾波器

        if (ESpO2 <= MINIMUM_SPO2) ESpO2 = MINIMUM_SPO2;    // 限制最小值

        if (ESpO2 > 100) ESpO2 = 99.9;                      // 限制最大值

        sumredrms = 0.0; sumirrms = 0.0; SpO2 = 0;

        i = 0;

        Spo2_re[num] = ESpO2; // 讀取30次產生一次 "."

        Serial.print(".");

        num++;

        if (num == 30){ // 讀取30次後

          Serial.println("OK!");

          for(int ii = 15 ; ii <30 ; ii++){ // 因為前15次不穩定不採取平均,第16次才開始取樣到30做平均

            Spo2_ave = Spo2_ave + Spo2_re[ii]; // Spo2_re[ii]為取樣數值,可以印出參考

          }

          Spo2_ave = Spo2_ave / 15 ;

          Serial.print(" 您的血氧值 (%) = "); Serial.println(Spo2_ave);

          while(1);

        } 

      }

      particleSensor.nextSample();                    // 進行下一筆值讀取

    }

  } 

}