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. 3, // Rele 2. 4, // 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 }; /* 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 = 50; 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 Salida_Rele1: digitalWrite(Rele_Pin[Rele1], HIGH); break; case Espera_Rele2: digitalWrite(Rele_Pin[Rele1], LOW); break; case Salida_Rele2: digitalWrite(Rele_Pin[Rele2], HIGH); break; case Espera_Rele3: digitalWrite(Rele_Pin[Rele2], LOW); break; case Salida_Rele3: digitalWrite(Rele_Pin[Rele3], HIGH); break; case Estado_Final: digitalWrite(Rele_Pin[Rele3], LOW); 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], LOW); } pinMode(Pulsador_Pin, INPUT); 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: { const bool pulsador_estado_cambiado = leer_cambio_de_estado(pulsador, tiempo); if (pulsador_estado_cambiado && pulsador.estado == HIGH) { estado_actual = ejecutar_transicion(estado_actual, tiempo); } break; } } if (estado_actual != estado_original) { actualizar_salida(estado_actual); } }