#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9
#define BUZZER 3
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
MAX30105 particleSensor;
// =========================
const byte RATE_SIZE = 4;
byte rates[RATE_SIZE];
byte rateSpot = 0;
long lastBeat = 0;
float beatAvg = 0;
float spo2 = 98;
bool finger = false;
// ========================= ICONS
void drawHeart(int x, int y, uint16_t color)
{
tft.fillCircle(x - 6, y, 6, color);
tft.fillCircle(x + 6, y, 6, color);
tft.fillTriangle(x - 12, y + 2, x + 12, y + 2, x, y + 18, color);
}
void drawDrop(int x, int y, uint16_t color)
{
tft.fillTriangle(x, y - 15, x - 10, y + 10, x + 10, y + 10, color);
tft.fillCircle(x, y + 10, 10, color);
}
// ========================= UI
void drawUI()
{
tft.fillScreen(ST77XX_BLACK);
tft.setTextSize(1);
tft.setTextColor(ST77XX_GREEN);
tft.setCursor(10, 5);
tft.print("HEART & SPO2 MONITOR");
tft.drawLine(0, 18, 160, 18, ST77XX_WHITE);
drawHeart(25, 50, ST77XX_RED);
drawDrop(25, 110, ST77XX_CYAN);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.setCursor(60, 35);
tft.print("HR");
tft.setCursor(60, 95);
tft.print("SpO2");
}
// ========================= SETUP
void setup()
{
Serial.begin(115200);
pinMode(BUZZER, OUTPUT);
tft.initR(INITR_BLACKTAB);
tft.setRotation(3);
drawUI();
if (!particleSensor.begin(Wire, I2C_SPEED_FAST))
{
tft.setCursor(10, 60);
tft.setTextColor(ST77XX_RED);
tft.print("Sensor ERROR");
while (1);
}
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x2F);
particleSensor.setPulseAmplitudeIR(0x2F);
}
// ========================= LOOP
void loop()
{
long irValue = particleSensor.getIR();
finger = irValue > 50000;
// ========================= HEART RATE
if (finger)
{
if (checkForBeat(irValue))
{
long delta = millis() - lastBeat;
lastBeat = millis();
float bpm = 60.0 / (delta / 1000.0);
if (bpm > 40 && bpm < 180)
{
rates[rateSpot++] = (byte)bpm;
rateSpot %= RATE_SIZE;
beatAvg = 0;
for (byte i = 0; i < RATE_SIZE; i++)
beatAvg += rates[i];
beatAvg /= RATE_SIZE;
tone(BUZZER, 2000, 50);
drawHeart(25, 50, ST77XX_MAGENTA);
}
}
// ========================= SIMPLE REAL SIGNAL BASED SPO2
float ratio = irValue / 100000.0;
spo2 = 110 - (ratio * 10);
if (spo2 > 100) spo2 = 100;
if (spo2 < 90) spo2 = 90;
}
else
{
noTone(BUZZER);
}
// ========================= HR DISPLAY
tft.fillRect(60, 30, 100, 40, ST77XX_BLACK);
tft.setCursor(60, 40);
if (finger)
{
tft.setTextColor(ST77XX_GREEN);
tft.print((int)beatAvg);
tft.print(" BPM");
}
else
{
tft.setTextColor(ST77XX_RED);
tft.print("--");
}
// ========================= SPO2 DISPLAY
tft.fillRect(60, 90, 100, 40, ST77XX_BLACK);
tft.setCursor(60, 100);
if (finger)
{
tft.setTextColor(ST77XX_CYAN);
tft.print((int)spo2);
tft.print("%");
}
else
{
tft.setTextColor(ST77XX_RED);
tft.print("--%");
}
// ========================= STATUS
tft.fillRect(0, 140, 160, 20, ST77XX_BLACK);
tft.setCursor(25, 140);
if (finger)
{
tft.setTextColor(ST77XX_GREEN);
tft.print("FINGER DETECTED");
}
else
{
tft.setTextColor(ST77XX_YELLOW);
tft.print("PLACE FINGER");
}
delay(20);
}