#include <MAX3010x.h>
#include "filters.h"
#include <Adafruit_GFX.h> //OLED libraries
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//#include <MAX30105extra.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Sensor (adjust to your sensor type)
MAX30105 sensor;
//MAX30105extra particleSensor;
const auto kSamplingRate = sensor.SAMPLING_RATE_400SPS;
const float kSamplingFrequency = 400.0;
// Finger Detection Threshold and Cooldown
const unsigned long kFingerThreshold = 10000;
const unsigned int kFingerCooldownMs = 500;
// Edge Detection Threshold (decrease for MAX30100)
const float kEdgeThreshold = -2000.0;
// Filters
const float kLowPassCutoff = 5.0;
const float kHighPassCutoff = 0.5;
// Averaging
const bool kEnableAveraging = false;
const int kAveragingSamples = 5;
const int kSampleThreshold = 5;
// limitation of sop2
const int spo2limit =95;
void setup() {
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Start the OLED display
delay(3000);
tone(3,1000); //And tone the buzzer for a 100ms you can reduce it it will be better
delay(1000);
noTone(3);
display.display();
if(sensor.begin() && sensor.setSamplingRate(kSamplingRate)) {
Serial.println("Sensor initialized");
}
else {
Serial.println("Sensor not found");
while(1);
}
}
// Filter Instances
LowPassFilter low_pass_filter_red(kLowPassCutoff, kSamplingFrequency);
LowPassFilter low_pass_filter_ir(kLowPassCutoff, kSamplingFrequency);
HighPassFilter high_pass_filter(kHighPassCutoff, kSamplingFrequency);
Differentiator differentiator(kSamplingFrequency);
MovingAverageFilter<kAveragingSamples> averager_bpm;
MovingAverageFilter<kAveragingSamples> averager_r;
MovingAverageFilter<kAveragingSamples> averager_spo2;
// Statistic for pulse oximetry
MinMaxAvgStatistic stat_red;
MinMaxAvgStatistic stat_ir;
// R value to SpO2 calibration factors
float kSpO2_A = 1.5958422;
float kSpO2_B = -34.6596622;
float kSpO2_C = 112.6898759;
// Timestamp of the last heartbeat
long last_heartbeat = 0;
// Timestamp for finger detection
long finger_timestamp = 0;
bool finger_detected = false;
// Last diff to detect zero crossing
float last_diff = NAN;
bool crossed = false;
long crossed_time = 0;
int lowsopcount =0;
void loop() {
unsigned int val; //定義變量val
unsigned int dat;//定義變量dat
val=analogRead(1);//將val設置為讀取到的A0的數值
dat=(500 * val) /1024; //計算出當前溫度數字dat
auto sample = sensor.readSample(1000);
float current_value_red = sample.red;
float current_value_ir = sample.ir;
// Detect Finger using raw sensor value
if(sample.red > kFingerThreshold) {
if(millis() - finger_timestamp > kFingerCooldownMs) {
finger_detected = true;
}
}
else {
// Reset values if the finger is removed
differentiator.reset();
averager_bpm.reset();
averager_r.reset();
averager_spo2.reset();
low_pass_filter_red.reset();
low_pass_filter_ir.reset();
high_pass_filter.reset();
stat_red.reset();
stat_ir.reset();
finger_detected = false;
finger_timestamp = millis();
}
if(finger_detected) {
current_value_red = low_pass_filter_red.process(current_value_red);
current_value_ir = low_pass_filter_ir.process(current_value_ir);
// Statistics for pulse oximetry
stat_red.process(current_value_red);
stat_ir.process(current_value_ir);
// Heart beat detection using value for red LED
float current_value = high_pass_filter.process(current_value_red);
float current_diff = differentiator.process(current_value);
// Valid values?
if(!isnan(current_diff) && !isnan(last_diff)) {
// Detect Heartbeat - Zero-Crossing
if(last_diff > 0 && current_diff < 0) {
crossed = true;
crossed_time = millis();
}
if(current_diff > 0) {
crossed = false;
}
// Detect Heartbeat - Falling Edge Threshold
if(crossed && current_diff < kEdgeThreshold) {
if(last_heartbeat != 0 && crossed_time - last_heartbeat > 300) {
// Show Results
int bpm = 60000/(crossed_time - last_heartbeat);
float rred = (stat_red.maximum()-stat_red.minimum())/stat_red.average();
float rir = (stat_ir.maximum()-stat_ir.minimum())/stat_ir.average();
float r = rred/rir;
float spo2 = kSpO2_A * r * r + kSpO2_B * r + kSpO2_C;
if(bpm > 50 && bpm < 250) {
// Average?
if(kEnableAveraging) {
int average_bpm = averager_bpm.process(bpm);
int average_r = averager_r.process(r);
int average_spo2 = averager_spo2.process(spo2);
// Show if enough samples have been collected
if(averager_bpm.count() >= kSampleThreshold) {
Serial.print("Time (ms): ");
Serial.println(millis());
Serial.print("Heart Rate (avg, bpm): ");
Serial.println(average_bpm);
Serial.print("R-Value (avg): ");
Serial.println(average_r);
Serial.print("SpO2 (avg, %): ");
Serial.println(average_spo2);
if( average_spo2 >100) average_spo2 = 100;
display.clearDisplay(); //Clear the display
display.setTextSize(2); //Near it display the average BPM you can display the BPM if you want
display.setTextColor(WHITE);
display.setCursor(15,0);
display.println("BPM");
display.setCursor(70,0);
display.println(bpm);
display.setCursor(15,18);
display.println("SpO2");
display.setCursor(70,18);
display.println((int)average_spo2);
display.setCursor(15,36);
display.println("TMP");
display.setCursor(70,36);
display.println((int)dat);
display.display();
if ((int)average_spo2 < spo2limit){
lowsopcount++;
if (lowsopcount >3) {
tone(3,1000); //And tone the buzzer for a 100ms you can reduce it it will be better
delay(1000);
noTone(3);
}
}
if((int)average_spo2 >spo2limit) lowsopcount = 0;
}
}
else {
Serial.print("Time (ms): ");
Serial.println(millis());
Serial.print("Heart Rate (current, bpm): ");
Serial.println(bpm);
Serial.print("R-Value (current): ");
Serial.println(r);
Serial.print("SpO2 (current, %): ");
Serial.println(spo2);
if( spo2 >100) spo2 = 100;
display.clearDisplay(); //Clear the display
display.setTextSize(2); //Near it display the average BPM you can display the BPM if you want
display.setTextColor(WHITE);
display.setCursor(15,0);
display.println("BPM");
display.setCursor(70,0);
display.println(bpm);
display.setCursor(15,18);
display.println("SpO2");
display.setCursor(70,18);
display.println((int)spo2);
display.setCursor(15,36);
display.println("TMP");
display.setCursor(70,36);
display.println((int)dat);
display.display();
if ((int)spo2 < spo2limit){
lowsopcount++;
if (lowsopcount >3) {
tone(3,1000); //And tone the buzzer for a 100ms you can reduce it it will be better
delay(1000);
noTone(3);
}
}
if((int)spo2 >spo2limit) lowsopcount = 0;
}
}
// Reset statistic
stat_red.reset();
stat_ir.reset();
}
crossed = false;
last_heartbeat = crossed_time;
}
}
last_diff = current_diff;
}
}
|