Semáforo ferroviario

Buenas a todos.

Estoy con un proyecto de recrear un semáforo ferroviario como los que hay a la entrada de las estaciones.

Tiene cuatro colores (verde, rojo, amarillo y blanco). Y a diferencia de los de coches, se pueden encender dos luces a la vez y estar fijas o parpadeando.

En total 9 señales diferentes que controlo con un If según el número que se introduce en un keypad.

El problema le tengo cuando tengo que tener una luz intermitente.

En ese caso para que me haga el bucle (high/delay/low/delay) le he puesto un while, pero no consigo que al pulsar otra tecla salga y pase a otra opción del if.

Espero que alguien me pueda ayudar.

Muchas gracias y un saludo

¿Puedes compartir tu código por favor?
Utilice la etiqueta de código para mostrarlo correctamente </>



#include <Keypad.h>     // importa libreria Keypad


const byte FILAS = 4;     // define numero de filas
const byte COLUMNAS = 4;    // define numero de columnas
char keys[FILAS][COLUMNAS] = {    // define la distribucion de teclas
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte pinesFilas[FILAS] = {6,7,8,9};   // pines correspondientes a las filas
byte pinesColumnas[COLUMNAS] = {10,11,12,13}; // pines correspondientes a las columnas

Keypad teclado = Keypad(makeKeymap(keys), pinesFilas, pinesColumnas, FILAS, COLUMNAS);  // crea objeto

char TECLA;       // almacena la tecla presionada

int VERDE = 2; //variable de la luz verde
int ROJO = 3; // variable de la luz roja
int AMARILLO = 4; //variable de la luz amarilla
int BLANCO = 5; // variable de la luz blanca


void setup() {
  // put your setup code here, to run once:
pinMode(VERDE,OUTPUT); //definicion de las variables como salida
pinMode(ROJO,OUTPUT);
pinMode(AMARILLO,OUTPUT);
pinMode(BLANCO,OUTPUT);

digitalWrite(VERDE,LOW); // inicializacion de las luces con la orden de parada por defecto.
digitalWrite(ROJO,HIGH);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);
  
 Serial.begin(9600);      // inicializa comunicacion serie
}


void loop() {
  
 TECLA = teclado.getKey();   // obtiene tecla presionada y asigna a variable


 if (TECLA!=NO_KEY) {       // comprueba que se haya presionado una tecla
digitalWrite(VERDE,LOW);
digitalWrite(ROJO,HIGH);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);}

if (TECLA == '1'){// OPCION 1 VIA LIBRE
  digitalWrite(VERDE,HIGH);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);}

if (TECLA == '2'){// OPCION 2 VIA LIBRE CONDICIONAL
  char PARO;
  while(PARO !='2'){
   
digitalWrite(VERDE,HIGH);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);
delay(250);
digitalWrite(VERDE,LOW);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);
delay(250);
  PARO = teclado.getKey();


}}

if (TECLA=='3'){

  digitalWrite(VERDE,HIGH);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,HIGH);
digitalWrite(BLANCO,LOW);
}
  if (TECLA=='4'){

  digitalWrite(VERDE,LOW);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,HIGH);
digitalWrite(BLANCO,LOW);
}
    if (TECLA=='5'){
digitalWrite(VERDE,LOW);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,HIGH);
digitalWrite(BLANCO,LOW);
delay(250);
digitalWrite(VERDE,LOW);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);
delay(250);

 if (TECLA=='6'){

  digitalWrite(VERDE,LOW);
digitalWrite(ROJO,HIGH);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);
}
     if (TECLA=='7'){
digitalWrite(VERDE,LOW);
digitalWrite(ROJO,HIGH);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,HIGH);
delay(250);
digitalWrite(VERDE,LOW);
digitalWrite(ROJO,HIGH);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,LOW);
delay(250);
}
 if (TECLA=='8'){

  digitalWrite(VERDE,LOW);
digitalWrite(ROJO,HIGH);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,HIGH);

 if (TECLA=='9'){

digitalWrite(VERDE,LOW);
digitalWrite(ROJO,LOW);
digitalWrite(AMARILLO,LOW);
digitalWrite(BLANCO,HIGH);
}
}}}

Generalmente evito el uso de delay() pero para no cambiar la forma en que lo has programado, prueba agregando un delay de al menos 500 mseg inmediatamente debajo del lazo while(), así cuando sale del mismo te da tiempo a soltar la tecla, sino va a volver a leer que está pulsada.
Ten en cuenta que al microprocesador le lleva apenas unos microsegundos salir del while() y volver a leer el teclado, es mucho más veloz de lo que tú tardas en soltar la tecla.

Saludos

PD: Por si no queda claro

while(PARO !='2'){
// lo que sigue dentro del lazo...
}
delay(500); 

En el único caso que se puede usar delay() es cuando haces algo FIJO. Un semáforo que no atiende a las vias, y solo hace una secuencia determinada es un buen caso, como un BLINK mas complicado.
Lo mejor es usar millis() para lo cual Documentación tiene excelentes tutoriales.
Eso te permitirá hacer lo que no te imaginas ahora.

Hola. @ea1ihz
creo que el funcionamiento es correcto y al pulsar otra tecla sale del while que crea la intermitencia. El unico inconveniente es que debes mantener esa tecla pulsada al menos 0.5 seg, (suma de los dos delays), no es tan instantanea como las otras.
Si quieres evitar esto tendras que hacerle caso a @Surbyte
Saludos.

No, si pulsa otra tecla no sale del while(), sale justamente con una nueva pulsación de la tecla "2"

while(PARO != "2") {

entonces sale del while(), evalúa los demás if() en cuestión de useg y lo mas probable al volver a leer las teclas al inicio del loop() es que encuentre "2" todavía pulsada.

Convengamos que no es la mejor forma de encarar este problema, por eso le aclaré que intentaba no modificar su filosofía, claramente yo lo haría de otra forma pero lo importante es que la idea general está bien, la lógica está bien, y eso es el 90% de la tarea resuelta. :wink:

Efectivamente, no habia comprendido bien la condicion del while pero el quiere:

Luego hay que cambiar ese while porque no funciona.
En su código donde el pone:

char PARO;
while(PARO !='2'){

Se podria poner:

char PARO = NO_KEY;
while (PARO == '2' || PARO == NO_KEY) {

Si no me he confundido al depurar mediante Serial.print, millis, asignaciones, etc... Porque no tengo un keypad. Que lo pruebe @ea1ihz a ver si asi va
Saludos.

Me gustó. :wink:

Como suelen decir "Dos cabezas piensan más que una" :smiley: