How I AUTOMATED a GATE with an ESP32 🚪⚡ | PCB + Motor + Remote Control
GERBER -
https://github.com/ELECTROALL/TARJETA-PARA-PORTON-CON-ESP32/tree/main
CODE -
https://github.com/ELECTROALL/TARJETA-PARA-PORTON-CON-ESP32/blob/main/Gerber_PCB1_2026-07-22.zip
https://github.com/ELECTROALL/TARJETA-PARA-PORTON-CON-ESP32/tree/main
CODE -
https://github.com/ELECTROALL/TARJETA-PARA-PORTON-CON-ESP32/blob/main/Gerber_PCB1_2026-07-22.zip
Complete Project Code
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Preferences.h>
#include <esp_task_wdt.h> // Watchdog para recuperacion automatica 24/7
#define WDT_TIMEOUT 5 // Tiempo de reinicio si el codigo se bloquea (segundos)
// ============================== LCD Y MEMORIA ==================================
LiquidCrystal_I2C lcd(0x27, 16, 2);
Preferences memoria;
// ============================== PINES ==========================================
#define PIN_CORRIENTE 36
#define SENSOR_CERRADO 32
#define SENSOR_ABIERTO 35
#define PIN_PARADA_EMERGENCIA 34
#define PIN_PULSADOR_TOGGLE 39 // Entrada pulsador externo (Activo en LOW)
#define PIN_REMOTO_ABRIR 12
#define PIN_REMOTO_CERRAR 14
#define PIN_ON_OFF_LAMPARA 26
#define PIN_REMOTO_EMERGENCIA 27
#define PIN_BTN_ADD 2
#define PIN_BTN_MINUS 13
#define PIN_BTN_OK 15
#define PIN_MOTOR_ARRIBA 19
#define PIN_MOTOR_ABAJO 23
#define PIN_MOSFET_PWM 18
#define PIN_ALARMA 17
#define CHAPA_PUERTA 16
#define PIN_LAMPARA 4
// ============================== VARIABLES CONFIGURACIÓN =====================
int cfg_tRampa = 3;
int cfg_vMax = 20;
int cfg_tVMax = 20;
int cfg_vMin = 10;
bool cfg_chapaEn = true;
int cfg_chapaOn = 500;
int cfg_chapaOff = 800;
bool cfg_sirenaEn = true;
bool cfg_sirenaModoCompleto = false;
int cfg_sirenaTOn = 3;
int cfg_limCorriente = 4000;
long ciclosTotales = 0;
// ============================== CONTROL Y ESTADOS ============================
enum EstadoPuerta {
DETENIDO,
CHAPA_ACTIVA,
PRE_RAMPA,
ACELERANDO,
VEL_MAXIMA,
DESACELERANDO,
VEL_LENTA,
FRENADO_EMERGENCIA,
PAUSA_INVERSION,
FALLO_SENSORES
};
EstadoPuerta estadoMotor = DETENIDO;
bool motorAbriendo = false;
unsigned long tiempoInicioFase = 0;
unsigned long tiempoInicioGlobalMovimiento = 0;
unsigned long ultimaLecturaCorriente = 0;
unsigned long ultimaAccionRemoto = 0;
float corrienteFiltrada = 0;
const float FACTOR_SUAVIZADO = 0.3;
const int PWM_STOP = 0;
int pwmActualInt = 0;
// --- VARIABLES DE TIEMPO / ANTIAPLASTAMIENTO ---
bool causaEsSobrecorriente = false;
bool paradaForzada = false;
unsigned long pwmAlChoque = 0;
long posicionEstimadaMs = 0;
unsigned long ultimoTiempoCalculo = 0;
// --- VARIABLES LÁMPARA ---
bool estadoLampara = false;
int ultimoEstadoPinLampara = LOW;
unsigned long tiempoReboteLampara = 0;
int estadoFiltroLampara = LOW;
// --- VARIABLES SIRENA ---
bool sirenaDebeSonar = false;
unsigned long tiempoUltimoSirena = 0;
bool estadoFisicoSirena = HIGH;
// ============================== SISTEMA MENÚ ===================================
byte flecha[] = { B10000, B11000, B11100, B11110, B11100, B11000, B10000, B00000 };
int menuContext = 0;
int menuCursor = 0;
bool isEditing = false;
int editTempVal = 0;
bool forzarRedraw = true;
unsigned long tiempoUltimoBoton = 0;
const unsigned long intervaloBoton = 200;
int estadoAnteriorOK = HIGH;
unsigned long ultimoRefrescoTest = 0;
String menuPrin[] = {"T. RAMP. VEL M.", "CHAPA", "SIRENA", "LIM. CORRIENTE", "TEST / INFO", "ATRAS"};
String menuTRamp[] = {"TIEMPO RAMPA", "VELOCIDAD MAX", "T. VEL MAX", "VELOCIDAD MIN", "ATRAS"};
String menuChapa[] = {"HABILITAR/DESHA", "TIEMPO ON", "TIEMPO OFF", "ATRAS"};
String menuSirena[] = {"HABILITAR/DESHA", "MODO", "TIEMPO ON Inic", "ATRAS"};
String menuTestInfo[] = {"TEST", "INFO", "ATRAS"};
// ============================== PROTOTIPOS =====================================
void cargarConfiguracion();
void guardarConfiguracion();
void maquinaMotor();
void iniciarMovimiento(bool esApertura);
void detenerSistema(String mensaje);
void iniciarFrenado(bool esSobrecorriente);
void fijarPWM(int pwm);
void gestionarBotones();
void dibujarMenu();
void mostrarSubMenu(int cursor, String menus[], int size);
int mapPWM(int vel_0_25);
void activarMotorDireccion(bool abriendo);
// ============================== SETUP ==========================================
void setup() {
Serial.begin(115200);
// 1. Apagado Físico Preventivo antes de configurar salidas
pinMode(PIN_MOTOR_ARRIBA, OUTPUT); digitalWrite(PIN_MOTOR_ARRIBA, LOW);
pinMode(PIN_MOTOR_ABAJO, OUTPUT); digitalWrite(PIN_MOTOR_ABAJO, LOW);
pinMode(PIN_MOSFET_PWM, OUTPUT); analogWrite(PIN_MOSFET_PWM, 0);
pinMode(CHAPA_PUERTA, OUTPUT); digitalWrite(CHAPA_PUERTA, HIGH);
pinMode(PIN_ALARMA, OUTPUT); digitalWrite(PIN_ALARMA, HIGH);
pinMode(PIN_LAMPARA, OUTPUT); digitalWrite(PIN_LAMPARA, HIGH);
// 2. Configuración de Entradas
pinMode(PIN_CORRIENTE, INPUT);
pinMode(SENSOR_CERRADO, INPUT_PULLUP);
pinMode(SENSOR_ABIERTO, INPUT_PULLUP);
pinMode(PIN_PARADA_EMERGENCIA, INPUT_PULLUP);
pinMode(PIN_PULSADOR_TOGGLE, INPUT); // Entrada pulsador externo D39
pinMode(PIN_REMOTO_ABRIR, INPUT);
pinMode(PIN_REMOTO_CERRAR, INPUT);
pinMode(PIN_REMOTO_EMERGENCIA, INPUT);
pinMode(PIN_ON_OFF_LAMPARA, INPUT);
pinMode(PIN_BTN_ADD, INPUT_PULLUP);
pinMode(PIN_BTN_MINUS, INPUT_PULLUP);
pinMode(PIN_BTN_OK, INPUT_PULLUP);
cargarConfiguracion();
// 3. Inicialización del Watchdog (Compatible con ESP32 Core v3.x)
esp_task_wdt_config_t twdt_config;
twdt_config.timeout_ms = WDT_TIMEOUT * 1000;
twdt_config.idle_core_mask = (1 << portNUM_PROCESSORS) - 1;
twdt_config.trigger_panic = true;
esp_task_wdt_init(&twdt_config);
esp_task_wdt_add(NULL);
lcd.init();
lcd.backlight();
lcd.createChar(0, flecha);
lcd.setCursor(0, 0);
lcd.print("SISTEMA 24/7 ");
lcd.setCursor(0, 1);
lcd.print("INICIANDO... ");
delay(1200);
estadoAnteriorOK = digitalRead(PIN_BTN_OK);
menuContext = 0;
lcd.clear();
}
// ============================== LOOP PRINCIPAL =================================
void loop() {
esp_task_wdt_reset();
unsigned long actualMillis = millis();
// --- COMPROBACIÓN DE SEGURIDAD: SENSORES CONTRADICTORIOS ---
bool senCerrado = (digitalRead(SENSOR_CERRADO) == LOW);
bool senAbierto = (digitalRead(SENSOR_ABIERTO) == LOW);
if (senCerrado && senAbierto) {
detenerSistema("ERROR SENSORES");
estadoMotor = FALLO_SENSORES;
}
// --- BOTÓN LÁMPARA ---
int lecturaLamparaActual = digitalRead(PIN_ON_OFF_LAMPARA);
if (lecturaLamparaActual != ultimoEstadoPinLampara) {
tiempoReboteLampara = actualMillis;
}
if ((actualMillis - tiempoReboteLampara) > 50) {
if (lecturaLamparaActual != estadoFiltroLampara) {
estadoFiltroLampara = lecturaLamparaActual;
if (estadoFiltroLampara == HIGH) {
estadoLampara = !estadoLampara;
digitalWrite(PIN_LAMPARA, estadoLampara ? LOW : HIGH);
}
}
}
ultimoEstadoPinLampara = lecturaLamparaActual;
// --- BOTONES DE PARADA DE EMERGENCIA ---
bool btnStop = (digitalRead(PIN_REMOTO_EMERGENCIA) == HIGH) || (digitalRead(PIN_PARADA_EMERGENCIA) == HIGH);
if (btnStop && estadoMotor != DETENIDO && estadoMotor != FRENADO_EMERGENCIA && (actualMillis - ultimaAccionRemoto >= 500)) {
ultimaAccionRemoto = actualMillis;
iniciarFrenado(false);
}
// --- BOTONES DE CONTROL REMOTO Y PULSADOR TOGGLE (D39) ---
bool btnAbrir = (digitalRead(PIN_REMOTO_ABRIR) == HIGH);
bool btnCerrar = (digitalRead(PIN_REMOTO_CERRAR) == HIGH);
bool btnToggle = (digitalRead(PIN_PULSADOR_TOGGLE) == LOW); // Pulsador externo activo en LOW
if ((btnAbrir || btnCerrar || btnToggle) && menuContext == 0 && (actualMillis - ultimaAccionRemoto >= 500)) {
ultimaAccionRemoto = actualMillis;
if (estadoMotor == DETENIDO) {
bool errorNoSensor = (!senCerrado && !senAbierto && !paradaForzada);
if (!errorNoSensor) {
if (btnToggle) {
// Lógica de funcionamiento paso a paso (Toggle)
if (senAbierto) {
iniciarMovimiento(false); // Si está abierta -> Cerrar
} else if (senCerrado) {
iniciarMovimiento(true); // Si está cerrada -> Abrir
} else {
// Si está a medio camino, invierte el sentido respecto al último movimiento
iniciarMovimiento(!motorAbriendo);
}
}
else if (btnAbrir && !senAbierto) {
iniciarMovimiento(true);
}
else if (btnCerrar && !senCerrado) {
iniciarMovimiento(false);
}
}
}
}
// --- FINALES DE CARRERA EN MOVIMIENTO ---
if (estadoMotor != DETENIDO && estadoMotor != FRENADO_EMERGENCIA && estadoMotor != PAUSA_INVERSION && estadoMotor != FALLO_SENSORES) {
if (motorAbriendo && senAbierto) {
posicionEstimadaMs = ((long)cfg_tRampa * 2 + (long)cfg_tVMax) * 1000;
paradaForzada = false;
detenerSistema("FIN CARRERA: ABIERTA");
}
if (!motorAbriendo && senCerrado) {
posicionEstimadaMs = 0;
paradaForzada = false;
detenerSistema("FIN CARRERA: CERRADA");
}
}
// --- MONITOREO DE CORRIENTE (ANTIAPLASTAMIENTO) ---
if (actualMillis - ultimaLecturaCorriente >= 100) {
ultimaLecturaCorriente = actualMillis;
corrienteFiltrada = (FACTOR_SUAVIZADO * analogRead(PIN_CORRIENTE)) + ((1 - FACTOR_SUAVIZADO) * corrienteFiltrada);
if (estadoMotor >= ACELERANDO && estadoMotor <= VEL_LENTA && corrienteFiltrada >= cfg_limCorriente) {
iniciarFrenado(true);
}
}
// --- MÁQUINAS DE ESTADO ---
maquinaMotor();
gestionarBotones();
dibujarMenu();
}
// ============================== MOTOR Y SECUENCIAS =============================
int mapPWM(int vel_0_25) {
if (vel_0_25 > 25) vel_0_25 = 25;
if (vel_0_25 < 0) vel_0_25 = 0;
return map(vel_0_25, 0, 25, 0, 255);
}
void fijarPWM(int pwm) {
pwmActualInt = pwm;
analogWrite(PIN_MOSFET_PWM, pwm);
}
void activarMotorDireccion(bool abriendo) {
digitalWrite(PIN_MOTOR_ARRIBA, LOW);
digitalWrite(PIN_MOTOR_ABAJO, LOW);
delayMicroseconds(100);
if (abriendo) {
digitalWrite(PIN_MOTOR_ARRIBA, HIGH);
} else {
digitalWrite(PIN_MOTOR_ABAJO, HIGH);
}
}
void iniciarMovimiento(bool esApertura) {
motorAbriendo = esApertura;
paradaForzada = false;
fijarPWM(PWM_STOP);
bool estaTotalmenteCerrada = (digitalRead(SENSOR_CERRADO) == LOW);
if (esApertura) {
ciclosTotales++;
if (ciclosTotales % 10 == 0) {
memoria.putLong("ciclos", ciclosTotales);
}
if (cfg_chapaEn && estaTotalmenteCerrada) {
digitalWrite(CHAPA_PUERTA, LOW);
estadoMotor = CHAPA_ACTIVA;
tiempoInicioFase = millis();
} else {
activarMotorDireccion(true);
estadoMotor = ACELERANDO;
tiempoInicioFase = millis();
ultimoTiempoCalculo = millis();
}
} else {
activarMotorDireccion(false);
estadoMotor = ACELERANDO;
tiempoInicioFase = millis();
ultimoTiempoCalculo = millis();
}
tiempoInicioGlobalMovimiento = millis();
sirenaDebeSonar = cfg_sirenaEn;
tiempoUltimoSirena = millis();
estadoFisicoSirena = LOW;
if (sirenaDebeSonar) digitalWrite(PIN_ALARMA, estadoFisicoSirena);
forzarRedraw = true;
}
void iniciarFrenado(bool esSobrecorriente) {
causaEsSobrecorriente = esSobrecorriente;
pwmAlChoque = pwmActualInt;
paradaForzada = !esSobrecorriente;
estadoMotor = FRENADO_EMERGENCIA;
tiempoInicioFase = millis();
}
void detenerSistema(String mensaje) {
fijarPWM(PWM_STOP);
digitalWrite(PIN_MOTOR_ARRIBA, LOW);
digitalWrite(PIN_MOTOR_ABAJO, LOW);
digitalWrite(CHAPA_PUERTA, HIGH);
sirenaDebeSonar = false;
estadoFisicoSirena = HIGH;
digitalWrite(PIN_ALARMA, HIGH);
estadoMotor = DETENIDO;
forzarRedraw = true;
}
void maquinaMotor() {
if (estadoMotor == DETENIDO || estadoMotor == FALLO_SENSORES) return;
unsigned long actualMillis = millis();
unsigned long tTranscurrido = actualMillis - tiempoInicioFase;
int pwmMax = mapPWM(cfg_vMax);
int pwmMin = mapPWM(cfg_vMin);
long tAcelMs = (long)cfg_tRampa * 1000;
long tDecelMs = (long)cfg_tRampa * 1000;
long tTotalViajeMs = tAcelMs + ((long)cfg_tVMax * 1000) + tDecelMs;
if (estadoMotor >= ACELERANDO && estadoMotor <= VEL_LENTA) {
long dt = actualMillis - ultimoTiempoCalculo;
if (motorAbriendo) posicionEstimadaMs += dt;
else posicionEstimadaMs -= dt;
}
ultimoTiempoCalculo = actualMillis;
if (sirenaDebeSonar) {
if (!cfg_sirenaModoCompleto && (actualMillis - tiempoInicioGlobalMovimiento) >= (unsigned long)cfg_sirenaTOn * 1000) {
sirenaDebeSonar = false;
digitalWrite(PIN_ALARMA, HIGH);
} else {
unsigned long tiempoEnEstadoAct = actualMillis - tiempoUltimoSirena;
if (estadoFisicoSirena == LOW && tiempoEnEstadoAct >= 600) {
estadoFisicoSirena = HIGH;
digitalWrite(PIN_ALARMA, HIGH);
tiempoUltimoSirena = actualMillis;
}
else if (estadoFisicoSirena == HIGH && tiempoEnEstadoAct >= 200) {
estadoFisicoSirena = LOW;
digitalWrite(PIN_ALARMA, LOW);
tiempoUltimoSirena = actualMillis;
}
}
}
switch (estadoMotor) {
case CHAPA_ACTIVA:
if (tTranscurrido >= cfg_chapaOn) {
digitalWrite(CHAPA_PUERTA, HIGH);
estadoMotor = PRE_RAMPA;
tiempoInicioFase = actualMillis;
}
break;
case PRE_RAMPA:
if (tTranscurrido >= cfg_chapaOff) {
activarMotorDireccion(motorAbriendo);
estadoMotor = ACELERANDO;
tiempoInicioFase = actualMillis;
ultimoTiempoCalculo = actualMillis;
}
break;
case ACELERANDO:
if (tTranscurrido <= tAcelMs) {
int pwmCalculado = map(tTranscurrido, 0, tAcelMs, PWM_STOP, pwmMax);
fijarPWM(pwmCalculado);
} else {
fijarPWM(pwmMax);
estadoMotor = VEL_MAXIMA;
tiempoInicioFase = actualMillis;
}
break;
case VEL_MAXIMA:
fijarPWM(pwmMax);
if (motorAbriendo && posicionEstimadaMs >= (tTotalViajeMs - tDecelMs)) {
estadoMotor = DESACELERANDO;
tiempoInicioFase = actualMillis;
}
else if (!motorAbriendo && posicionEstimadaMs <= tDecelMs) {
estadoMotor = DESACELERANDO;
tiempoInicioFase = actualMillis;
}
break;
case DESACELERANDO:
if (tTranscurrido <= tDecelMs) {
int pwmCalculado = map(tTranscurrido, 0, tDecelMs, pwmMax, pwmMin);
fijarPWM(pwmCalculado);
} else {
fijarPWM(pwmMin);
estadoMotor = VEL_LENTA;
}
break;
case VEL_LENTA:
fijarPWM(pwmMin);
break;
case FRENADO_EMERGENCIA:
if (tTranscurrido <= 600) {
int pwmCalculado = map(tTranscurrido, 0, 600, pwmAlChoque, PWM_STOP);
fijarPWM(pwmCalculado);
} else {
fijarPWM(PWM_STOP);
if (causaEsSobrecorriente) {
estadoMotor = PAUSA_INVERSION;
tiempoInicioFase = actualMillis;
} else {
detenerSistema("PARADA POR USUARIO");
}
}
break;
case PAUSA_INVERSION:
if (tTranscurrido >= 800) {
iniciarMovimiento(!motorAbriendo);
}
break;
}
}
// ============================== LÓGICA DE MENÚS Y PANTALLA =====================
void gestionarBotones() {
bool btnAdd = (digitalRead(PIN_BTN_ADD) == LOW);
bool btnMinus = (digitalRead(PIN_BTN_MINUS) == LOW);
int lecturaOK = digitalRead(PIN_BTN_OK);
unsigned long actual = millis();
bool flagOk = false;
if (actual > 2000) {
if (estadoAnteriorOK == HIGH && lecturaOK == LOW) {
flagOk = true;
delay(50);
}
}
estadoAnteriorOK = lecturaOK;
if (flagOk) {
if (menuContext == 0 && estadoMotor == DETENIDO) {
menuContext = 10; menuCursor = 0; forzarRedraw = true;
}
else if (!isEditing && menuContext >= 10 && menuContext <= 50) {
if (menuContext == 10) {
if (menuCursor == 0) { menuContext = 20; menuCursor = 0; }
else if (menuCursor == 1) { menuContext = 30; menuCursor = 0; }
else if (menuCursor == 2) { menuContext = 40; menuCursor = 0; }
else if (menuCursor == 3) {
menuContext = 103;
isEditing = true;
editTempVal = (cfg_limCorriente / 5) * 5;
}
else if (menuCursor == 4) { menuContext = 50; menuCursor = 0; }
else if (menuCursor == 5) { menuContext = 0; menuCursor = 0; }
}
else if (menuContext == 20) {
if (menuCursor == 4) { menuContext = 10; menuCursor = 0; }
else { menuContext = 200 + menuCursor; isEditing = true;
if(menuCursor==0) editTempVal = cfg_tRampa;
if(menuCursor==1) editTempVal = cfg_vMax;
if(menuCursor==2) editTempVal = cfg_tVMax;
if(menuCursor==3) editTempVal = cfg_vMin;
}
}
else if (menuContext == 30) {
if (menuCursor == 3) { menuContext = 10; menuCursor = 1; }
else { menuContext = 300 + menuCursor; isEditing = true;
if(menuCursor==0) editTempVal = cfg_chapaEn ? 1 : 0;
if(menuCursor==1) editTempVal = cfg_chapaOn;
if(menuCursor==2) editTempVal = cfg_chapaOff;
}
}
else if (menuContext == 40) {
if (menuCursor == 3) { menuContext = 10; menuCursor = 2; }
else { menuContext = 400 + menuCursor; isEditing = true;
if(menuCursor==0) editTempVal = cfg_sirenaEn ? 1 : 0;
if(menuCursor==1) editTempVal = cfg_sirenaModoCompleto ? 1 : 0;
if(menuCursor==2) editTempVal = cfg_sirenaTOn;
}
}
else if (menuContext == 50) {
if (menuCursor == 0) { menuContext = 60; }
else if (menuCursor == 1) { menuContext = 61; }
else if (menuCursor == 2) { menuContext = 10; menuCursor = 4; }
}
forzarRedraw = true;
}
else if (menuContext == 60 || menuContext == 61) {
menuContext = 50;
forzarRedraw = true;
}
else if (isEditing) {
if(menuContext == 103) { cfg_limCorriente = editTempVal; menuContext = 10; }
else if(menuContext == 200) { cfg_tRampa = editTempVal; menuContext = 20; }
else if(menuContext == 201) { cfg_vMax = editTempVal; menuContext = 20; }
else if(menuContext == 202) { cfg_tVMax = editTempVal; menuContext = 20; }
else if(menuContext == 203) { cfg_vMin = editTempVal; menuContext = 20; }
else if(menuContext == 300) { cfg_chapaEn = (editTempVal == 1); menuContext = 30; }
else if(menuContext == 301) { cfg_chapaOn = editTempVal; menuContext = 30; }
else if(menuContext == 302) { cfg_chapaOff = editTempVal; menuContext = 30; }
else if(menuContext == 400) { cfg_sirenaEn = (editTempVal == 1); menuContext = 40; }
else if(menuContext == 401) { cfg_sirenaModoCompleto = (editTempVal == 1); menuContext = 40; }
else if(menuContext == 402) { cfg_sirenaTOn = editTempVal; menuContext = 40; }
guardarConfiguracion();
isEditing = false;
lcd.clear(); lcd.setCursor(0,0); lcd.print(" GUARDADO! ");
delay(600);
forzarRedraw = true;
}
}
if ((btnAdd || btnMinus) && (actual - tiempoUltimoBoton >= intervaloBoton)) {
tiempoUltimoBoton = actual;
if (!isEditing && menuContext >= 10 && menuContext <= 50) {
if (btnAdd) menuCursor++;
if (btnMinus) menuCursor--;
int maxCursor = 0;
if (menuContext == 10) maxCursor = 5;
if (menuContext == 20) maxCursor = 4;
if (menuContext == 30) maxCursor = 3;
if (menuContext == 40) maxCursor = 3;
if (menuContext == 50) maxCursor = 2;
if (menuCursor < 0) menuCursor = 0;
if (menuCursor > maxCursor) menuCursor = maxCursor;
forzarRedraw = true;
}
else if (isEditing) {
int salto = 1;
if (menuContext == 103) salto = 5;
if (menuContext == 301 || menuContext == 302) salto = 50;
if (btnAdd) editTempVal += salto;
if (btnMinus) editTempVal -= salto;
if(editTempVal < 0) editTempVal = 0;
if(menuContext == 103 && editTempVal > 4095) editTempVal = 4095;
if((menuContext == 201 || menuContext == 203) && editTempVal > 25) editTempVal = 25;
if((menuContext == 300 || menuContext == 400 || menuContext == 401) && editTempVal > 1) editTempVal = 1;
forzarRedraw = true;
}
}
}
void dibujarMenu() {
if (!forzarRedraw && menuContext != 60 && menuContext != 0) return;
if (menuContext == 0) {
static bool lastSensorA = false;
static bool lastSensorC = false;
static EstadoPuerta lastEstadoMotor = DETENIDO;
bool actualSensorA = (digitalRead(SENSOR_ABIERTO) == LOW);
bool actualSensorC = (digitalRead(SENSOR_CERRADO) == LOW);
if (forzarRedraw || actualSensorA != lastSensorA || actualSensorC != lastSensorC || estadoMotor != lastEstadoMotor) {
lcd.clear();
if (estadoMotor == FALLO_SENSORES) {
lcd.setCursor(0, 0); lcd.print(" ERROR CRITICO ");
lcd.setCursor(0, 1); lcd.print(" AMBOS SENSORES ");
}
else if (estadoMotor == FRENADO_EMERGENCIA || estadoMotor == PAUSA_INVERSION) {
lcd.setCursor(0, 0); lcd.print(" FRENANDO... ");
lcd.setCursor(0, 1); lcd.print(causaEsSobrecorriente ? "ANTIAPLASTAMIENT" : " POR BOTON STOP ");
}
else if (estadoMotor != DETENIDO) {
lcd.setCursor(0, 0); lcd.print(motorAbriendo ? " ABRIENDO... " : " CERRANDO... ");
lcd.setCursor(0, 1); lcd.print(" EN MOVIMIENTO ");
}
else {
if (paradaForzada) {
lcd.setCursor(0, 0); lcd.print(" PARADA ");
lcd.setCursor(0, 1); lcd.print(" DE EMERGENCIA ");
}
else if (!actualSensorA && !actualSensorC) {
lcd.setCursor(0, 0); lcd.print(" ERROR ");
lcd.setCursor(0, 1); lcd.print(" NO SENSOR ");
}
else {
lcd.setCursor(0, 0);
if (actualSensorA) lcd.print(" PUERTA ABIERTA ");
else if (actualSensorC) lcd.print(" PUERTA CERRADA ");
lcd.setCursor(0, 1);
lcd.print(" EN ESPERA ");
}
}
lastSensorA = actualSensorA;
lastSensorC = actualSensorC;
lastEstadoMotor = estadoMotor;
forzarRedraw = false;
}
}
else if (!isEditing && menuContext >= 10 && menuContext <= 50) {
if (menuContext == 10) mostrarSubMenu(menuCursor, menuPrin, 6);
if (menuContext == 20) mostrarSubMenu(menuCursor, menuTRamp, 5);
if (menuContext == 30) mostrarSubMenu(menuCursor, menuChapa, 4);
if (menuContext == 40) mostrarSubMenu(menuCursor, menuSirena, 4);
if (menuContext == 50) mostrarSubMenu(menuCursor, menuTestInfo, 3);
forzarRedraw = false;
}
else if (isEditing) {
lcd.clear();
lcd.setCursor(0, 0);
if(menuContext == 103) lcd.print("LIM CORRIENTE:");
else if(menuContext == 200) lcd.print("T. Rampa (s):");
else if(menuContext == 201) lcd.print("Vel. Max (0-25):");
else if(menuContext == 202) lcd.print("T. Vel Max (s):");
else if(menuContext == 203) lcd.print("Vel. Min (0-25):");
else if(menuContext == 300 || menuContext == 400) lcd.print("Estado:");
else if(menuContext == 301) lcd.print("Tiempo ON (ms):");
else if(menuContext == 302) lcd.print("Pre-Rampa (ms):");
else if(menuContext == 401) lcd.print("Modo Sirena:");
else if(menuContext == 402) lcd.print("T.ON Inicio (s):");
lcd.setCursor(0, 1);
if(menuContext == 300 || menuContext == 400) {
lcd.print(editTempVal == 1 ? "ON " : "OFF");
} else if (menuContext == 401) {
lcd.print(editTempVal == 1 ? "COMPLETO" : "INICIO ");
} else {
lcd.print(editTempVal);
lcd.print(" ");
}
forzarRedraw = false;
}
else if (menuContext == 60) {
if (millis() - ultimoRefrescoTest >= 200) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("S.P_C S.P_A P_EM");
lcd.setCursor(2, 1);
lcd.print(digitalRead(SENSOR_CERRADO));
lcd.setCursor(8, 1);
lcd.print(digitalRead(SENSOR_ABIERTO));
lcd.setCursor(14, 1);
lcd.print(digitalRead(PIN_PARADA_EMERGENCIA));
ultimoRefrescoTest = millis();
}
}
else if (menuContext == 61) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("CICLOS COMPLET:");
lcd.setCursor(0, 1);
lcd.print(ciclosTotales);
forzarRedraw = false;
}
}
void mostrarSubMenu(int cursor, String menus[], int size) {
lcd.clear();
String l1 = "", l2 = "";
if (cursor % 2 == 0) {
lcd.setCursor(0, 0); lcd.write(byte(0));
l1 = menus[cursor];
if (cursor + 1 < size) l2 = menus[cursor + 1];
} else {
l1 = menus[cursor - 1];
lcd.setCursor(0, 1); lcd.write(byte(0));
l2 = menus[cursor];
}
lcd.setCursor(1, 0); lcd.print(l1);
lcd.setCursor(1, 1); lcd.print(l2);
}
// ============================== GESTIÓN EEPROM =================================
void cargarConfiguracion() {
memoria.begin("config", false);
cfg_tRampa = memoria.getInt("tRampa", 3);
cfg_vMax = memoria.getInt("vMax", 20);
cfg_tVMax = memoria.getInt("tVMax", 20);
cfg_vMin = memoria.getInt("vMin", 10);
cfg_chapaEn = memoria.getBool("chapaEn", true);
cfg_chapaOn = memoria.getInt("chapaOn", 500);
cfg_chapaOff = memoria.getInt("chapaOff", 800);
cfg_sirenaEn = memoria.getBool("sirEn", true);
cfg_sirenaModoCompleto = memoria.getBool("sirMod", false);
cfg_sirenaTOn = memoria.getInt("sirTOn", 3);
cfg_limCorriente = memoria.getInt("limCorr", 4000);
if (cfg_limCorriente > 4095) cfg_limCorriente = 4095;
cfg_limCorriente = (cfg_limCorriente / 5) * 5;
ciclosTotales = memoria.getLong("ciclos", 0);
}
void guardarConfiguracion() {
memoria.putInt("tRampa", cfg_tRampa);
memoria.putInt("vMax", cfg_vMax);
memoria.putInt("tVMax", cfg_tVMax);
memoria.putInt("vMin", cfg_vMin);
memoria.putBool("chapaEn", cfg_chapaEn);
memoria.putInt("chapaOn", cfg_chapaOn);
memoria.putInt("chapaOff", cfg_chapaOff);
memoria.putBool("sirEn", cfg_sirenaEn);
memoria.putBool("sirMod", cfg_sirenaModoCompleto);
memoria.putInt("sirTOn", cfg_sirenaTOn);
memoria.putInt("limCorr", cfg_limCorriente);
memoria.putLong("ciclos", ciclosTotales);
}
Comments
Post a Comment