Cómo puedo encender leds con pulsadores independientes?

Hola , disculpen soy nuevo en todo esto del mundo del arduino, pero quisiera aprender más acerca de esto.

Bueno la razón por la que estoy aquí es por que necesito una ayuda para un pequeño proyecto que tengo que realizar en un arduino mega con 18 leds y no se si alguien podría ayudarme a como hacer la programación para el siguiente tema:

Hacer un juego de leds en el cual cada uno tenga su propio botón de encendido y una vez completado el encendido de todos los leds, al presionar otro botón (cualquiera o tal vez uno ajeno) se apaguen todos pero esta vez al encenderlos de nuevo cada cada botón enciende otro led (de modo que el encendido de cada led sea distinto a la primera parte, al azar) y así sucesivamente.

Cómo tendría que ser mi código, en este caso?

Hola,
No parece muy difícil lo que pretendes.¿ Tienes algo hecho?¿Conoces algo de programación?¿Sabes algo de electrónica?¿Ya has pensado dónde vas a colocar los pulsadores, digitales o analógicos?. Lo que está claro es que necesitaras la Random para seleccionar un led al azar para encenderlo. Y ya según lo plantes seguramente algún flag, variable booleana, para saber si estas en la primera vuelta o en la vuelta aleatoria, unos pocos if y mucha paciencia para definir los pines de entrada y los pines de salida.
Cuéntanos que tienes hecho.
Un saludo.

Si tengo conocimientos básicos de electrónica , solo me falta la programación , y sobre el circuito ya lo tengo armado

Hola Romer. Supongo que si rodripelto te pregunta si tienes ya algo avanzado es para que digas el qué y si puedes lo expongas/muestres en el foro lo que ya tienes encaminado para hacernos una mejor idea de cómo poder ayudarte.

Pero ya puestos a dar pistas "a ciegas", a lo del random que ya te ha propuesto rodripelto, yo añado el consejo de usar tres arrays. Uno para los LEDs, otro para los pulsadores y otro para relacionar aleatoriamente los pulsadores con los LEDs.

Hola Romer,

Aqui para que te ayuden deberas aportar algo de tu parte, en caso contrario el pedido de ayuda se entiende como un mero "haganmelo".

Contestando a tu pregunta. Si la duda es como hacer que un interruptor encienda tanto un led como otro mi respuesta es:

Lo normal es que cuando el interruptor X este ON se active el LED X y cuando este OFF se desactive el LED X. Tu lo que puedes hacer es que cuando el interruptor X este ON la variable boolean X este en TRUE y cuando este en OFF que la misma variable este en FALSE. Luego asignar esta variable al LED que tu quieras en cada momento via programacion. Mi pregunta es ¿Sabes programar para hacer lo normal? Si es asi, te resultara sencillo hacer lo que te he dicho, sino te sonara a chino.

Esa pregunta la acaban de hacer hace unos dias con no recuerdo la cantidad de leds pero eran menos que 18.

Busca. Pero veo que es una tarea escolar.

Mas alla que lo sea o no, empieza a pensar como programador.

Hacer un juego de leds en el cual cada uno tenga su propio botón de encendido y una vez completado el encendido de todos los leds, al presionar otro botón (cualquiera o tal vez uno ajeno) se apaguen todos pero esta vez al encenderlos de nuevo cada cada botón enciende otro led (de modo que el encendido de cada led sea distinto a la primera parte, al azar) y así sucesivamente.

Presionas y que ocurre con los leds? se prenden como?

Perdón por perderme XD, bueno aqui lo tengo acabado , solucioné parte del problema salvo que tengo que presionar el botón en un tiempo mayor a 0.5s , hay manera de regular esto?

int A[]={30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47};
int B[]={2,3,4,5,6,7,8,9,10,11,12,22,23,24,25,26,27,28};
int a;
int actual =0;
int ant = 0;
int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18;
int count=0;
int led;
int bott;

