problema con 4 botones

Hola, un saludo!

tengo un problemilla con este código, la idea del proyecto son 4 botones que pulsados en un orden correcto, desbloquean una cerradura.

Funciona regular pero me gustaría mejorar algunas cosas:

el programa cuenta varias pulsaciones al dejar un botón pulsado
quiero que mientras esté el botón pulsado, no haya mas pulsaciones.

Además, en ocasiones, aparecen pulsaciones fantasma, ( estoy monitoreando por serial y aparece que se están pulsando botones cuando en realidad no se está pulsando nada)

#define outputPin 12
int clave[]={1,3,2,0,0,1};
int sec[]= {100,100,100,100,100,100};
int estado=0;
int amarillo=3;
int azul=5;
int rojo=7;
int verde=9;
long intervalo=5000;
long tiempoPulsacion=0;
long pulsacionAnterior=0;
bool botonPulsado=false;

int opc;


void setup() {
  // put your setup code here, to run once:
pinMode(outputPin, OUTPUT);
digitalWrite(outputPin, HIGH);
pinMode(amarillo, INPUT_PULLUP);
pinMode(azul, INPUT_PULLUP);
pinMode(rojo, INPUT_PULLUP);
pinMode(verde, INPUT_PULLUP);
delay(100);
Serial.begin(9600);
}


void loop() {
  // put your main code here, to run repeatedly:
  if (botonPulsado==true && digitalRead (amarillo)== HIGH && digitalRead (azul)== HIGH && digitalRead(rojo)==HIGH && digitalRead (verde)==HIGH)
{
  botonPulsado=false;
  }
while (botonPulsado==false)
  {  
tiempoPulsacion=millis();
if((tiempoPulsacion-pulsacionAnterior)>intervalo && (estado!=0))
{
  estado=0;
  Serial.println ("Resetando clave");
  }

  
  if (digitalRead (amarillo)==LOW) //&& botonPulsado==false)
  {
    pulsacionAnterior=millis();
    botonPulsado=true;
    Serial.println ("Boton amarillo pulsado");
    sec[estado]=0;
    estado++;
    Serial.println (estado);
    //delay(250);
    
    }
    if (digitalRead (azul)==LOW) //&& botonPulsado==false)
  {
    pulsacionAnterior=millis();
    botonPulsado=true;
    Serial.println ("Boton azul pulsado");
    sec[estado]=1;
    estado++;
    Serial.println (estado);
    //delay(250);
    
    }
    if (digitalRead (rojo)==LOW)  //&& botonPulsado==false)
  {
    pulsacionAnterior=millis();
    botonPulsado=true;
    Serial.println ("Boton rojo pulsado");
    sec[estado]=2;
    estado++;
    Serial.println (estado);
    //delay(250);
    
    }
    if (digitalRead (verde)==LOW)  //&& botonPulsado==false)
  {
    pulsacionAnterior=millis();
    botonPulsado=true;
    Serial.println ("Boton verde pulsado");
    sec[estado]=3;
    estado++;
    Serial.println (estado);
    //delay(250);
    
    }
  }
  
    if (estado==6)
    {
       if((sec[0]==clave[0])&&(sec[1]==clave[1])&&(sec[2]==clave[2])&&(sec[3]==clave[3])&&(sec[4]==clave[4])&&(sec[5]==clave[5]))
          {
            Serial.println("Codigo correcto");
          digitalWrite(outputPin, LOW);
          delay(3000);
          digitalWrite(outputPin, HIGH);
          delay(10);
          
          }
         
          estado=0;
      }
      if (Serial.available()>0){
          opc=Serial.read();
          Serial.println (opc);
          }

switch (opc)
    {
      case 49:
      
        digitalWrite (outputPin, LOW);
    delay(3000);
          digitalWrite(outputPin, HIGH);
          opc=48;
        break;
        
      case 50:
      estado=0;
          opc=48;
       
          break;
          
        
    }
}

Se agradece cualquier ayuda! Gracias!

