血氧感測儀
// 注意事項: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(); // 進行下一筆值讀取
}
}
}