En esta segunda parte del proyecto vamos a implementar la secuencia de luces con los LEDs.

La idea es que los LEDs se enciendan y se apaguen completando la secuencia en ambas direcciones tal y como puedes ver en el siguiente vídeo:

Música de https://www.fiftysounds.com/es/

Por ahora nos olvidamos de los pulsadores y del display LCD.

Sketch

Este no es el sketch completo, puesto que es bastante largo y complejo, por lo que comenzaremos implementando un sketch más sencillo que puedas probar en tu Arduino y que genere la secuencia de luces del juego. A partir del mismo, en las siguientes partes del proyecto, iremos añadiendo código para ampliar las funcionalidades hasta completar la implementación total del juego.

/*********************
    DECLARACIONES
**********************/
const int LEDS [] = {0,1,4,5,6,7,8,9,10,11};
int time_led =1000;


/*********************
    CONFIGURACIÓN
**********************/
void setup() {
 for(int i=0; i<10; i++){
   pinMode(LEDS[i], OUTPUT);
 }
}


/*********************
    FUNCIONES
**********************/
void clean (){
 for(int i=0; i<10; i++){
   digitalWrite(LEDS[i], LOW);
 }
}

void led(int i){
  digitalWrite(LEDS[i], HIGH);
  delay(time_led);
  digitalWrite(LEDS[i], LOW);
}

void sequence(){
 clean ();
 for(int i=2; i<10; i++){
   led(i);
 }
 clean ();
 for(int i=7; i>=0; i--){
   led(i);
 }
}


/*********************
    FUNCIÓN LOOP
**********************/
void loop() {
 sequence();
}

A continuación vamos a ver en detalle cada una de las partes del sketch. Ten a mano el circuito para entenderlo todo bien.

Declaraciones

En la sección de declaraciones del sketch tenemos una constante a la que he llamado LEDS y una variable entera a la que he llamado time_led:

const int LEDS [] = {0,1,4,5,6,7,8,9,10,11};
int time_led =1000;

La constante LEDS es un array de enteros en el que vamos a almacenar los pines digitales en los que están conectados los leds (revisa el circuito). Si los has conectado a otros pines distintos a los míos debes cambiar estos valores. En mi caso son los pines digitales 0, 1, 4, 5, 6, 7, 8, 9, 10 y 11:

Es importante que estos valores estén en el mismo orden que los leds para que la secuencia sea consecutiva cuando se iluminen.

En cuanto a la variable time_led, son los mili segundos que permanecerá encendido cada led. Inicialmente yo he puesto 1000 ms que son 1s. Si quieres poner otro valor, adelante.

Tras cada pulsación de un jugador decrementaremos este valor para que el tiempo que permanecen encendidos los leds sea menor y de esta forma la secuencia vaya más rápido, aumentando así la dificultad del juego.

Configuración

Dentro de la función setup() debemos configurar los pines digitales en los que están conectados los leds.

Tienes la opción de configurar cada pin de forma individual usando la función pinMode() con cada uno, pero tendrás que escribirla 10 veces.

La ventaja de haber declarado un array con todos los pines es que esta tarea se simplifica si usas un bucle for, por lo que solo tendrás que usar la función pinMode() una vez:

void setup() {
 for(int i=0; i<10; i++){
   pinMode(LEDS[i], OUTPUT);
 }
}

Como puedes apreciar en el código, el for itera desde 0 (int i=0) hasta 9 (i<10) incluidos, es decir, las posiciones del array.

A la función pinMode() le indicamos el pin que queremos configurar con LEDS[i]. Recuerda que LEDS es el array, por lo que si la variable i tiene valor 0 le estaríamos pasando el valor de la posición 0 del array, es decir, el pin 0:

Si i tiene valor 5 le estaríamos pasando el valor de dicha posición, es decir 7:

Y lo mismo con el resto del array.

Todos los pines digitales en los que hay leds conectados se configuran como salida, por eso el segundo parámetro de pinMode es OUTPUT.

Y con esto dejaríamos todos los pines con leds listos.

Funciones