void setup(){
for(int i=0;i<=17;i++){
  pinMode(A[i],OUTPUT);
}
for(int i=0;i<=17;i++){
  pinMode(B[i],INPUT);
}
randomSeed(analogRead(A0));
Serial.begin(9600); 

}


void bottones(int x, int y,int actual, int ant){
a=digitalRead(B[y]);
if((a==HIGH)&&(ant==LOW)){
  actual=1-actual;
  delay(10);
}
ant=a;
if(actual==1){
digitalWrite(A[x],HIGH);
count=1+count;
delay(500);
}

}
int i=0;
void complejo(){
led=random(0,18);
bott=random(0,18);
a1=led;
b1=bott;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)){
    a2=led;
    b2=bott;
    i=1;
   }
}
i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)){
    a3=led;
    b3=bott;
    i=1;
   }
}  
i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)){
    a4=led;
    b4=bott;
    i=1;
   }
}
i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)){
    a5=led;
    b5=bott;
    i=1;
   }
} 
i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)){
    a6=led;
    b6=bott;
    i=1;
   }
} 
i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)){
    a7=led;
    b7=bott;
    i=1;
   }
}   
i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)){
    a8=led;
    b8=bott;
    i=1;
   }
}
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)){
    a9=led;
    b9=bott;
    i=1;
   }
}
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)){
    a10=led;
    b10=bott;
    i=1;
   }
}
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)){
    a11=led;
    b11=bott;
    i=1;
   }
}
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)){
    a12=led;
    b12=bott;
    i=1;
   }
} 
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)&&(a12 != led)&&(b12 != bott)){
    a13=led;
    b13=bott;
    i=1;
   }
}
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)&&(a12 != led)&&(b12 != bott)&&(a13 != led)&&(b13 != bott)){
    a14=led;
    b14=bott;
    i=1;
   }
} 
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)&&(a12 != led)&&(b12 != bott)&&(a13 != led)&&(b13 != bott)&&(a14 != led)&&(b14 != bott)){
    a15=led;
    b15=bott;
    i=1;
   }
}
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)&&(a12 != led)&&(b12 != bott)&&(a13 != led)&&(b13 != bott)&&(a14 != led)&&(b14 != bott)&&(a15 != led)&&(b15 != bott)){
    a16=led;
    b16=bott;
    i=1;
   }     
} 
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)&&(a12 != led)&&(b12 != bott)&&(a13 != led)&&(b13 != bott)&&(a14 != led)&&(b14 != bott)&&(a15 != led)&&(b15 != bott)&&(a16 != led)&&(b16 != bott)){
    a17=led;
    b17=bott;
    i=1;
   }     
}   
 i=0;
while( i==0){
  led=random(0,18);
  bott=random(0,18);
 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)&&(a12 != led)&&(b12 != bott)&&(a13 != led)&&(b13 != bott)&&(a14 != led)&&(b14 != bott)&&(a15 != led)&&(b15 != bott)&&(a16 != led)&&(b16 != bott)&&(a17 != led)&&(b17 != bott)){
    a18=led;
    b18=bott;
    i=1;
   }     
}                                    
}
void loop() {
for(int i=0;i<=17;i++){
  digitalWrite(A[i],LOW);
}
delay(2000);
complejo();
while(count<=18){
bottones(a1,b1,0,0);
bottones(a2,b2,0,0);
bottones(a3,b3,0,0);
bottones(a4,b4,0,0);
bottones(a5,b5,0,0);
bottones(a6,b6,0,0);
bottones(a7,b7,0,0);
bottones(a8,b8,0,0);
bottones(a9,b9,0,0);
bottones(a10,b10,0,0);
bottones(a11,b11,0,0);
bottones(a12,b12,0,0);
bottones(a13,b12,0,0);
bottones(a14,b14,0,0);
bottones(a15,b15,0,0);
bottones(a16,b16,0,0);
bottones(a17,b17,0,0);
bottones(a18,b18,0,0);


}
delay(2000);  
}

