Problema en contador de pulsos con ArduinoUno

Hola, estoy intentando entender las funciones básicas de programación en Arduino ya que soy nuevo en esto. Me encuentro haciendo un código que cuente los pulsos de un botón pulsador, enseguida les explico mi problema y les anexo mi código (espero me de a entender).

Mi programa intenta simular una secuencia tipo "semáforo" controlada por un botón pulsador, es decir, pulso el botón una vez y la secuencia empieza a correr, pulso el botón por segunda vez y la secuencia se detiene.

Al momento de pulsar el botón por primera vez le digo a mi programa que mande un valor "1" a "int contador" para que se ejecute una secuencia tipo "semáforo" siempre y cuando siga habiendo un valor "1" en "int contador" (hasta aquí el código funciona).

Mi problema es que al yo presionar el botón pulsador por segunda vez, no pasa nada, la secuencia del "semáforo" se sigue ejecutando infinitamente, amenos que deje sostenido el botón pulsador hasta que termine la secuencia, entonces ahí se ejecuta el ultimo "if" y el "int contador" vuelve a "0" apagando la secuencia tipo "semáforo", y dejando al programa en espera de que se vuelva a presionar el boton para ejecutar nuevamente la secuencia.

int contador = 0;
int verde = 3;
int amarillo = 4;
int rojo = 5;
int estadoAnterior = 0;
int boton = 2;

void setup() {
 
 
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(2, INPUT);
}

void loop() {
  
int lectura = digitalRead(boton);

if (lectura != estadoAnterior){
  if (lectura == HIGH){
    contador++;
  
  }
}

estadoAnterior = lectura;
if (contador == 1){
  
  digitalWrite(verde, HIGH);
  delay(2700);
  digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
   digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
   digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
   digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
  digitalWrite(verde, LOW);
  
digitalWrite(amarillo, HIGH);
delay (2700);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);


digitalWrite(rojo, HIGH);
delay (2700);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);

}

if (contador == 2){
  digitalWrite(verde, LOW);
  digitalWrite(amarillo, LOW);
  digitalWrite(rojo, LOW);
  contador=0;
}
}

Pienso que puede ser por dos razones:

1.- La memoria del contador no esta reteniendo el segundo pulso.

2.- La velocidad/forma en que el Arduino lee las lineas de código es muy rápida y no alcanza a leer el cambio de estado del contador una vez que se pulso el botón por segunda vez.

Espero me puedan ayudar, llevo un rato quebrando me la cabeza con este pequeño programa.

Swagmaista:
Mi problema es que al yo presionar el botón pulsador por segunda vez, no pasa nada, la secuencia del "semáforo" se sigue ejecutando infinitamente, amenos que deje sostenido el botón pulsador hasta que termine la secuencia, entonces ahí se ejecuta el ultimo "if" y el "int contador" vuelve a "0" apagando la secuencia tipo "semáforo", y dejando al programa en espera de que se vuelva a presionar el boton para ejecutar nuevamente la secuencia.

En realidad, la causa del problema está en el exceso de delay; esto "bloquea" el programa hasta el punto en que imposibilita la lectura del botón. Por eso es que sólo lo alcanza a leer cuando la secuencia haya terminado.

Lo que tendrás que hacer es aprender sobre algo llamado "máquina estado", y a cómo usar la función millis. Un buen punto de partida podría ser con el ejemplo BlinkWithoutDelay. Basado en este, he podido crear un programa que, por ejemplo, haga parpadear 3 LEDs a un ritmo diferente cada uno.

Y algo mas simple..
no leiste que un delay detiene la ejecución del programa?
Tu programa lee contador = 1
Y comienza la secuencia y tu presionas el pulsador pero el programa esta detenido en los delay(XXXX) que has puesto, por no se cuantos segundos.
Imposible o mucha casualidad que cuando termine lea tu pulsador. De hecho lo hare pero antes te aburres

Prueba esto solo para entender mi punto.
Quita todos los delays.
Usa Serial.println para ver el cambio de contador en tu monitor serie y luego me dices.

La solución no es facil, pero debes usar millis() y todo lo demas implementarlo en una máquina de estados.
Chino básico no? Resuelve lo primero y luego lo vemos

He encontrado la solución, muy simple por cierto.

Buscando algunos ejemplos por Internet me tope con la instrucción "attachInterrupt", si mal no entendí su funcionamiento, lo que hace es que al tu llamarla el Arduino va y lee el pedazo de código que tu le indiques sin importar que linea de código este leyendo, después de leer el "attachInterrupt" el Arduino vuelve al pedazo de código en el que se quedo antes de que mandaras llamar la instrucción.

Les anexo el código para que le den una leída.

