#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;
long lastBeat = 0;
float beatsPerMinute;
int beatAvg = 72;
int spo2 = 98;
bool fingerDetected = false;
// =====================================================
// HEART ICON
// =====================================================
void drawHeart(int x, int y, uint16_t color)
{
tft.fillCircle(x - 8, y, 8, color);
tft.fillCircle(x + 8, y, 8, color);
tft.fillTriangle(x - 16, y + 2, x + 16, y + 2, x, y + 22, color);
}
// =====================================================
// BLOOD DROP
// =====================================================
void drawDrop(int x, int y, uint16_t color)
{
tft.fillCircle(x, y + 8, 10, color);
tft.fillTriangle(x - 10, y + 8, x + 10, y + 8, x, y - 15, color);
}
// =====================================================
// UI
// =====================================================
void drawUI()
{
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_GREEN);
tft.setTextSize(1);
tft.setCursor(18, 5);
tft.print("HEART & SPO2 MONITOR");
tft.drawLine(0, 18, 160, 18, ST77XX_WHITE);
tft.drawLine(0, 80, 160, 80, ST77XX_WHITE);
drawHeart(40, 40, ST77XX_RED);
drawDrop(40, 105, ST77XX_CYAN);
tft.setTextSize(2);
tft.setTextColor(ST77XX_WHITE);
tft.setCursor(80, 30);
tft.print("HR");
tft.setCursor(80, 92);
tft.print("SpO2");
tft.setTextSize(1);
tft.setCursor(130, 60);
tft.print("BPM");
}
// =====================================================
// SETUP
// =====================================================
void setup()
{
Serial.begin(115200);
pinMode(BUZZER, OUTPUT);
tft.initR(INITR_BLACKTAB);
// Horizontal
tft.setRotation(3);
drawUI();
if (!particleSensor.begin(Wire, I2C_SPEED_STANDARD))
{
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_RED);
tft.setTextSize(2);
tft.setCursor(10, 60);
tft.print("MAX30102 ERROR");
while (1);
}
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x1F);
particleSensor.setPulseAmplitudeGreen(0);
}
// =====================================================
// LOOP
// =====================================================
void loop()
{
long irValue = particleSensor.getIR();
fingerDetected = irValue > 50000;
// ==============================
// HEART RATE DETECT
// ==============================
if (fingerDetected)
{
if (checkForBeat(irValue))
{
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60.0 / (delta / 1000.0);
if (beatsPerMinute > 40 && beatsPerMinute < 180)
{
beatAvg = (int)beatsPerMinute;
// Fake SPO2
spo2 = random(97, 100);
// Buzzer
tone(BUZZER, 2000, 80);
// Heart Animation
drawHeart(40, 40, ST77XX_MAGENTA);
delay(30);
drawHeart(40, 40, ST77XX_RED);
}
}
}
// ==============================
// HR VALUE
// ==============================
tft.fillRect(80, 52, 60, 20, ST77XX_BLACK);
tft.setTextSize(2);
tft.setCursor(80, 52);
if (fingerDetected)
{
tft.setTextColor(ST77XX_GREEN);
tft.print(beatAvg);
}
else
{
tft.setTextColor(ST77XX_RED);
tft.print("--");
}
// ==============================
// SPO2 VALUE
// ==============================
tft.fillRect(80, 115, 60, 20, ST77XX_BLACK);
tft.setCursor(80, 115);
if (fingerDetected)
{
tft.setTextColor(ST77XX_CYAN);
tft.print(spo2);
tft.print("%");
}
else
{
tft.setTextColor(ST77XX_RED);
tft.print("--%");
}
// ==============================
// STATUS
// ==============================
tft.fillRect(0, 145, 160, 15, ST77XX_BLACK);
tft.setTextSize(1);
if (fingerDetected)
{
tft.setCursor(40, 145);
tft.setTextColor(ST77XX_GREEN);
tft.print("FINGER DETECTED");
}
else
{
tft.setCursor(42, 145);
tft.setTextColor(ST77XX_YELLOW);
tft.print("PLACE FINGER");
}
delay(50);
}