Hola,

El culpable pude ser el deley(500) que tienes en el método bottones.
Yo siempre digo que si el programa hace lo que queremos, el programa está bien, dicho esto el tuyo tiene muchos puntos de mejora.
Por partes, primero en el setup

 for(int i=0;i<=17;i++){
   pinMode(A,OUTPUT);
 }
 for(int i=0;i<=17;i++){
   pinMode(B,INPUT);
 }

Si tienes un for es para que haga algo, no solo dar vueltas.

 for(int i=0;i<=17;i++){
   pinMode(A[i],OUTPUT);
 }
 for(int i=0;i<=17;i++){
   pinMode(B[i],INPUT);
 }

Un programador siempre está intentando que su código sea legible y escribir la menor número de líneas posibles, así que usar bucles es una muy buena opción.
Por lo tanto analiza cómo puedes hacer esto.

if((a1 != led)&&(b1 != bott)){
     a2=led;
     b2=bott;
     i=1;
    }

Con for o while y un array, creo que es suficiente, para evitar esto

 if((a1 != led)&&(b1 != bott)&&(a2 != led)&&(b2 != bott)&&(a3 != led)&&(b3 != bott)&&(a4 != led)&&(b4 != bott)&&(a5 != led)&&(b5 != bott)&&(a6 != led)&&(b6 != bott)&&(a7 != led)&&(b7 != bott)&&(a8 != led)&&(b8 != bott)&&(a9 != led)&&(b9 != bott)&&(a10 != led)&&(b10 != bott)&&(a11 != led)&&(b11 != bott)&&(a12 != led)&&(b12 != bott)&&(a13 != led)&&(b13 != bott)&&(a14 != led)&&(b14 != bott)&&(a15 != led)&&(b15 != bott)&&(a16 != led)&&(b16 != bott)&&(a17 != led)&&(b17 != bott)){
     a18=led;
     b18=bott;
     i=1;
    }

OJO.
actual=1-actual; Primero creo que está mal, esa operación te puede dar números negativos, en todo caso sería actual= actual -1, pero esto es equivalente actual--;
Lo mismo con count=1+count; mejor count++;

Un saludo.

Hola buenas!

Probablemente haya llegado un poco tarde XD, aún así me pareció interesante el programa que tenia que hacer Romer, y decidí ponerme a hacerlo. Finalmente lo termine, y no se si ahora servirá de ayuda o no, pero bueno, ya que estoy lo paso. Además me gustaría que me dieran su opinión, para ver si puedo mejorar algo o lo que sea, y así aprendo cosas nuevas.

El programa lo hice con 4 botones y 4 leds, ya que en esencia es lo mismo. Aquí lo dejo:

int r[4]={6,7,8,9}; //le pongo estos valores para que por defecto no aparezacn ceros y no me de problemas
int a;
int b;

void setup() { 
 pinMode(1,INPUT);//boton
 pinMode(2,INPUT);//boton
 pinMode(3,INPUT);//boton
 pinMode(4,INPUT);//boton
 pinMode(5,OUTPUT);//led
 pinMode(6,OUTPUT);//led
 pinMode(7,OUTPUT);//led
 pinMode(8,OUTPUT);//led

}