int contador = 0;
int verde = 3;
int amarillo = 4;
int rojo = 5;
int estadoAnterior = 0;
int boton = 2;

void setup() {
  Serial.begin(9600);
  attachInterrupt(0, memoria_contador, RISING);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(2, INPUT);
}

void loop() {

int lectura = digitalRead(boton);

if (lectura != estadoAnterior){
  if (lectura == HIGH){
    contador++;
  }
}

estadoAnterior = lectura;
if (contador == 1){
  
  digitalWrite(verde, HIGH);
  delay(2700);
  digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
   digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
   digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
   digitalWrite(verde, LOW);
  delay (100);
  digitalWrite(verde, HIGH);
  delay (100);
  digitalWrite(verde, LOW);
  
digitalWrite(amarillo, HIGH);
delay (2700);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);
delay (100);
digitalWrite(amarillo, HIGH);
delay (100);
digitalWrite(amarillo, LOW);


digitalWrite(rojo, HIGH);
delay (2700);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);
delay (100);
digitalWrite(rojo, HIGH);
delay (100);
digitalWrite(rojo, LOW);

}

if (contador == 2){
  digitalWrite(verde, LOW);
  digitalWrite(amarillo, LOW);
  digitalWrite(rojo, LOW);
  contador=0;
}
}

void memoria_contador(){
  contador++;
  Serial.println(contador);
  if (contador > 2) contador = 0;
}

Aun no pruebo los resultados de sus respuestas pero en unos momentos mas lo haré. Gracias y les escribo los resultados.

No es solución. La solución es un mejor programa usando millis().
Te resulta mas fácil el camino simple, pues adelante.

Además usar Serial.print en una interrupción no es aconsejable por no decir que esta PROHIBIDO.

void memoria_contador(){
  contador++;
  Serial.println(contador);
  if (contador > 2) contador = 0;
}

Una interrupción debe ser breve. Veloz.

Un semáforo simple, como máquiina de tiempos, se puede hacer como tu lo has encarado, con delay.
Un semáforo con pulsador no.

Tranquilo amigo, te he dicho que iba a probar tu método, no te exaltes.

Me gustaría me dieran un ejemplo de como usar la función "millis" correctamente, encuentro ejemplos pero la verdad es que ya fastidiado de pasar tanto tiempo frente a la PC me tiene ciclado.

Entiendo a grandes rasgos lo que engloba la función y que en el BlinkWithoutDelays lo que se hace es comparar valores y luego restarlos para vaciar el resultado en una "int" que modifica constantemente el estado del LED.

Espero puedan explicarme con un pedazo de código.

Aun así me saltan algunas dudas: ¿para usar "millis" se declara a fuerza el "unsigned long" y el "const"? ¿o no es necesario usar esos términos para hacer uso del "millis"?

Tranquilo amigo, te he dicho que iba a probar tu método, no te exaltes.

Sin palabras. Hago esto porque quiero y esto gano. Maravilloso!!

Volvamos a tu problema no el mío.
Que te quede bien claro eso: el que debe entregar la tarea sos vos.

Deberías estudiar maquina de estados con arduino. Cómo: Google: arduino maquina de estados.
No es fácil pero es la manera de hacerlo.

Imagina esto: tienes que pasar de una manera de programar LA ACTUAL a OTRA donde todo ocurre de manera que Arduino pueda atender todos los cambios que sean necesarios y si requiere de demoras, debes hacerlo usando las herramientas que te da millis().

Un ejemplo.

int contador        = 0;
int verde           = 3;
int amarillo        = 4;
int rojo            = 5;
int estadoAnterior  = 0;
int boton           = 2;
unsigned long start;

void setup() {
  Serial.begin(9600);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(2, INPUT);
  Serial.println("Iniciando programa");
}

void loop() {

  int lectura = digitalRead(boton);
  if (lectura != estadoAnterior){
    if (lectura == HIGH){
      contador++;
      Serial.println(contador);
    }
  }
  estadoAnterior = lectura;
  
  if (contador == 1) {
      estado = 1;
  }

  switch (estado) {
      case 1: digitalWrite(verde, HIGH); 
              estado = 2;
              break;
      case 2: if (millis()-start > 2700UL){  // estado en el que me mantengo por 2700 mseg
                 digitalWrite(verde, LOW);
                 estado = 3;                 // hasta no cumplir los 2700mseg no paso a 3
                 start = millis;             // preparo el arranque del siguiente estado
              }
              break;
      case 3: if (millis()-start > 100UL){
                  digitalWrite(verde, HIGH);
                  estado = 4;
                  start = millis;             // preparo el arranque del siguiente estado
              }
              break;
      case 4: // y seguimos

  }
}