/*
Wokwi | questions
My code doesn't work
! delax
September 16, 2025 — 9:08 AM
https://wokwi.com/projects/442257053723909121
*/
/******************************************************
* Monitoramento de Saúde em Tempo Real – Wokwi (ESP32/UNO)
* - DHT22 (GPIO 19)
* - Potenciômetro BPM (GPIO 34)
* - Potenciômetro SpO2 (GPIO 35)
* - OLED SSD1306 128x64 I2C (SDA=21, SCL=22, addr 0x3C)
* - LEDs: Verde=5, Amarelo=17, Vermelho=16
* - Buzzer (GPIO 15) usando tone()
******************************************************/
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "DHT.h"
// ---------- OLED ----------
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// ---------- DHT ----------
#define DHTPIN 19
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// ---------- I/O ----------
const int LED_VERDE = 5;
const int LED_AMARELO = 17;
const int LED_VERMELHO = 16;
const int BUZZER_PIN = 15; // buzzer (2 pinos)
const int ADC_BPM = 34; // potenciômetro 1
const int ADC_SPO2 = 35; // potenciômetro 2
// ---------- Limiares ----------
struct Faixas {
float t_alerta = 37.5;
float t_critico = 38.5;
int bpm_min_ok = 60;
int bpm_max_ok = 100;
int bpm_alerta_sup = 140;
int bpm_alerta_inf = 50;
int bpm_critico_sup= 150;
int bpm_critico_inf= 40;
int spo2_alerta = 94; // 90–94 alerta
int spo2_critico = 90; // <90 crítico
} fx;
// Estado 0=ok, 1=alerta, 2=critico
int estadoGeral = 0, estadoAnterior = -1;
// ---- Amostragem do DHT (a cada 2 s) ----
float lastTemp = NAN;
unsigned long lastDhtRead = 0;
const unsigned long DHT_INTERVAL = 2000; // 2s
// --------- Utils ----------
int nivelPorTemp(float t) {
if (isnan(t)) return 1;
if (t > fx.t_critico) return 2;
if (t > fx.t_alerta) return 1;
return 0;
}
int nivelPorBPM(int bpm) {
if (bpm > fx.bpm_critico_sup || bpm < fx.bpm_critico_inf) return 2;
if (bpm > fx.bpm_alerta_sup || bpm < fx.bpm_alerta_inf) return 1;
if (bpm >= fx.bpm_min_ok && bpm <= fx.bpm_max_ok) return 0;
return 1;
}
int nivelPorSpO2(int s) {
if (s < fx.spo2_critico) return 2;
if (s <= fx.spo2_alerta) return 1;
return 0;
}
void buzzerInit() {
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
}
void buzzerBeep(int nivel) {
if (nivel == 0) { noTone(BUZZER_PIN); return; }
int freq = (nivel == 2) ? 2400 : 1800; // crítico mais agudo
tone(BUZZER_PIN, freq, 120); // 120 ms
delay(120);
noTone(BUZZER_PIN);
}
void setLeds(int nivel) {
digitalWrite(LED_VERDE, nivel == 0 ? HIGH : LOW);
digitalWrite(LED_AMARELO, nivel == 1 ? HIGH : LOW);
digitalWrite(LED_VERMELHO, nivel == 2 ? HIGH : LOW);
}
int mapAnalogToBPM(int raw) { return map(raw, 0, 4095, 40, 180); } // 40..180 BPM
int mapAnalogToSpO2(int raw) { return map(raw, 0, 4095, 80, 100); } // 80..100%
void desenharTela(float temp, int bpm, int spo2, int nivel) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Saude em Tempo Real");
const char* statusTxt = (nivel==0) ? "OK" : (nivel==1) ? "ALERTA" : "CRITICO";
int x = 128 - (strlen(statusTxt) * 6);
if (x < 0) x = 0;
display.setCursor(x, 0);
display.print(statusTxt);
display.setTextSize(2);
display.setCursor(0, 16);
display.print("T:");
if (isnan(temp)) display.print("--.-");
else display.print(String(temp, 1));
display.print((char)247); display.print("C");
display.setCursor(0, 36);
display.print("BPM:"); display.print(bpm);
display.setTextSize(1);
display.setCursor(0, 56);
display.print("SpO2: "); display.print(spo2); display.print("%");
display.display();
}
void setup() {
Serial.begin(115200);
delay(200);
pinMode(LED_VERDE, OUTPUT);
pinMode(LED_AMARELO, OUTPUT);
pinMode(LED_VERMELHO, OUTPUT);
buzzerInit();
dht.begin();
Wire.begin(21, 22); // SDA=21, SCL=22
display.setRotation(2); // flips screen vertically
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println(F("Falha ao iniciar SSD1306"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Inicializando...");
display.display();
setLeds(0);
}
void loop() {
// Leituras rápidas
int rawBpm = analogRead(ADC_BPM);
int rawSpO2 = analogRead(ADC_SPO2);
int bpm = mapAnalogToBPM(rawBpm);
int spo2 = mapAnalogToSpO2(rawSpO2);
// DHT a cada 2s
static float temp = NAN;
unsigned long now = millis();
if (now - lastDhtRead >= DHT_INTERVAL) {
float t = dht.readTemperature();
if (!isnan(t)) temp = t;
lastDhtRead = now;
}
int nTemp = nivelPorTemp(temp);
int nBpm = nivelPorBPM(bpm);
int nSpO2 = nivelPorSpO2(spo2);
estadoGeral = max(nTemp, max(nBpm, nSpO2));
setLeds(estadoGeral);
if (estadoGeral != estadoAnterior) {
buzzerBeep(estadoGeral);
estadoAnterior = estadoGeral;
} else if (estadoGeral == 2) {
buzzerBeep(2); // reforço em crítico
}
desenharTela(temp, bpm, spo2, estadoGeral);
Serial.printf("Temp=%.1fC, BPM=%d, SpO2=%d%% -> Nivel=%d\n",
(isnan(temp)?-1:temp), bpm, spo2, estadoGeral);
delay(200);
}