enum Reles { Rele1, Rele2, Rele3, MAX_RELE, }; /* Configuracion */ // Tiempos de espera antes de emitir senyales de salida de rele. // Unidades en milisegundos (1s = 1000ms). const unsigned long TIEMPO_ESPERA_SALIDA_MS[MAX_RELE] = { 5000, // Rele 1. 2000, // Rele 2. 3000, // Rele 3. }; // Pines reles. // // Pines 0 y 1 en Arduino UNO son para comunicacion serie, no usar. const int Rele_Pin[MAX_RELE] = { 2, // Rele 1. 4, // Rele 2. 3, // Rele 3. }; // Pin pulsador. const int Pulsador_Pin = 5; enum Estado { Estado_Inicial, Espera_Rele1, Salida_Rele1, Espera_Rele2, Salida_Rele2, Espera_Rele3, Salida_Rele3, Estado_Final, MAX_ESTADO, }; enum Transicion { Automatica, // Transicion automatica. Retardada, // Transicion automatica retardada. Manual, // Transicion al pulsar boton. }; const Transicion transiciones[MAX_ESTADO] = { Manual, // Estado_Inicial -> Espera_Rele1 Retardada, // -> Salida_Rele1 Manual, // -> Espera_Rele2 Retardada, // -> Salida_Rele2 Manual, // -> Espera_Rele3 Retardada, // -> Salida_Rele3 Manual, // -> Estado_Final Automatica, // -> Estado_Inicial }; constexpr int RELE_ACTIVADO = LOW; constexpr int RELE_DESACTIVADO = HIGH; /* Entrada digital con debounce. */ // Tiempo en el que la senyal debe permanecer con un valor constante para // que se ejecute la lectura logica de la senyal. const unsigned long DEBOUNCE_DELAY_MS = 25; // Entrada digital. struct EntradaDigital { int pin; // Pin de entrada. int estado; // Estado logico actual, LOW o HIGH. int ultima_senyal; // Ultima senyal de entrada, LOW o HIGH. unsigned long debounce_time_ms; // Tiempo del ultimo cambio de estado en la entrada. }; // Lee un cambio de estado de la entrada digital. // Devuelve cierto si se ejecuta un cambio de estado logico, falso en caso contrario. bool leer_cambio_de_estado(EntradaDigital& entrada, unsigned long tiempo) { const int senyal_actual = digitalRead(entrada.pin); bool estado_cambiado = false; if (senyal_actual != entrada.ultima_senyal) { entrada.debounce_time_ms = tiempo; } else if ( ((tiempo - entrada.debounce_time_ms) >= DEBOUNCE_DELAY_MS) && (senyal_actual != entrada.estado) ){ entrada.estado = senyal_actual; estado_cambiado = true; } entrada.ultima_senyal = senyal_actual; return estado_cambiado; } /* Programa principal. */ Estado estado_actual; EntradaDigital pulsador; unsigned long tiempo_ultima_transicion; // Ejecuta una transicion de estado y devuelve el nuevo estado. Estado ejecutar_transicion(Estado estado, unsigned long tiempo) { tiempo_ultima_transicion = tiempo; return Estado((estado + 1) % MAX_ESTADO); } // Actualiza la salida despues de un cambio de estado. void actualizar_salida(Estado estado_actual) { switch (estado_actual) { case Estado_Inicial: break; case Espera_Rele1: digitalWrite(LED_BUILTIN, HIGH); break; case Salida_Rele1: digitalWrite(LED_BUILTIN, LOW); digitalWrite(Rele_Pin[Rele1], RELE_ACTIVADO); break; case Espera_Rele2: digitalWrite(LED_BUILTIN, HIGH); digitalWrite(Rele_Pin[Rele1], RELE_DESACTIVADO); break; case Salida_Rele2: digitalWrite(LED_BUILTIN, LOW); digitalWrite(Rele_Pin[Rele2], RELE_ACTIVADO); break; case Espera_Rele3: digitalWrite(LED_BUILTIN, HIGH); digitalWrite(Rele_Pin[Rele2], RELE_DESACTIVADO); break; case Salida_Rele3: digitalWrite(LED_BUILTIN, LOW); digitalWrite(Rele_Pin[Rele3], RELE_ACTIVADO); break; case Estado_Final: digitalWrite(Rele_Pin[Rele3], RELE_DESACTIVADO); break; default: break; } } // Devuelve el tiempo de espera para el estado dado. unsigned long get_tiempo_espera(Estado estado) { switch (estado) { case Espera_Rele1: return TIEMPO_ESPERA_SALIDA_MS[Rele1]; case Espera_Rele2: return TIEMPO_ESPERA_SALIDA_MS[Rele2]; case Espera_Rele3: return TIEMPO_ESPERA_SALIDA_MS[Rele3]; default: return 0; } } // Inicializacion. void setup() { const unsigned long tiempo = millis(); for (int i = 0; i < MAX_RELE; ++i) { pinMode(Rele_Pin[i], OUTPUT); digitalWrite(Rele_Pin[i], RELE_DESACTIVADO); } pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); pinMode(Pulsador_Pin, INPUT_PULLUP); estado_actual = Estado_Inicial; pulsador = (EntradaDigital) { .pin = Pulsador_Pin, .estado = LOW, .ultima_senyal = LOW, .debounce_time_ms = tiempo, }; tiempo_ultima_transicion = tiempo; } // Bucle principal. void loop() { const unsigned long tiempo = millis(); const Estado estado_original = estado_actual; switch (transiciones[estado_actual]) { case Automatica: estado_actual = ejecutar_transicion(estado_actual, tiempo); break; case Retardada: { const unsigned long tiempo_espera = get_tiempo_espera(estado_actual); if ( (tiempo - tiempo_ultima_transicion) >= tiempo_espera ) { estado_actual = ejecutar_transicion(estado_actual, tiempo); } break; } case Manual: { // Para una senyal INPUT_PULLUP, se lee LOW, no HIGH, cuando se presiona // el boton. const bool pulsador_estado_cambiado = leer_cambio_de_estado(pulsador, tiempo); if (pulsador_estado_cambiado && pulsador.estado == LOW) { estado_actual = ejecutar_transicion(estado_actual, tiempo); } break; } } if (estado_actual != estado_original) { actualizar_salida(estado_actual); } }