Problema con mi código de 4 botones

Buenas gente. Antes que nada, quiero decir que es mi primer mensaje en el foro y que me encanta vuestra comunidad, así que cuando hoy me he encontrado con este problema en mi proyecto, he decidido pediros una ayudita jajaja.
La cosa es así: Estoy intentando hacer un cerrojo de puerta que funcione con un destornillador sónico de Doctor Who a base de ponerle un LED infrarrojo. Esa parte, sin embargo, está sin problema. Las dudas me aparecen cuando, y como mecanismo de seguridad, quiero tener cuatro botones que sirvan para introducir una contraseña en caso que no tenga en ese momento el LED infrarrojo.

La cosa es, en principio, sencilla. Cuatro botones puestos en hilera que se tienen que pulsar en orden y coincidir con el orden ya guardado en una array del código. Pero, por alguna razón, no consigo que funcione y acaba detectando casi siempre que he pulsado el botón 1, además de que el LED rojo se acaba volviendo un poco loco

Éste es mi código:

int correct[5] = {1,2,3,4};
int usuario[5];//Contraseña introducida por el usuario
int i=0;//Centinela de los botones
int check=0;//Neutro = 0, Correcto = 1, Erróneo = 2;
int pos=0;//Posición en grados del servo

#define uno 8
#define dos 9
#define tres 10
#define cuatro 11
#define verde 12
#define rojo 13

void setup(){
  
  pinMode(uno, INPUT);
  pinMode(dos, INPUT);
  pinMode(tres, INPUT);
  pinMode(cuatro, INPUT);
  
  pinMode(verde, OUTPUT);
  pinMode(rojo, OUTPUT);
  
  Serial.begin(9600);
}

void loop(){
  
  //Entradas de Botones
  //----------------------
  //En cuanto se pulsa uno de ellos, se añade el valor correspondiente (1, 2, 3 o 4) a
  //la array "usuario". Cuando se han pulsado 4 botones, la variable "i" aumenta en uno,
  //así se pasa al siguiente paso, la comprobación.
  if(digitalRead(uno)==HIGH){
    usuario[i]=1;
    i++;
    Serial.print("Boton 1 guardado en posicion ");
    Serial.println(i);
    delay(200);
  } else if(digitalRead(dos)==HIGH){
    usuario[i]=2;
    i++;
    Serial.print("Boton 2 guardado en posicion ");
    Serial.println(i);
    delay(200);
  } else if(digitalRead(tres)==HIGH){
    usuario[i]=3;
    i++;
    Serial.print("Boton 3 guardado en posicion ");
    Serial.println(i);
    delay(200);
  } else if(digitalRead(cuatro)==HIGH){
    usuario[i]=4;
    i++;
    Serial.print("Boton 4 guardado en posicion ");
    Serial.println(i);
    delay(200);
  }
  
  //Comprobación
  //---------------
  //Si se han pulsado 4 botones y, por tanto, "i" es igual a 4, se inicia la comprobación.
  //Primero se resetea "i" poniéndola a cero, pues tanto si se introduce una contraseña
  //correcta como si no, se empezaría de nuevo igual.
  //Después comprueba uno a uno, con un bucle "for", si las respuestas son correctas.
  //Si alguna falla, la variable "check" toma el valor de 2,  es decir, erróneo,
  //impidiendo que en la comprobación cuando se pulsa el último botón pueda dar positivo.
  //En cambio, si todos han sido correctos, check se transforma en afirmativo (1).
  if(i==4){    
   i=0;
   for(int j=0;j<4&&check!=2;++j){     
     if(usuario[j]!=correct[j]) check=2;
     if(j==3&&check!=2) check=1;
   }    
  }
  
  //Iluminación de LED de Comprobación
  //--------------------------------------
  //Si el valor de "check" es uno y, por tanto, la comprobación ha resultado ser
  //correcta, se iluminará el led verde durante un segundo y cambia la posición del servo a
  //abierto. Si no, se enciende el rojo y se cierra.
  switch(check){    
    case 1: digitalWrite(verde, HIGH);
            delay(1000);
            digitalWrite(verde, LOW);
            pos=0;
            break;
    case 2: digitalWrite(rojo, HIGH);
            delay(1000);
            digitalWrite(rojo, LOW);
            pos=180;
  }
  
}