void loop() {
 a=0;        
 while(a<=3){      
   do{
     r[a]=random(1,5);
     }
   while((r[0]==r[1])||(r[0]==r[2])||(r[0]==r[3])||(r[1]==r[2])||(r[1]==r[3])||(r[2]==r[3])); //compara todos los valores del array r[] para que no sean iguales en ningun momento
   a++;                          
 }

 while((digitalRead(5)==LOW)||(digitalRead(6)==LOW)||(digitalRead(7)==LOW)||(digitalRead(8)==LOW)){ 
   a=0;
   b=5;
   while((a<=3)&&(b<=8)){
     if(digitalRead(r[a])==HIGH){
       digitalWrite(b,HIGH);
       a++;
       b++;
     }    
   }
 }
 
 if((digitalRead(1)==HIGH)||(digitalRead(2)==HIGH)||(digitalRead(3)==HIGH)||(digitalRead(4)==HIGH)){ 
   digitalWrite(5,LOW);
   digitalWrite(6,LOW); 
   digitalWrite(7,LOW); 
   digitalWrite(8,LOW);
   r[0]=6;
   r[1]=7;
   r[2]=8;
   r[3]=9;
      
 }
}

Espero que sirva de ayuda, y que si hay alguna forma mejor de hacerlo que me lo digan, lo agradecería mucho. Gracias de antemano.

Un saludo!

(parte una de dos)

Acepto el reto de danke197. Hay miles de formas de hacerlo. Unas mejores que otras, y esta es mi propuesta.

Aprovecho para dar un par de sugerencias. La primera: el nombre de las variables no gasta memoria en el Arduino. El compilador de Arduino no mete infomación extra de depuración, así que va a ocupar lo mismo una variable que se llame a como si se llama nombreDeVariableLargaQueNoEsNadaDescriptiva. Así que recomiendo poner nombres no muy largos, pero sí descriptivos. Todo en mayúsculas si se trata de una constante. (He de reconocer que yo no soy muy bueno poniendo nombres a las variables, pero sí que pongo algo de empeño en ello... no mucho, pero algo es algo).

Así que nada de r, a o b para el nombre de las variables. Un "caso especial" es i (o cosas similares) en un pequeño bucle for.

Otra cosa es el uso de los arrays, arreglos, vectores (o como lo quieran llamar): si te encuentras con unas variables llamadas a1, a2, a3, a4, a5... creo que sería buena idea plantearse usar un array a[ ].

Así que voy a empezar definiendo, con ayuda de una constante, unos arrays:

const byte CANTIDAD_LEDS_Y_PULSADORES = 4;

const byte PIN_LEDS[CANTIDAD_LEDS_Y_PULSADORES] = {3, 5, 7, 9};

const byte PIN_PULSADORES[CANTIDAD_LEDS_Y_PULSADORES] = {2, 4, 6, 8};

byte ledAsignadoAlPulsador[CANTIDAD_LEDS_Y_PULSADORES];

¿Alguien sabría decirme para qué quiero las constantes que he definido? ¿Y la variable? Bueno, tal vez la variable necesite una explicación, pero las constantes creo que se explican por sí misma. Y supongo también que está claro qué son constantes y qué es variable.

Bueno, lo que tal vez necesita explicación es ledAsignadoAlPulsador. En este array guardaré la asignación aleatoria entre pulsadores y LEDs. En la posición 0 se guardará para el pulsador PIN_PULSADORES[0] un valor aleatorio entre 0 y CANTIDAD_LEDS_Y_PULSADORES menos 1 que corresponde a la posición dentro del array PIN_LEDS del LED que se le asigna a ese pulsador. Y así uno tras otro. En principio no debería de haber ningún elemento del array ledAsignadoAlPulsador con el valor CANTIDAD_LEDS_Y_PULSADORES (que es el número total de LEDs o pulsadores que controlamos) ya que empezamos a partir del valor 0 y terminaremos con el valor CANTIDAD_LEDS_Y_PULSADORES menos 1. Así que aprovecho que nunca ha de tener el valor CANTIDAD_LEDS_Y_PULSADORES y lo que haré es asignarlo cuando haya encendido el LED. De esta forma sabré que ya ha sido "usado" y podré llevar fácilmente el conteo de cuantos LEDs quedan por encender. También lo voy a aprovechar para inicializar el array antes de llenarlo con los valores aleatorios. Si tiene un valor distinto a CANTIDAD_LEDS_Y_PULSADORES entonces es que ya le he asignado un LED.

