#include <Wire.h>
#include "MAX30105.h"
#include"seeed_line_chart.h" //include the library
#include "spo2_algorithm.h"
MAX30105 particleSensor;
TFT_eSPI tft;
long baseValue = 0;
long HB = 0, oldHB = 0;
int diffHB = 0;
int state = 0;
int th = -500;
#define max_size 50 //maximum size of data
doubles data; //Initilising a doubles type to store data
TFT_eSprite spr = TFT_eSprite(&tft); // Sprite
long lastBeat = 0; //Time at which the last beat occurred
const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
float beatsPerMinute;
int beatAvg;
long delta;
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//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 irBuffer[100]; //infrared LED sensor data
uint16_t redBuffer[100]; //red LED sensor data
#else
uint32_t irBuffer[100]; //infrared LED sensor data
uint32_t redBuffer[100]; //red LED sensor data
#endif
int32_t bufferLength; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid
void setup() {
pinMode(WIO_BUZZER, OUTPUT);
tft.begin();
tft.setRotation(3);
spr.createSprite(TFT_HEIGHT,TFT_WIDTH);
Serial.begin(115200);
Serial.println("Initializing...");
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println("MAX30105 was not found. Please check wiring/power. ");
while (1);
}
particleSensor.setup(); //Configure sensor with default settings
particleSensor.setPulseAmplitudeRed(20); //Turn Red LED to low to indicate sensor is running
particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
}
void loop() {
bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps
//read the first 100 samples, and determine the signal range
for (byte i = 0 ; i < bufferLength ; i++)
{
while (particleSensor.available() == false) //do we have new data?
particleSensor.check(); //Check the sensor for new data
redBuffer[i] = particleSensor.getRed();
irBuffer[i] = particleSensor.getIR();
particleSensor.nextSample(); //We're finished with this sample so move to next sample
Serial.print(F("red="));
Serial.print(redBuffer[i], DEC);
Serial.print(F(", ir="));
Serial.println(irBuffer[i], DEC);
}
//calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
//Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second
while (1)
{
//dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
for (byte i = 25; i < 100; i++)
{
redBuffer[i - 25] = redBuffer[i];
irBuffer[i - 25] = irBuffer[i];
display();
}
//take 25 sets of samples before calculating the heart rate.
for (byte i = 75; i < 100; i++)
{
while (particleSensor.available() == false) //do we have new data?
particleSensor.check(); //Check the sensor for new data
redBuffer[i] = particleSensor.getRed();
irBuffer[i] = particleSensor.getIR();
particleSensor.nextSample(); //We're finished with this sample so move to next sample
//send samples and calculation result to terminal program through UART
Serial.print(F("red="));
Serial.print(redBuffer[i], DEC);
Serial.print(F(", ir="));
Serial.print(irBuffer[i], DEC);
Serial.print(F(", HR="));
Serial.print(heartRate, DEC);
Serial.print(F(", HRvalid="));
Serial.print(validHeartRate, DEC);
Serial.print(F(", SPO2="));
Serial.print(spo2, DEC);
Serial.print(F(", SPO2Valid="));
Serial.println(validSPO2, DEC);
display();
}
//After gathering 25 new samples recalculate HR and SP02
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
}
}
void display() {
spr.fillSprite(TFT_WHITE);
if (data.size() == max_size) {
data.pop();//this is used to remove the first read variable
}
HB = particleSensor.getIR();
diffHB = HB - oldHB;
data.push(diffHB); //read variables and store in data
if(state == 0 && diffHB < th){
delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
rateSpot %= RATE_SIZE; //Wrap variable
//Take average of readings
beatAvg = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++)
beatAvg += rates[x];
beatAvg /= RATE_SIZE;
Serial.println(beatAvg);
state = 1;
analogWrite(WIO_BUZZER, 128);
Serial.println("Beat!!!!!!!");
}else if(state == 1 && diffHB > th){
state = 0;
analogWrite(WIO_BUZZER, 0);
}
//Settings for SpO2
String stSpO2 = " SpO2:";
if(validSPO2){
stSpO2 += spo2;
}else{
stSpO2 += "-";
}
char charSpO2[20];
stSpO2.toCharArray(charSpO2, 20);
auto header = text(0, 0)
.value(charSpO2)
.align(left)
.valign(vcenter)
.width(tft.width())
.thickness(3);
header.height(header.font_height() * 2);
header.draw(); //Header height is the twice the height of the font
//Settings for HeartRate
String stHB = " HeartRate:";
stHB += beatAvg;
char charHB[20];
stHB.toCharArray(charHB, 20);
auto header2 = text(0, header.height())
.value(charHB)
.align(left)
.valign(vcenter)
.width(tft.width())
.thickness(3);
header2.height(header.font_height() * 2);
header2.draw(); //Header height is the twice the height of the font
//Settings for the line graph
auto content = line_chart(0, header.height() + header2.height()); //(x,y) where the line graph begins
content
.height(tft.height() - (header.height() + header2.height()) * 1.0) //actual height of the line chart
.width(tft.width() - content.x() * 2) //actual width of the line chart
.based_on(0.0) //Starting point of y-axis, must be a float
.show_circle(false) //drawing a cirle at each point, default is on.
.value(data) //passing through the data to line graph
.color(TFT_PURPLE) //Setting the color for the line
.draw();
spr.pushSprite(0, 0);
oldHB = HB;
}
Comments