Saludos
Prueba esto y me avisas

#define outputPin 12
const String botonPulsado[]={"Amarillo", "Azul","Rojo", "Verde"};
int clave[]={1,3,2,0,0,1};
int sec[]= {100,100,100,100,100,100};
int estado=0;

int amarillo=3;
int azul=5;
int rojo=7;
int verde=9;

byte pulsador[]= {amarillo,azul,rojo,verde};
long intervalo=5000;
long tiempoPulsacion=0;
long pulsacionAnterior=0;
bool botonPulsado=false;

int opc;


void setup() {
  // put your setup code here, to run once:
  pinMode(outputPin, OUTPUT);
  digitalWrite(outputPin, HIGH);
  pinMode(amarillo, INPUT_PULLUP);
  pinMode(azul, INPUT_PULLUP);
  pinMode(rojo, INPUT_PULLUP);
  pinMode(verde, INPUT_PULLUP);
  delay(100);
  Serial.begin(9600);
}


void loop() {
  // put your main code here, to run repeatedly:
  if (botonPulsado==true && digitalRead (amarillo)== HIGH && digitalRead (azul)== HIGH && digitalRead(rojo)==HIGH && digitalRead (verde)==HIGH){
    botonPulsado=false;
  }

  while (botonPulsado==false){  
    tiempoPulsacion=millis();
    if((tiempoPulsacion-pulsacionAnterior)>intervalo && (estado!=0)){
      estado=0;
      Serial.println ("Resetando clave");
    }

    for(byte i=0;i<4;i++){
      if(!digitalRead(pulsador[i])){
        pulsacionAnterior=millis();
        botonPulsado=true;
        sec[estado]=i;  
        estado++;
        Serial.print("Boton Pulsado: ");
        Serial.println(botonPulsado[i]);
        Serial.println (estado);
        while(!digitalRead(pulsador[i])){}
      }
    }
  }
  
  if (estado==6){
    if((sec[0]==clave[0])&&(sec[1]==clave[1])&&(sec[2]==clave[2])&&(sec[3]==clave[3])&&(sec[4]==clave[4])&&(sec[5]==clave[5])){
      Serial.println("Codigo correcto");
      digitalWrite(outputPin, LOW);
      delay(3000);
      digitalWrite(outputPin, HIGH);
      delay(10);
    }
    estado=0;
  }
  if (Serial.available()>0){
    opc=Serial.read();
    Serial.println (opc);
  }

  switch (opc){
    case 49:
      digitalWrite (outputPin, LOW);
      delay(3000);
      digitalWrite(outputPin, HIGH);
      opc=48;
      break;
        
    case 50:
      estado=0;
      opc=48;
      break;      
  }
}

Hola, antes de nada darte las gracias por la respuesta y la ayuda. Ese código me da error:

Arduino:1.6.12 (Windows 10), Tarjeta:"Arduino/Genuino Uno"