También he adjuntado una imagen de cómo está dispuesto el hardware, aunque he de admitir que no lo he hecho de forma física, y simplemente lo he probado en un simulador web. Por si alguien lo quiere ver en “acción”, el link es éste:

Algo me dice a mí que el problema está en el nesting de if’s.
Si alguien me puede echar un cable, estaría muy agradecido. Gracias de antemano.

Saludos.
Creo que tu problema es que no tienes control de los rebotes de los pulsadores.
Busca en este link mas informacion.

max_saeta:
Saludos.
Creo que tu problema es que no tienes control de los rebotes de los pulsadores.
Busca en este link mas informacion.

Perfecto, ahora le echo un ojo y te comento. Muchas gracias! :smiley:

Vale, lo he estado mirando pero resulta que usa la función millis(), que según lo que leí hace tiempo tiene un máximo de un mes o así, y luego se resetea... Supongo que podría buscarle una solución, pero en principio tiene pinta de que sí me va a servir, aunque tenga que modificar bastante el código inicial jajaja

Cuando lo tenga solucionado postearé el código y lo daré por acabado, así que muchas gracias! :grin:

Yo normalmente hago esto

if(digitalRead(dos)){
delay(50);
if(digitalRead(dos)){
//Mi Codigo
}
}

max_saeta:
Yo normalmente hago esto

if(digitalRead(dos)){
delay(50);
if(digitalRead(dos)){
//Mi Codigo
}
}

Pues tiene muy buena pinta jajaja
Y menos mal, porque me estaba comiendo la cabeza. Si esto funciona, se hace bastante más sencillo


EDIT

Por desgracia parece ser que no entiendo cómo va la cosa. He hecho unas cuantas modificaciones pero sigue sin funcionar como debería. Inserto código por si podéis seguir ayudándome:

int correct[5] = {1,2,3,4};
int usuario[5];//Contraseña introducida por el usuario
int i=0;//Centinela de los botones
int check=0;//Neutro = 0, Correcto = 1, Erróneo = 2;
int pos=0;//Posición en grados del servo

#define uno 8
#define dos 9
#define tres 10
#define cuatro 11
#define verde 12
#define rojo 13

void setup(){
  
  pinMode(uno, INPUT);
  pinMode(dos, INPUT);
  pinMode(tres, INPUT);
  pinMode(cuatro, INPUT);
  
  pinMode(verde, OUTPUT);
  pinMode(rojo, OUTPUT);
  
  Serial.begin(9600);
}