He declarado 3 funciones: clean(), led() y sequence().

Función clean()

La función clean() apaga todos los leds:

void clean (){
 for(int i=0; i<10; i++){
   digitalWrite(LEDS[i], LOW);
 }
}

Es similar a la función setup(), utilizo de nuevo el bucle for para poder iterar por todos los pines digitales almacenados en el array LEDS. La diferencia es que ahora tenemos que usar digitalWrite para apagar los leds. Para ello enviamos como segundo parámetro LOW.

La función led() ilumina un led durante un tiempo concreto y después lo apaga:

void led(int i){
  digitalWrite(LEDS[i], HIGH);
  delay(time_led);
  digitalWrite(LEDS[i], LOW);
}

Si te fijas, la función recibe como parámetro una variable entera (int i). Se trata del índice del array LEDS correspondiente al led que queremos encender. De esto se encarga digitalWrite(LEDS[i], HIGH).

Si la función recibe i con valor 5 iluminará el led de la posición 5 del array, en este caso el led conectado al pin digital 7:

A continuación, delay(time_led) hará que la ejecución se pare el tiempo indicado por time_led, en nuestro caso 1000 ms (1s). Cuando este tiempo se agote se ejecutará digitalWrite(LEDS[i], LOW) y se apagará el led.

Función sequence()

La función sequence() es la encargada de encender y apagar los leds en el orden correcto:

void sequence(){
 clean ();
 for(int i=2; i<10; i++){
   led(i);
 }
 clean ();
 for(int i=7; i>=0; i--){
   led(i);
 }
}

Vamos a dividir esta función en 2 partes para entenderla bien.

Empezaremos por este fragmento de código. Es el encargado de hacer la secuencia de derecha a izquierda:

clean ();
for(int i=2; i<10; i++){
 led(i);
}

En la primera línea se ejecuta la función clean() para apagar todos los leds.

Después, el bucle for se encarga de recorrer todos los leds del array menos los 2 primeros. Esto es así porque estas 2 posiciones se corresponden con los leds rojo y naranja del lado derecho y la secuencia siempre debe empezar en un led verde:

Por cada iteración del bucle for se ejecuta la función led(), que recibe como parámetro la variable i. Como ya vimos anteriormente, la función led() enciende y apaga el led de la posición que pasamos como parámetro.

Una vez el led se apaga, el bucle pasa a la siguiente iteración y se repite todo el proceso con el siguiente led, consiguiendo así la secuencia.

Veamos ahora el resto del código encargado de hacer la secuencia de izquierda a derecha:

clean();
for(int i=7; i>=0; i--){
   led(i);
}

Si comparas este bloque de código con el anterior verás que se parecen bastante. La diferencia principal está en el bucle for.

Como puedes ver se ejecuta clean() al inicio. De esta forma nos aseguramos de que estén todos los leds apagador antes de hacer la secuencia.

El bucle for recorre el array, pero en esta ocasión al revés, puesto que la secuencia cambia de sentido. Para conseguir esto hay que empezar en la posición 7 del array y recorrerlo al revés hasta llegar a la posición 0 (incluida):

Por eso el bucle for en esta ocasión es así:

for(int i=7; i>=0; i--)

Comienza en 7 (i=7), va en orden inverso (i–) hasta llegar a la posición 0 (i>=0).

Ya te habrás dado cuenta que la función sequence() en realidad genera dos secuencias, una de derecha a izquierda y otra de izquierda a derecha. Si ejecutamos muchas veces seguidas esta función conseguiríamos el efecto de ping-png, pero de esto ya se encarga la función loop que vamos a ver a continuación.

Función loop

La función loop() es muy sencilla. Simplemente llama a la función sequence() para que se ejecute:

void loop() {
 sequence();
}

Ya vimos anteriormente que la función sequence() contiene todo el código necesario para generar la secuencia de leds en ambos sentidos, por lo que no necesitamos más código aquí por ahora.

Carga el sketch en tu Arduino y comprueba que los leds se iluminan igual que en el vídeo del inicio.

Te espero en la parte 2 del proyecto para implementar la lógica de los botones.