C:\Program Files (x86)\Arduino\arduino-builder -dump-prefs -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -hardware C:\Users\Usuario\Documents\Arduino\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries C:\Users\Usuario\Documents\Arduino\libraries -fqbn=arduino:avr:uno -vid-pid=0X2341_0X0043 -ide-version=10612 -build-path C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000 -warnings=none -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avrdude.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -prefs=runtime.tools.avr-gcc.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -verbose C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino
C:\Program Files (x86)\Arduino\arduino-builder -compile -logger=machine -hardware C:\Program Files (x86)\Arduino\hardware -hardware C:\Users\Usuario\Documents\Arduino\hardware -tools C:\Program Files (x86)\Arduino\tools-builder -tools C:\Program Files (x86)\Arduino\hardware\tools\avr -built-in-libraries C:\Program Files (x86)\Arduino\libraries -libraries C:\Users\Usuario\Documents\Arduino\libraries -fqbn=arduino:avr:uno -vid-pid=0X2341_0X0043 -ide-version=10612 -build-path C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000 -warnings=none -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.avrdude.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -prefs=runtime.tools.avr-gcc.path=C:\Program Files (x86)\Arduino\hardware\tools\avr -verbose C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino
Using board 'uno' from platform in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr
Using core 'arduino' from platform in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr
Detecting libraries used...
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10612 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard" "C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000\sketch\Solo_botones_colores_reseteo.ino.cpp" -o "nul"
Generating function prototypes...
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -flto -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10612 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard" "C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000\sketch\Solo_botones_colores_reseteo.ino.cpp" -o "C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000\preproc\ctags_target_for_gcc_minus_e.cpp"
"C:\Program Files (x86)\Arduino\tools-builder\ctags\5.8-arduino10/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000\preproc\ctags_target_for_gcc_minus_e.cpp"
Compilando programa...
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10612 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino" "-IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard" "C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000\sketch\Solo_botones_colores_reseteo.ino.cpp" -o "C:\Users\Usuario\AppData\Local\Temp\arduino_build_436000\sketch\Solo_botones_colores_reseteo.ino.cpp.o"
botto:3: error: redefinition of 'int clave []'

 int clave[]={1,3,2,0,0,1};

           ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:2:5: note: 'int clave [6]' previously defined here

 int clave[]={1,3,2,0,0,1};

     ^

botto:4: error: redefinition of 'int sec []'

 int sec[]= {100,100,100,100,100,100};

         ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:3:5: note: 'int sec [6]' previously defined here

 int sec[]= {100,100,100,100,100,100};

     ^

botto:5: error: redefinition of 'int estado'

 int estado=0;

     ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:4:5: note: 'int estado' previously defined here

 int estado=0;

     ^

botto:7: error: redefinition of 'int amarillo'

 int amarillo=3;

     ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:5:5: note: 'int amarillo' previously defined here

 int amarillo=3;

     ^

botto:8: error: redefinition of 'int azul'

 int azul=5;

     ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:6:5: note: 'int azul' previously defined here

 int azul=5;

     ^

botto:9: error: redefinition of 'int rojo'

 int rojo=7;

     ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:7:5: note: 'int rojo' previously defined here

 int rojo=7;

     ^

botto:10: error: redefinition of 'int verde'

 int verde=9;

     ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:8:5: note: 'int verde' previously defined here

 int verde=9;

     ^

botto:13: error: redefinition of 'long int intervalo'

 long intervalo=5000;

      ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:9:6: note: 'long int intervalo' previously defined here

 long intervalo=5000;

      ^

botto:14: error: redefinition of 'long int tiempoPulsacion'

 long tiempoPulsacion=0;

      ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:10:6: note: 'long int tiempoPulsacion' previously defined here

 long tiempoPulsacion=0;

      ^

botto:15: error: redefinition of 'long int pulsacionAnterior'

 long pulsacionAnterior=0;

      ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:11:6: note: 'long int pulsacionAnterior' previously defined here

 long pulsacionAnterior=0;

      ^

botto:16: error: redefinition of 'bool botonPulsado'

 bool botonPulsado=false;

      ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:12:6: note: 'bool botonPulsado' previously defined here

 bool botonPulsado=false;

      ^

botto:17: error: redefinition of 'int opc'

 int opc;

     ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:14:5: note: 'int opc' previously declared here

 int opc;

     ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\botto.ino: In function 'void setup()':

