#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ---- OLED ----
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, -1);
// ---- Pins ----
#define PIN_SPO2_ADC 34
#define PIN_TEMP_ADC 35
#define PIN_BP_ADC 32
#define PIN_LED_STATUS 2
#define PIN_LED_HR 4
#define PIN_BTN_MEASURE 25
#define PIN_BTN_RESET 26
// ---- Simulated vital sign values ----
float spo2 = 0;
float tempC = 0;
int sysBP = 0;
int diasBP = 0;
int heartRate = 0;
unsigned long lastBlink = 0;
unsigned long lastHRBeat = 0;
bool statusLed = false;
// ---- Read ADC and map to physiological range ----
float readSpO2() {
int raw = analogRead(PIN_SPO2_ADC);
return map(raw, 0, 4095, 880, 1000) / 10.0; // 88.0 – 100.0 %
}
float readTemp() {
int raw = analogRead(PIN_TEMP_ADC);
return map(raw, 0, 4095, 350, 420) / 10.0; // 35.0 – 42.0 °C
}
int readSysBP() {
int raw = analogRead(PIN_BP_ADC);
return map(raw, 0, 4095, 60, 180); // 60 – 180 mmHg
}
int estimateDiasBP(int sys) {
return (int)(sys * 0.63); // rough 2/3 ratio
}
int estimateHR(float spo2val) {
// Simulate HR loosely correlated to SpO2 (low SpO2 -> slightly raised HR)
return (int)(70 + (100.0 - spo2val) * 2.5);
}
void drawDisplay() {
display.clearDisplay();
// Header
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("VITAL SIGNS MONITOR");
display.drawLine(0, 9, 127, 9, SSD1306_WHITE);
// SpO2
display.setCursor(0, 13);
display.print("SpO2 : ");
display.setTextSize(1);
display.print(spo2, 1);
display.print(" %");
// Heart Rate
display.setCursor(0, 24);
display.print("HR : ");
display.print(heartRate);
display.print(" bpm");
// Temperature
display.setCursor(0, 35);
display.print("Temp : ");
display.print(tempC, 1);
display.print(" C");
// Blood Pressure
display.setCursor(0, 46);
display.print("BP : ");
display.print(sysBP);
display.print("/");
display.print(diasBP);
display.print(" mmHg");
// Status bar
display.drawLine(0, 56, 127, 56, SSD1306_WHITE);
display.setCursor(0, 58);
bool measuring = (digitalRead(PIN_BTN_MEASURE) == LOW);
display.print(measuring ? ">> MEASURING... <<" : " Press to measure");
display.display();
}
void setup() {
Serial.begin(115200);
Serial.println("Vital Signs Monitor — Wokwi Simulation");
pinMode(PIN_LED_STATUS, OUTPUT);
pinMode(PIN_LED_HR, OUTPUT);
pinMode(PIN_BTN_MEASURE, INPUT_PULLUP);
pinMode(PIN_BTN_RESET, INPUT_PULLUP);
analogReadResolution(12);
Wire.begin(21, 22);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println("SSD1306 not found — check wiring");
while (true) { delay(100); }
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// Splash
display.setTextSize(1);
display.setCursor(10, 10);
display.println("VITAL SIGNS MONITOR");
display.setCursor(20, 28);
display.println("Kyambogo University");
display.setCursor(30, 42);
display.println("Initialising...");
display.display();
delay(1500);
}
void loop() {
unsigned long now = millis();
// Read sensors (potentiometers in simulation)
spo2 = readSpO2();
tempC = readTemp();
sysBP = readSysBP();
diasBP = estimateDiasBP(sysBP);
heartRate = estimateHR(spo2);
// Status LED blink (1 Hz)
if (now - lastBlink >= 500) {
statusLed = !statusLed;
digitalWrite(PIN_LED_STATUS, statusLed);
lastBlink = now;
}
// HR beat LED — flash at heartRate bpm
long hrInterval = 60000L / heartRate;
if (now - lastHRBeat >= (unsigned long)hrInterval) {
digitalWrite(PIN_LED_HR, HIGH);
delay(50);
digitalWrite(PIN_LED_HR, LOW);
lastHRBeat = now;
}
drawDisplay();
// Serial output for plotter / monitor
Serial.print("SpO2:"); Serial.print(spo2);
Serial.print(",Temp:"); Serial.print(tempC);
Serial.print(",SysBP:"); Serial.print(sysBP);
Serial.print(",DiasBP:"); Serial.print(diasBP);
Serial.print(",HR:"); Serial.println(heartRate);
delay(200);
}