void loop(){
  
  //Entradas de Botones
  //----------------------
  //En cuanto se pulsa uno de ellos, se añade el valor correspondiente (1, 2, 3 o 4) a
  //la array "usuario". Cuando se han pulsado 4 botones, la variable "i" aumenta en uno,
  //así se pasa al siguiente paso, la comprobación.
  if(digitalRead(uno)==HIGH){
    delay(100);
    if(digitalRead(uno)==HIGH){
      usuario[i]=1;
      i++;
      Serial.print("Boton 1 guardado en posicion ");
      Serial.println(i);
  }
  } else if(digitalRead(dos)==HIGH){
    delay(100);
    if(digitalRead(dos)==HIGH){
      usuario[i]=2;
      i++;
      Serial.print("Boton 2 guardado en posicion ");
      Serial.println(i);
  }
  } else if(digitalRead(tres)==HIGH){
    delay(100);
    if(digitalRead(tres)==HIGH){
      usuario[i]=3;
      i++;
      Serial.print("Boton 3 guardado en posicion ");
      Serial.println(i);
  }
  } else if(digitalRead(cuatro)==HIGH){
    delay(100);
    if(digitalRead(cuatro)==HIGH){
      usuario[i]=4;
      i++;
      Serial.print("Boton 4 guardado en posicion ");
      Serial.println(i);
  }
  }
  
  //Comprobación
  //---------------
  //Si se han pulsado 4 botones y, por tanto, "i" es igual a 4, se inicia la comprobación.
  //Primero se resetea "i" poniéndola a cero, pues tanto si se introduce una contraseña
  //correcta como si no, se empezaría de nuevo igual.
  //Después comprueba uno a uno, con un bucle "for", si las respuestas son correctas.
  //Si alguna falla, la variable "check" toma el valor de 2,  es decir, erróneo,
  //impidiendo que en la comprobación cuando se pulsa el último botón pueda dar positivo.
  //En cambio, si todos han sido correctos, check se transforma en afirmativo (1).
  if(i==4){    
   i=0;
   for(int j=0;j<4&&check!=2;++j){     
     if(usuario[j]!=correct[j]) check=2;
     if(j==3&&check!=2) check=1;
   }    
  }
  
  //Iluminación de LED de Comprobación
  //--------------------------------------
  //Si el valor de "check" es uno y, por tanto, la comprobación ha resultado ser
  //correcta, se iluminará el led verde durante un segundo y cambia la posición del servo a
  //abierto. Si no, se enciende el rojo y se cierra.
  //Cada vez que termina de iluminarse el LED, check vuelve a ser cero para que no se ilumine nada
  switch(check){    
    case 1: digitalWrite(verde, HIGH);
            delay(1000);
            digitalWrite(verde, LOW);
            pos=0;
            check=0;
            break;
    case 2: digitalWrite(rojo, HIGH);
            delay(1000);
            digitalWrite(rojo, LOW);
            pos=180;
            check=0;
  }
  
}

Expica mejor que problema te presenta.

Básicamente sigue sin coger el input como debería, porque al pulsar un solo botón imprime cuatro entradas diferentes en el monitor. Además, la luz roja sigue volviéndose loca :frowning:
Pero por suerte he encontrado algo que tiene pinta de poder ayudarme. Es una librería que se llama bounce2, y parece simplificar el problema porque cambia la manera de obtener los datos de los botones.
Lo mismo que antes, miraré si me funciona y si resulta que sí lo postearé.

Ok entonces vamos a añadir otra linea