botto:20: error: redefinition of 'void setup()'

 void setup() {

      ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:17:6: note: 'void setup()' previously defined here

 void setup() {

      ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\botto.ino: In function 'void loop()':

botto:33: error: redefinition of 'void loop()'

 void loop() {

      ^

C:\Users\Usuario\Documents\Arduino\Solo_botones_colores_reseteo\Solo_botones_colores_reseteo.ino:30:6: note: 'void loop()' previously defined here

 void loop() {

      ^

exit status 1
redefinition of 'int clave []'

franoween:
el programa cuenta varias pulsaciones al dejar un botón pulsado
quiero que mientras esté el botón pulsado, no haya mas pulsaciones.

En el playground de arduino.cc está como controlar los pulsadores a modo de interruptor usando millis()

franoween:
Además, en ocasiones, aparecen pulsaciones fantasma, ( estoy monitoreando por serial y aparece que se están pulsando botones cuando en realidad no se está pulsando nada)

Más que “fantasmas” son los botes que se producen en los pulsadores “bounce”. Ningún misterio.

No entiendo el sentido de usar millis() si después el código acaba usando delays(); Al hacer delay() interrumpes también los tiempos que usas con millis()

Lo siento me mareé con tanto código (tranquilo cada cual programa a su manera es sólo que yo me estreso).
Si puede ayudarte en algo te pongo un ejemplo muy sencillito que he tardado 3 minutos en hacer.
No es tu ejercicio completado, sino una manera de evitar los rebotes en los pulsadores de forma ordenada y a partir de ahí seguir.

Anteriormente he usado métodos similares pero con bytes y aunque les ha funcionado les ha resultado difícil de “leer”, pero a mí me cuesta más interpretar un millón de líneas, por tanto vamos a probar si usando un array de String resulta más sencillo de entender.

Este código está sin comentar para que se vea su brevedad ( comentado más abajo )
Servirá para tantos pulsadores como definas en el array y podrás encender / pagar leds en base al valor.

#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))

byte debounce = 150;

String botones[][4] = {
  {"rojo",     "2", "no pulsado", "0"}, 
  {"amarillo", "3", "no pulsado", "0"},
  {"verde",    "4", "no pulsado", "0"},
  {"azul",     "5", "no pulsado", "0"}
};

void setup() {
  Serial.begin(9600);
  for(byte i = 0; i < ARRAY_LENGTH(botones); i++ ){ 
    pinMode(botones[i][1].toInt(), INPUT_PULLUP); 
    botones[i][3] = String(millis());
  }
}

void loop() {
  for(byte i = 0; i < ARRAY_LENGTH(botones); i++ ){ 
    String estado = ( digitalRead(botones[i][1].toInt()) ) ? "pulsado" : "no pulsado";
    if( botones[i][2] != estado && millis() >= botones[i][3].toInt() + debounce ){
      botones[i][2] = estado;
      botones[i][3] = String(millis());
      Serial.println("El boton " + botones[i][0] + " cambio a " + botones[i][2]);
    }
  }
}

(Comentado y a color)

#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))

byte debounce = 150; // tiempo añadido para detectar los cambios (un “delay”).

String botones[4] = {
{“rojo”, “2”, “no pulsado”, “0”}, //nombre, pin, estado, tiempo del último cambio.
{“amarillo”, “3”, “no pulsado”, “0”}, // “” “” “”
{“verde”, “4”, “no pulsado”, “0”}, // “” “” “”
{“azul”, “5”, “no pulsado”, “0”} // “” “” “”
};

void setup() {
Serial.begin(9600);
for(byte i = 0; i < ARRAY_LENGTH(botones); i++ ){ //Recorremos los botones.
pinMode(botones*[1].toInt(), INPUT_PULLUP); //El elemento 1 es el pin.*
_ botones*[3] = String(millis()); //El elemento 3 es el tiempo, ponemos el actual._
_
}_
_
}_
void loop() {
_
//Recorremos los botones._
for(byte i = 0; i < ARRAY_LENGTH(botones); i++ ){*

* //variable estado temporal, si el botón está pulsado su valor es “pulsado” si no, es “no pulsado”.*
_ String estado = ( digitalRead(botones*[1].toInt()) ) ? “pulsado” : “no pulsado”;*_

* //Si el estado actual es diferente al estado del botón guardado y se produce el delay usando millis, entonces…*
if( botones_[2] != estado && millis() >= botones*[3].toInt() + debounce ){*_

_ botones*[2] = estado; //El estado actual será este último.
botones[3] = String(millis()); //Actualizamos el tiempo.*_

* //Mostramos sin repetir cuando el botón ha pasado de un estado a otro.*
_ Serial.println("El boton " + botones[i ][0] + " cambio a " + botones*[2]);
}
}
}
[/quote]*_

¡Muchas gracias Arduinito! he hecho unas modificaciones y ya funciona, lo malo es que ahora al meter la clave para abrir la cerradura, a veces se come alguna pulsación :’(

Dejo el código por si se puede hacer algo.

los cambios que hice fueron añadir un algoritmo para que se reinicie el contador de pulsaciones a 0 si pasan más de 5 segundos desde la ultima vez que se pulsó un botón.

También añadí que guarde las pulsaciones en un array y cuando el contador de pulsaciones llega a 6, se resetea el contador a 0, compara la clave con el password autentico y si es correcto, se abre. si no, solo muestra un mensaje de código incorrecto.

Además de un sistema para poder abrir la cerradura o resetear el contador desde el monitor serie.

#define ARRAY_LENGTH(x) (sizeof (x) / sizeof (x[0]))
#define outputPin 12
byte debounce = 150;
String botones [][4] = {
  {"Amarillo", "3", "No pulsado", "0"},
  {"Azul",     "5", "No pulsado", "0"},
  {"Rojo",     "7", "No pulsado", "0"},
  {"Verde",    "9", "No pulsado", "0"},

};
int clave[]={100,100,100,100,100,100};
int pass[]= {5,9,7,3,3,5};
int contadorPulsa=0;
long pulsacionAnterior=0;
long tiempoPulsacion=0;
long intervalo = 5000;
int opc=0;

void setup() {
  // put your setup code here, to run once:
  pinMode (outputPin, OUTPUT);
  digitalWrite(outputPin, HIGH);
  Serial.begin (9600);
  for (byte i = 0; i < ARRAY_LENGTH (botones); i++){
    pinMode (botones [i][1].toInt(), INPUT_PULLUP);
    botones [i][3] = String (millis());
  }


}

void loop() {
  tiempoPulsacion=millis();
if((tiempoPulsacion-pulsacionAnterior)>intervalo && (contadorPulsa!=0))
{
  contadorPulsa=0;
  Serial.println ("Resetando clave");
  }
  // put your main code here, to run repeatedly:
for (byte i=0; i< ARRAY_LENGTH(botones); i++)
{
    String estado = (digitalRead(botones[i][1].toInt()) ) ? "no pulsado" : "pulsado";
    if (botones[i][2] !=estado && millis () >= botones [i][3].toInt () + debounce ){
      
      botones [i][2] = estado;
      botones[i][3] = String(millis());
      Serial.println ("El boton " + botones[i][1] + " cambio a " + botones [i][2]); 
      if (botones[i][2]== "pulsado")
      {
       pulsacionAnterior= millis();
       clave[contadorPulsa]= botones[i][1].toInt();
       Serial.println(clave[contadorPulsa] );
       Serial.println(pass[contadorPulsa]);
        contadorPulsa++;
       Serial.println (contadorPulsa);
       if (contadorPulsa==6)
      {
         contadorPulsa = 0;
        if (clave[0]==pass[0] && clave[1]==pass[1] && clave[2]==pass[2] && clave[3]==pass[3] && clave[4]==pass[4] && clave[5]==pass[5])
        {    
          Serial.println ("Codigo correcto.");
          digitalWrite (outputPin, LOW);
          delay (3000);
          digitalWrite (outputPin, HIGH);
           
      }
      else
      {
        contadorPulsa =0;
        Serial.println ("codigo incorrecto");
      }
        }
      }
    
      }
      if (Serial.available()>0){
          opc=Serial.read();
          Serial.println (opc);
          }
     switch (opc)
    {
      case 49:
      
        digitalWrite (outputPin, LOW);
    delay(3000);
          digitalWrite(outputPin, HIGH);
          opc=48;
        break;
        
      case 50:
      contadorPulsa=0;
          opc=48;
       
          break;
          
        
    }
      
     }
    }

franoween:
¡Muchas gracias Arduinito! he hecho unas modificaciones y ya funciona, lo malo es que ahora al meter la clave para abrir la cerradura, a veces se come alguna pulsación :cry:

Dejo el código por si se puede hacer algo.

Si explicas un poco la idea quizás podamos entenderte. Ten en cuenta que cada persona plantea la programación a su manera y yo partiendo de tu código no entiendo la tuya :confused: Es normal ya que cada cual desarrolla las cosas según su lógica. P.e lo de clave 100,100,100 no lo entiendo y tiendo a sospechar que tu planteamiento genera más variables de las necesarias.

franoween:
los cambios que hice fueron añadir un algoritmo para que se reinicie el contador de pulsaciones a 0 si pasan más de 5 segundos desde la ultima vez que se pulsó un botón.

Dos cosas:
Primero empecemos a llamar cada cosa por su nombre, hacer un contador con una variable global no es un algoritmo.
"Algoritmo: Conjunto ordenado de operaciones sistemáticas que permite hacer un cálculo y hallar la solución de un tipo de problemas." Lo que podría ser por poner un ejemplo una ecuación en matemáticas o bien toda la aplicación en programación. Un contador en un bucle no deja de ser un Sumando. Pueden parecer tonterías pero no llamemos raíces cuadradas a las restas :wink: porque después arrastramos esos errores y no nos entienden a nivel profesional el día de mañana.

Si nos explicas que debe hacer (los pasos) el usuario para abrir o cerrar la cerradura acabamos antes. Es lo que se conoce como pseudocódigo, estilo enunciados en los exámenes de programación.

Un saludo y me alegro que te sirviese de algo el ejemplo.

Muchas gracias por la respuesta y la aclaración!

A ver, el proyecto es un control de acceso. Una puerta esta cerrada y tiene 4 botones de colores.
Estos botones, al ser pulsados en un orden concreto, desbloquean la puerta y permite que se abra.

Ahora mismo el Sketch funciona, cada vez que se introduce el código correcto, se abre, no genera los rebotes y si dejo un botón pulsado, no se cuenta como varias pulsaciones. OK
Pero hay ocasiones que se come pulsaciones, introduzco CLAVE y el sistema solo reconoce CLV.

 :) #define ARRAY_LENGTH(x) (sizeof (x) / sizeof (x[0]))
#define outputPin 12
byte debounce = 150;
String botones [][4] = {
  {"Amarillo", "3", "No pulsado", "0"},
  {"Azul",     "5", "No pulsado", "0"},
  {"Rojo",     "7", "No pulsado", "0"},
  {"Verde",    "9", "No pulsado", "0"},

};
int clave[6];//este array guarda la clave que ha introducido el usuario
int pass[]= {5,9,7,3,3,5}; //clave que abre la puerta
int contadorPulsa=0; //cuenta el numero de pulsaciones  y sirve de indice para el array clave[]
long pulsacionAnterior=0; //en esta variable guardo el tiempo en el que se ha pulsado cualquier boton, para saber en que momento se ha pulsado
long tiempoPulsacion=0; //guarda millis
long intervalo = 5000;// intervalo de tiempo para el reseteo del codigo
int opc=0; // variable para saber la opcion que se ha introducido por monitor para abrir la puerta o resetear la clave

void setup() {
  // put your setup code here, to run once:
  pinMode (outputPin, OUTPUT);
  digitalWrite(outputPin, HIGH);
  Serial.begin (9600);
  for (byte i = 0; i < ARRAY_LENGTH (botones); i++){
    pinMode (botones [i][1].toInt(), INPUT_PULLUP);
    botones [i][3] = String (millis());
  }


}

void loop() {
  tiempoPulsacion=millis();
  //este if controla el tiempo que hay entre las pulsaciones, si es mayor que 5000, reinicio el contador e indice a 0
if((tiempoPulsacion-pulsacionAnterior)>intervalo && (contadorPulsa!=0))
{
  contadorPulsa=0;
  Serial.println ("Resetando clave");
  }
  // put your main code here, to run repeatedly:

  //aqui viene tu codigo, gracias
for (byte i=0; i< ARRAY_LENGTH(botones); i++)
{
    String estado = (digitalRead(botones[i][1].toInt()) ) ? "no pulsado" : "pulsado"; //no entiendo muy bien q hace la ? "no pulsado" : "pulsado"
    if (botones[i][2] !=estado && millis () >= botones [i][3].toInt () + debounce ){ 
      
      botones [i][2] = estado;
      botones[i][3] = String(millis());
      Serial.println ("El boton " + botones[i][1] + " cambio a " + botones [i][2]); 
      if (botones[i][2]== "pulsado") // aqui miro si el`boton esta pulsado. 
      {
       pulsacionAnterior= millis(); //guardo el tiempo en q se pulsó el boton
       clave[contadorPulsa]= botones[i][1].toInt(); // guardo el numero de pin en el array clave
       Serial.println(clave[contadorPulsa] ); // muestro por pantalla el boton pulsado
       Serial.println(pass[contadorPulsa]); // muestro por pantalla el numero que deberia pulsarse
        contadorPulsa++; // sumento en 1 el valor decontadorPulsa
       Serial.println (contadorPulsa); // muestro por pantalla el numero de pulsaciones hechas
       if (contadorPulsa==6) // si el contador llega a 6, lo reinicio a 0 y compruebo que el codigo introducido es correcto
      {
         contadorPulsa = 0;
         // si es correcto, lo muestro en pantalla y desbloqueo la puerta durante 3 segundos
        if (clave[0]==pass[0] && clave[1]==pass[1] && clave[2]==pass[2] && clave[3]==pass[3] && clave[4]==pass[4] && clave[5]==pass[5])
        {    
          Serial.println ("Codigo correcto.");
          digitalWrite (outputPin, LOW);
          delay (3000);
          digitalWrite (outputPin, HIGH);
           
      }
      else
      {
        contadorPulsa =0;
        Serial.println ("codigo incorrecto");
      }
        }
      }
    
      }

      //este switch me permite abrir y resetar el codigo desde el pc
      
      if (Serial.available()>0){
          opc=Serial.read();
          Serial.println (opc);
          }
     switch (opc)
    {
      case 49:
      //abro cerradura
        digitalWrite (outputPin, LOW);
    delay(3000);
          digitalWrite(outputPin, HIGH);
          opc=48;
        break;
        //reinicio el contador 
        case 50:
      contadorPulsa=0;
          opc=48;
       
          break;
          
        
    }
      
     }
    }

De entrada a tu manera haces que la parte de código que te pasé deje de funcionar. Nada más iniciar cambias el estado de todos los botones a pulsados por hacer mal las condiciones. Ando un poco liado, después si tengo tiempo te lo reviso pero te complicas un poco.

¿Cual debe ser la idea? ¿Esta?:

  1. Usuario pone por consola contraseña.
  2. Se guarda, Si el usuario la introduce correctamente abrir.
  3. Si no no pasa nada.
  4. Si pasa X tiempo reiniciar el tiempo que tiene el usuario para poner la clave.

Si lo explicas esquemáticamente mejor que revisar línea a línea.

Por cierto veo que comentaste en el código no entender los operadores ? y :.
En resumen ? es cuando la condición es cierta, : es cuando no.
Lo mismo que un if else.

Concretamente se llama Condicional ternario
Hay operadores de bit, operadores de comparación, etc.

No te compliques si estás empezando.
En Arduino veo que no son muy usados los operadores que no sean de comparación, ni se usan punteros, etc, etc. A más tiempo pasa, más me doy cuenta que en Arduino rara vez es usado por programadores digamos que... "titulados" en webs de tutoriales, viene a ser un lenguaje basado en C donde entra mucha gente con 0 experiencia y hay mucho copy and paste, pero es bueno que la gente empiece por lenguajes de bajo nivel (y ese bajo no significa que sea fácil, no confundir)

Hola otra vez y gracias por lo del ? Y :

A ver si logro esquematizarlo:

  1. usuario pulsa los botones en un orden
  2. Guardo esas pulsaciones y las comparo cada 6 pulsaciones.
    3 si el codigo es correcto, abro puerta y reinicio el contador. Si no, solo reseteo el contador.
    4 si alguien, sin saber la clave, pulsa varios botones, sin llegar a 6 o pasandose de 6, el sistema reinicia el contador pasados 5 segundos de la última pulsación.

Podría darse el caso de que aun pulsando los botones en el orden correcto, la cerradura no se accione y no se pueda abrir la puerta. Para ese caso, el programa admite que le lleguen ordenes por serial para abrir la puerta o reiniciar el contador.

Ahora mismo el programa funciona, el problema es que a veces no se reconocen las pulsaciones, dando el problema de que entonces, aunque se introduzca bien la clave, no se reconozca y no se abra la puerta. Y la idea es que funcione siempre, aunque tenga la opción de abrir la puerta por serial.

franoween:
Hola otra vez y gracias por lo del ? Y :

A ver si logro esquematizarlo:

  1. usuario pulsa los botones en un orden
  2. Guardo esas pulsaciones y las comparo cada 6 pulsaciones.
    3 si el codigo es correcto, abro puerta y reinicio el contador. Si no, solo reseteo el contador.
    4 si alguien, sin saber la clave, pulsa varios botones, sin llegar a 6 o pasandose de 6, el sistema reinicia el contador pasados 5 segundos de la última pulsación.

Ahora sí nos entendemos. :art: :wink:

Es fácil de hacer ¿Cual es tu duda exactamente? El problema que tienes en el código tuyo es que está mal, simplemente, no es buena idea unir sin más pedazos de códigos sin entenderlos.
Como ya te dije antes provocas de entrada que se cambien el estado de los botones según se inicia el Arduino.
¿Por qué? Porque entre otros fallos, has unido mi parte dentro de tu if inicial con tiempoPulsacion=millis(); al princpio del loop.
Repito, no unir códigos, los puzzles en programación sin conocimientos con copy and paste dan fallos. A las pruebas que hay en este foro me remito. Primero entenderlos y después crearlos.

Para desarrollar tu idea podrías usar dos arrays uno con la clave de colores que debe seguirse y otro que almacenará los valores guardados:

byte
clave[] = {1,5,9,0}, 
clave_pulsada[ARRAY_LENGTH(clave)];

También necesitarás dos variables para controlar que pasados esos 5 segundos se reinicie la clave pulsada

const unsigned long tiempo_max_espera = 5000;
unsigned long tiempo;

Tendrás que comprobar mediante un bucle si los valores de ambos arrays son iguales.
Sólo necesitas dos comparaciones. Si es igual abres la cerradura, si el tiempo máximo entre pulsaciones concluye, reinicias tiempo y clave_pulsada.

La asignación del valor no debe ser cuando se cambie sino cuando estado sea == “pulsado”.
Puedes comprobar la clave con una función como la que usé:

boolean check_clave(){
  for(byte i = 0; i < ARRAY_LENGTH(clave); i++ ){ 
    if( clave[i] != clave_pulsada[i] ){
      return false;
    }
  }
  return true;
}

No es ni complicado ni largo, 80 líneas exactas con comentarios en mi caso hacer tu ejercicio.
Puede verse de mala fe no pasar el código entero, pero volverás a hacer copy and paste y eso no sirve de nada porque además cada cual programa a su manera. Y privados pidiendo códigos tampoco, (sé que no has sido uno de ellos) :slight_smile: yo intento ayudar y que me ayuden, no hago tareas. Tonto el último.

Las dudas sin problema pregunta. :wink: Un saludo.

Hola, gracias otra vez!!

no pasa nada por lo del código! bastante haces en contestar jaja. le dare una vuelta y te comento a ver que pasa!