Los pines asignados (tanto para los LEDs como para los pulsadores) no tienen por qué ser consecutivos ni ir de dos en dos, se pueden poner los que se quieran y como se quieran. Lo que si no son cuatro, sino por ejemplo 10, se ha de definir la constante CANTIDAD_LEDS_Y_PULSADORES con el valor correspondiente, por ejemplo 10. Nótese que lo he definido todo tipo byte. Es porque no espero tener más de 256 LEDs y utiliza la mitad de memoria que un int. La memoria no es un recurso que sobre en un Arduino.

Según lo expuesto, en el setup() he de llenar ledAsignadoAlPulsador con el valor CANTIDAD_LEDS_Y_PULSADORES y luego inicializarlo con los valores de 0 a CANTIDAD_LEDS_Y_PULSADORES menos 1 en posiciones aleatorias. Sólo lo he llenar "a mano" la primera vez, al empezar, las veces posteriores se irá rellenando poco a poco según se van encendiendo los LEDs ya que es el valor que uso para indicarlo.

Ya de paso aprovecho el bucle para inicializar los pines de salida para los LEDs y de entrada para los pulsadores. Por cierto, el Arduino UNO tiene resistencias pull up internas que se pueden activar al configurar la entrada. Pues voy a usarlas y son resistencias externas que me ahorro (cada pulsador tendrá un extremo conectado directamente al pin de entrada del Arduino y el otro extremo dirécto a masa). Lo único que hay que tener en cuenta es que la entrada tendrá valor HIGH cuando no esté pulsado y LOW cuando se pulse. Así pues la función setup() me ha de quedar algo tal que así:

void setup() {
    randomSeed(analogRead(0));                                  // Siguiendo las sugerencias de la comunidad Arduino
    for (int i = 0; i < CANTIDAD_LEDS_Y_PULSADORES; i++) {      // Vamos a recorrer todos los elementos de los arrays
        ledAsignadoAlPulsador[i] = CANTIDAD_LEDS_Y_PULSADORES;      // Inicializamos cada elemento del array indicando que "está libre"
        pinMode(PIN_LEDS[i], OUTPUT);                               // Configuramoslos pines de los LEDs
        pinMode(PIN_PULSADORES[i], INPUT_PULLUP);                   // Configuramoslos pines de los pulsadores
    }
}

He añadido el randomSeed que recomienda Arduino para la aleotoriedad del random. Para quienes no sepan de qué va esto... Google es tu amigo.

Por simplificar, voy a hacer una cosa que no suelo hacer, y es no permitir que el loop() acabe hasta completar el encendido de todos los LEDs. Así que lo primero que se hará en el loop() es rellenar el array ledAsignadoAlPulsador aleatoriamente. Así que voy a meter los valores de 0 a CANTIDAD_LEDS_Y_PULSADORES menos 1 en posiciones aleatorias de ledAsignadoAlPulsador. Para estar seguro de que los meto en un lugar que no estuviera ya metido otro, miro si el valor de la ubicación aleatoria es CANTIDAD_LEDS_Y_PULSADORES (valor que inicialmente ya he metido en todo el array). Y ya de paso aprovecho para apagar todos los LEDs que es como debieran de estar en estos momentos. Así que el código inicial de loop() me queda algo tal que así:

void loop() {
    for (int i =  0; i < CANTIDAD_LEDS_Y_PULSADORES; i++) {             // Vamos a trabajar con todos los elementos uno a uno
        digitalWrite(PIN_LEDS[i], LOW);                                     // Apagamos cada uno de los LEDs
        while (true) {                                                      // Bucle infinito o hasta que se ejecute un break porque "ha encontrado hueco"
            byte indiceAleatorio = random(0, CANTIDAD_LEDS_Y_PULSADORES);               // Obtenemos una posición aleatoria
            if (ledAsignadoAlPulsador[indiceAleatorio] == CANTIDAD_LEDS_Y_PULSADORES) { // Si esa posición "está libre"...
                ledAsignadoAlPulsador[indiceAleatorio] = i;                                 // asignamos esa posición
                break;                                                                      // y salimos del bucle infinito
            }
        }
    }

Ya tenemos inicializado el array aleatoriamente así que ahora ha de entrar en un bucle que espera a que se pulsen los pulsadores y se enciendan todos los LEDs. (Insisto que esta solución no es muy de mi agrado, es más bien con fines didácticos). Así que el inicio del bucle será algo así como:

    for (int totalEncendidos = 0; totalEncendidos < CANTIDAD_LEDS_Y_PULSADORES; ) {

¡Ojo! No he puesto totalEncendidos++ después del segundo punto y coma. Y no lo he hecho por dos motivos, primero: porque se puede omitir. Segundo: porque no me interesa incrementarlo en cada iteración del bucle, sino cuando se de la condición de que se ha encendido un nuevo LED.

1 Like

(parte dos de dos)

¿Cuando se da la condición de que se ha de encender un LED? Pues cuando se encuentre pulsado el pulsador asociado mediante ledAsignadoAlPulsador. Si el valor fuera CANTIDAD_LEDS_Y_PULSADORES entonces es que ya se había encendido y no se ha de hacer nada. Esto último nos permite olvidarnos de los rebotes del pulsador ya que sólo hará efecto "la primera pulsación" descartando las repeticiones.

Así que valiéndome de otro bucle recorro pulsador a pulsador todos, viendo si está pulsado (recordar que en mi montaje es cuando la entrada está a nivel bajo, LOW). Si está pulsado y el LED "asociado" no es CANTIDAD_LEDS_Y_PULSADORES enciendo ese LED, lo "desasocio" e incremento totalEncendidos (ahora sí). En cuanto totalEncendidos llegue al valor CANTIDAD_LEDS_Y_PULSADORES se terminará el bucle. Este nuevo bucle nos quedará tal que así:

        for (int i = 0; i < CANTIDAD_LEDS_Y_PULSADORES; i++) {  // Vamos a verificar todos los pulsadores
            if (digitalRead(PIN_PULSADORES[i]) == LOW) {            // Si el pulsador está pulsado (con "pull up" y al pulsarlo se pone a masa la entrada)
                if (ledAsignadoAlPulsador[i] != CANTIDAD_LEDS_Y_PULSADORES) {   // Si aún no se ha encendido este LED...
                    digitalWrite(PIN_LEDS[ledAsignadoAlPulsador[i]], HIGH);         // lo encendemos
                    ledAsignadoAlPulsador[i] = CANTIDAD_LEDS_Y_PULSADORES;          // "lo marcamos" como ya encendido
                    totalEncendidos++;                                              // incrementamos el número de LEDs encendidos
                }
            }
        }

Mención especial creo que ha de tener la líena que enciende el LED.

digitalWrite(PIN_LEDS[ledAsignadoAlPulsador[ i ]], HIGH);

Lo que hace es que para el pulsador i localiza cual es su LED asignado (que ha de estar en la posición i del array ledAsignadoAlPulsador) que es ledAsignadoAlPulsador[ i ]. Y para saber cual es el pin de ese LED asignado se ha de obtener del array PIN_LEDS.

Nótese que suelo utilizar como nombre de variable para los bucles "triviales" la i, pero nótese también que no es una variable global, ni tampoco de la función. Es una variable cuyo ámbito es el bucle for que la usa.

Ahora ya sólo queda cerrar el bucle que controla que se han encendido todos los LEDs, y para evitar posibles rebotes del "último pulsador" vamos a esperar dos segundos antes de volver a empezar. Ya sé que no es una solución "redonda" ya que lo que debería de hacer es esperar a que se vuelva a pulsar algo antes de apagarlos todos y volver a empezar, pero eso ya lo dejo como ejercicio para casa.

El programa completo quedaría tal que así:

const byte CANTIDAD_LEDS_Y_PULSADORES = 4;
const byte PIN_LEDS[CANTIDAD_LEDS_Y_PULSADORES] = {3, 5, 7, 9};
const byte PIN_PULSADORES[CANTIDAD_LEDS_Y_PULSADORES] = {2, 4, 6, 8};
byte ledAsignadoAlPulsador[CANTIDAD_LEDS_Y_PULSADORES];

void setup() {
    randomSeed(analogRead(0));                                  // Siguiendo las sugerencias de la comunidad Arduino
    for (int i = 0; i < CANTIDAD_LEDS_Y_PULSADORES; i++) {      // Vamos a recorrer todos los elementos de los arrays
        ledAsignadoAlPulsador[i] = CANTIDAD_LEDS_Y_PULSADORES;      // Inicializamos cada elemento del array indicando que "está libre"
        pinMode(PIN_LEDS[i], OUTPUT);                               // Configuramoslos pines de los LEDs
        pinMode(PIN_PULSADORES[i], INPUT_PULLUP);                   // Configuramoslos pines de los pulsadores
    }
}

void loop() {
    for (int i =  0; i < CANTIDAD_LEDS_Y_PULSADORES; i++) {             // Vamos a trabajar con todos los elementos uno a uno
        digitalWrite(PIN_LEDS[i], LOW);                                     // Apagamos cada uno de los LEDs
        while (true) {                                                      // Bucle infinito o hasta que se ejecute un break porque "ha encontrado hueco"
            byte indiceAleatorio = random(0, CANTIDAD_LEDS_Y_PULSADORES);               // Obtenemos una posición aleatoria
            if (ledAsignadoAlPulsador[indiceAleatorio] != CANTIDAD_LEDS_Y_PULSADORES) { // Si esa posición "está libre"...
                ledAsignadoAlPulsador[indiceAleatorio] = i;                                 // asignamos esa posición
                break;                                                                      // y salimos del bucle infinito
            }
        }
    }
    for (int totalEncendidos = 0; totalEncendidos < CANTIDAD_LEDS_Y_PULSADORES; ) {
        for (int i = 0; i < CANTIDAD_LEDS_Y_PULSADORES; i++) {  // Vamos a verificar todos los pulsadores
            if (digitalRead(PIN_PULSADORES[i]) == LOW) {            // Si el pulsador está pulsado (con "pull up" y al pulsarlo se pone a masa la entrada)
                if (ledAsignadoAlPulsador[i] != CANTIDAD_LEDS_Y_PULSADORES) {   // Si aún no se ha encendido este LED...
                    digitalWrite(ledAsignadoAlPulsador[i], HIGH);                   // lo encendemos
                    ledAsignadoAlPulsador[i] = CANTIDAD_LEDS_Y_PULSADORES;          // "lo marcamos" como ya encendido
                    totalEncendidos++;                                              // incrementamos el número de LEDs encendidos
                }
            }
        }
    }
    delay(2000);
}

Nótese que para trabajar, por ejempo con 6 LEDs y con otra distribución, bastaría sólo con cambiar tres líneas de código. Ejemplo:

const byte CANTIDAD_LEDS_Y_PULSADORES = 6;
const byte PIN_LEDS[CANTIDAD_LEDS_Y_PULSADORES] = {13, 3, 2, 7, 9, 12};
const byte PIN_PULSADORES[CANTIDAD_LEDS_Y_PULSADORES] = {8, 10, 6, 4, 5, 11};

Como apunte final decir que los nombres de las variables no hacen milagros para que el código sea legible y entendible. Pero es que si ya de por sí es difícil con nombres "amigables", con nombres ofuscados se hace casi imposible. E insistir en que esta es una posible solución de infinidad de ellas posibles.

1 Like