if(digitalRead(dos)==HIGH){
    delay(100);
    if(digitalRead(dos)==HIGH){
         While(digitalRead(dos)==HIGH){}
         //Tu codigo aqui

}

Estooo. ¿No faltan en tu esquema resistencias pull down?

De acuerdo, veo que ya nos acercamos a la solución :grinning:
Con la línea de código extra que me has dicho, en efecto puedo conseguir que la señal que entre sea única (muy bien visto lo del loop vacío, por cierto jajaja), y que por tanto pueda pulsar un botón cada vez.
Lo que me sucede ahora (Y por suerte lo único que queda por arreglar de momento) es que cuando pulso los botones, el código reconoce el que le da la gana. Por ejemplo, si pulso el botón uno, le puede asignar cualquier valor entre el 1 y el 4, sin que necesariamente coincida, haciendo caso omiso del botón que realmente estoy pulsando.
Por el momento quiero darte las gracias, Max, que ya me has ayudado muuuucho más de lo que imaginas jajaja

noter:
Estooo. ¿No faltan en tu esquema resistencias pull down?

No tengo ni idea de qué es eso, sinceramente jajaja
¿Una ayudita? :stuck_out_tongue:

Cualquiera que sepa un poquito de electrónica (yo no sé prácticamente nada) te lo podrá explicar mejor, aunque lo intentaré.
Cuando una entrada no está conectada a nada, ¿está recibiendo HIGH o LOW? La respuesta es: está conectada al tuntún, osea que dará uno u otro nivel de forma azarosa. Hay que empujar o tirar un poquito para que "por defecto" esté apuntando hacia uno u otro, y entonces con nuestro pulsador hacemos cambiar ese estado que "insinuamos".
Una breve guía que se adapta bien a mi nivel.
Por cierto, puedes configurar la entrada arduino como INPUT_PULLUP, y podrías prescindir de resistencias, pero la lógica será inversa, pues la entrada estará por defecto en HIGH.
Si he pecado contra Ohm, Volta Kirchhoff u otro, ruego que alguien corrija el desaguisado :smiley:
Saludos.

noter:
Cualquiera que sepa un poquito de electrónica (yo no sé prácticamente nada) te lo podrá explicar mejor, aunque lo intentaré.

Con poca ayuda que me deis en electrónica ya me estaréis abriendo un mundo, que yo soy de software y poco más jajaja
Por lo que veo cuadra con mi problema (Al menos eso creo), porque tal cual tengo el código ahora, recibe la entrada que le da la gana:

int correct[5] = {1,2,3,4};
int usuario[5];//Contraseña introducida por el usuario
int i=0;//Centinela de los botones
int check=0;//Neutro = 0, Correcto = 1, Erróneo = 2;
int pos=0;//Posición en grados del servo

#define uno 8
#define dos 9
#define tres 10
#define cuatro 11
#define verde 12
#define rojo 13
#define btime 70

void setup(){
  
  pinMode(uno, INPUT);
  pinMode(dos, INPUT);
  pinMode(tres, INPUT);
  pinMode(cuatro, INPUT);
  
  pinMode(verde, OUTPUT);
  pinMode(rojo, OUTPUT);
  
  Serial.begin(9600);
}

void loop(){
  
  //Entradas de Botones
  //----------------------
  //En cuanto se pulsa uno de ellos, se añade el valor correspondiente (1, 2, 3 o 4) a
  //la array "usuario". Cuando se han pulsado 4 botones, la variable "i" aumenta en uno,
  //así se pasa al siguiente paso, la comprobación.
  if(digitalRead(uno)==HIGH){
    delay(btime);
    if(digitalRead(uno)==HIGH){
      while(digitalRead(uno)==HIGH){};
      usuario[i]=1;
      i++;
      Serial.print("Boton 1 guardado en posicion ");
      Serial.println(i);
  }
  }
  if(digitalRead(dos)==HIGH){
    delay(btime);
    if(digitalRead(dos)==HIGH){
      while(digitalRead(dos)==HIGH){};
      usuario[i]=2;
      i++;
      Serial.print("Boton 2 guardado en posicion ");
      Serial.println(i);
  }
  }
  if(digitalRead(tres)==HIGH){
    delay(btime);
    if(digitalRead(tres)==HIGH){
      while(digitalRead(tres)==HIGH){};
      usuario[i]=3;
      i++;
      Serial.print("Boton 3 guardado en posicion ");
      Serial.println(i);
  }
  }
  if(digitalRead(cuatro)==HIGH){
    delay(btime);
    if(digitalRead(cuatro)==HIGH){
      while(digitalRead(cuatro)==HIGH){};
      usuario[i]=4;
      i++;
      Serial.print("Boton 4 guardado en posicion ");
      Serial.println(i);
  }
  }
  
  //Comprobación
  //---------------
  //Si se han pulsado 4 botones y, por tanto, "i" es igual a 4, se inicia la comprobación.
  //Primero se resetea "i" poniéndola a cero, pues tanto si se introduce una contraseña
  //correcta como si no, se empezaría de nuevo igual.
  //Después comprueba uno a uno, con un bucle "for", si las respuestas son correctas.
  //Si alguna falla, la variable "check" toma el valor de 2,  es decir, erróneo,
  //impidiendo que en la comprobación cuando se pulsa el último botón pueda dar positivo.
  //En cambio, si todos han sido correctos, check se transforma en afirmativo (1).
  if(i==4){    
   i=0;
   for(int j=0;j<4&&check!=2;++j){     
     if(usuario[j]!=correct[j]) check=2;
     if(j==3&&check!=2) check=1;
   }    
  }
  
  //Iluminación de LED de Comprobación
  //--------------------------------------
  //Si el valor de "check" es uno y, por tanto, la comprobación ha resultado ser
  //correcta, se iluminará el led verde durante un segundo y cambia la posición del servo a
  //abierto. Si no, se enciende el rojo y se cierra.
  switch(check){    
    case 1: digitalWrite(verde, HIGH);
            delay(1000);
            digitalWrite(verde, LOW);
            pos=0;
            check=0;
            break;
    case 2: digitalWrite(rojo, HIGH);
            delay(1000);
            digitalWrite(rojo, LOW);
            pos=180;
            check=0;
  }
  
}

Lo dicho, le pego un repaso al hardware y os comento, porque la verdad es que es un proyecto al que le tengo muuuuchas ganas y no va a quedar a medias si depende de mí xD


CONSEGUIDO

Pues bien, si es cierto que no ha sido de la forma, llamémosla, honorable, al final he conseguido que reconozca cada entrada de forma individual y sin problema.
Os explico:
He descargado y trasteado un poco con la librería bounce2, que podéis encontrar para descarga tal que aquí, y la ficha de la librería (o biblioteca, según prefiráis) en el playground de arduino es ésta.

Pues bien, dando vueltas a un par de funciones de ejemplo, conseguí que me funcionase, aquí os dejo el código:

#include <Bounce2.h>


#define boton1 8
#define boton2 9
#define boton3 10
#define boton4 11


Bounce button1 = Bounce();
Bounce button2 = Bounce();
Bounce button3 = Bounce();
Bounce button4 = Bounce();

void setup() {
  
  // Setup the button with an internal pull-up :
  pinMode(boton1,INPUT_PULLUP);
  pinMode(boton2,INPUT_PULLUP);
  pinMode(boton3,INPUT_PULLUP);
  pinMode(boton4,INPUT_PULLUP);
  
  Serial.begin(9600);
  // After setting up the button, setup the Bounce instance :
  button1.attach(boton1);
  button1.interval(50);
  button2.attach(boton2);
  button2.interval(50);
  button3.attach(boton3);
  button3.interval(50);
  button4.attach(boton4);
  button4.interval(50);
  
  
 
  
}

void loop() {

  // Update the Bounce instance :
   button1.update();
   button2.update();
   button3.update();
   button4.update();
   
   // Call code if Bounce fell (transition from HIGH to LOW) :
   if (button1.fell()) Serial.println("Boton 1 pulsado");
   if (button2.fell()) Serial.println("Boton 2 pulsado");
   if (button3.fell()) Serial.println("Boton 3 pulsado");
   if (button4.fell()) Serial.println("Boton 4 pulsado");
}

El código que he posteado está prácticamente calcado del ejemplo “change” que viene con la librería y creo que incluso tiene anotaciones suyas. También os dejo este link que os llevará a mi proyecto de 123d Circuits para que lo veáis, con código incluido pero no funcional :grin: Además, adjunto una foto por si no os carga bien o lo que sea, que la página es muy lenta y quién sabe si a mí me dará en algún momento por borrar el proyecto.

En fin, agradecer a max_saeta y noter su involucración en el proyecto, que su ayuda me ha servido para, al menos, saber qué buscar jajaja
De momento se me crea cortocircuito si lo conecto a los 5V, pero supongo que será por cómo está el cableado o porque la resistencia que estoy usando es muy pequeña, algo que solucionaré en breve.

Para despedirme, decir que si acabo el proyecto, lo subiré a la web para compartirlo con vosotros y espero que venga con tutorial jajaja