#include <Arduino.h>
#include <LiquidCrystal.h>
#include <DHT.h>
// ---- Pines ----
static const uint8_t PIN_DHT = 4;
static const uint8_t PIN_LED_RED = 25;
static const uint8_t PIN_LED_BLU = 26;
static const uint8_t PIN_LED_GRN = 27;
static const uint8_t PIN_BUZZER = 32;
// ---- Pines LCD paralelo (evitando GPIO 21/22 = I2C por defecto) ----
static const uint8_t LCD_RS = 2;
static const uint8_t LCD_EN = 15;
static const uint8_t LCD_D4 = 16;
static const uint8_t LCD_D5 = 17;
static const uint8_t LCD_D6 = 18;
static const uint8_t LCD_D7 = 19;
// ---- Umbrales ----
static const float T_LOW = 20.0f;
static const float T_HIGH = 26.0f;
// ---- LCD ----
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
// ---- Sensor ----
DHT dht(PIN_DHT, DHT22);
// ---- Estado ----
enum class Estado : uint8_t { OK, FRIO, CALOR, ERROR };
static Estado estadoActual = Estado::OK;
static Estado estadoAnterior = Estado::OK;
static float ultimaTemp = NAN;
static float ultimaHum = NAN;
static bool lecturaValida = false;
static bool lcdOk = false;
static uint32_t ultimaLecturaMs = 0;
static const uint32_t PERIODO_LECTURA_MS = 2000;
// ---- Prototipos ----
void configurarHardware();
void leerSensor();
void evaluarEstado();
void pintarLCD();
void aplicarSalidas();
void setLed(uint8_t pin, bool on);
void buzzerOn();
void buzzerOff();
void logSerial();
// ============================================================================
// setup
// ============================================================================
void setup() {
Serial.begin(115200);
delay(200);
Serial.println();
Serial.println(F("=== Sistema de Alerta de Temperatura (Aula) ==="));
configurarHardware();
// LCD 16x2, modo 4 bits
lcd.begin(16, 2);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Aula Temp Alert"));
lcd.setCursor(0, 1);
lcd.print(F("Iniciando..."));
delay(1000);
lcdOk = true;
// DHT22
dht.begin();
delay(500);
// Primer ciclo
leerSensor();
evaluarEstado();
pintarLCD();
aplicarSalidas();
logSerial();
Serial.println(F("Sistema listo."));
}
// ============================================================================
// loop
// ============================================================================
void loop() {
const uint32_t ahora = millis();
if (ahora - ultimaLecturaMs >= PERIODO_LECTURA_MS) {
ultimaLecturaMs = ahora;
leerSensor();
evaluarEstado();
pintarLCD();
aplicarSalidas();
logSerial();
}
delay(50);
}
// ============================================================================
// Implementación
// ============================================================================
void configurarHardware() {
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_LED_BLU, OUTPUT);
pinMode(PIN_LED_GRN, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
setLed(PIN_LED_RED, false);
setLed(PIN_LED_BLU, false);
setLed(PIN_LED_GRN, false);
buzzerOff();
}
void leerSensor() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
ultimaTemp = t;
ultimaHum = h;
lecturaValida = true;
} else {
lecturaValida = false;
}
}
void evaluarEstado() {
estadoAnterior = estadoActual;
if (!lecturaValida) {
estadoActual = Estado::ERROR;
return;
}
if (ultimaTemp < T_LOW) estadoActual = Estado::FRIO;
else if (ultimaTemp > T_HIGH) estadoActual = Estado::CALOR;
else estadoActual = Estado::OK;
}
void aplicarSalidas() {
switch (estadoActual) {
case Estado::OK:
setLed(PIN_LED_GRN, true);
setLed(PIN_LED_RED, false);
setLed(PIN_LED_BLU, false);
buzzerOff();
break;
case Estado::FRIO:
setLed(PIN_LED_BLU, true);
setLed(PIN_LED_RED, false);
setLed(PIN_LED_GRN, false);
buzzerOn();
break;
case Estado::CALOR:
setLed(PIN_LED_RED, true);
setLed(PIN_LED_BLU, false);
setLed(PIN_LED_GRN, false);
buzzerOn();
break;
case Estado::ERROR:
setLed(PIN_LED_GRN, true);
setLed(PIN_LED_RED, false);
setLed(PIN_LED_BLU, false);
buzzerOff();
break;
}
}
void pintarLCD() {
if (!lcdOk) return;
lcd.clear();
lcd.setCursor(0, 0);
if (!lecturaValida) {
lcd.print(F("SENSOR ERROR"));
lcd.setCursor(0, 1);
lcd.print(F("T:-- H:--"));
return;
}
// Linea 1: T y H
lcd.print(F("T:"));
lcd.print(ultimaTemp, 1);
lcd.print(F("C H:"));
lcd.print(ultimaHum, 0);
lcd.print(F("%"));
// Linea 2: Estado
lcd.setCursor(0, 1);
lcd.print(F("Est:"));
switch (estadoActual) {
case Estado::OK: lcd.print(F("ESTABLE")); break;
case Estado::FRIO: lcd.print(F("FRIO ")); break;
case Estado::CALOR: lcd.print(F("CALOR ")); break;
case Estado::ERROR: lcd.print(F("ERROR ")); break;
}
}
void setLed(uint8_t pin, bool on) {
digitalWrite(pin, on ? HIGH : LOW);
}
void buzzerOn() { digitalWrite(PIN_BUZZER, HIGH); }
void buzzerOff() { digitalWrite(PIN_BUZZER, LOW); }
void logSerial() {
Serial.print(F("["));
Serial.print(millis() / 1000);
Serial.print(F("s] "));
if (!lecturaValida) {
Serial.println(F("lectura invalida -> ERROR"));
return;
}
Serial.print(F("T="));
Serial.print(ultimaTemp, 1);
Serial.print(F("C H="));
Serial.print(ultimaHum, 1);
Serial.print(F("% -> "));
switch (estadoActual) {
case Estado::OK: Serial.println(F("ESTABLE (verde, buzzer OFF)")); break;
case Estado::FRIO: Serial.println(F("FRIO (azul + buzzer ON)")); break;
case Estado::CALOR: Serial.println(F("CALOR (rojo + buzzer ON)")); break;
case Estado::ERROR: Serial.println(F("ERROR de lectura")); break;
}
}