Antirimbalzo avanzato - Buffer circolare

Ciao, volevo condividere con voi questo piccolo sketch per gestire in un modo un po alternativo l'antirimbalzo di un bottone. Sembra una cosa da poco ma una gestione del genere potrebbe essere utile per gestire poi con Arduino anche una piccola tastiera perchè in questo modo evito degli stalli del codice.

In pratica creo un buffer circolare per evitare di attendere anche poco tempo in un applicazione embedded. Si tratta di creare un piccolo automa che viene richiamato ad intervalli di tempo fissi, ad esempio lo richiamo all’interno di una routine di interrupt di un timer o cose simili. Ad ogni interrupt viene letto lo stato dell’ingresso, supponiamo che con il pulsante non premuto sia a 0. Lo stato del pulsante viene memorizzato in una variabile intera, es. un byte non prima di aver shiftato il suo contenuto a sx di una posizione (0)00000000. Quando il pulsante viene premuto viene premuto e per la prima volta viene letto lo stato a 1, il contenuto del byte diventa (1)000001. Se al passaggio successivo per un rimbalzo lo stato è a zero si avrà (2)00000010. Se al passaggio successivo lo stato viene riconosciuto a 1 si avrà (3)00000101. Ne passaggi successivi ad ogni passo l’evoluzione risulta:
(4 ) 00001011
(5) 00010111
(6) 00101111
(7) 01011111
(8) 10111111
(9) 01111111
(10)11111111
Se ad ogni passo verifichi se il contenuto del byte risulta pari a 01111111 e assegni a questo valore il riconoscimento del pulsante premuto ti rendi conto che solamente al passaggio (9) riconosci la pressione del pulsante.
Analogamente se vuoi rilevare il rilascio del pulsante senza rimbalzo puoi controllare che il contenuto sia ad esempio 11111110.

per l'esempio non ho utilizzato l'interrupt ma una chiamata in polling.

#define KEY_OFF 1000
#define KEY_PRESS 1001
#define KEY_HOLD 1011
#define KEY_REL 1010
#define btnPin 3
#define ledPin 13

//byte per lo stato del bottone
byte btnStatus = 0x0;

void setup(){
   pinMode(btnPin, INPUT);
   pinMode(ledPin, OUTPUT);
}

void loop(){
  if(getInputSwitchStatus() == KEY_PRESS){
    digitalWrite(ledPin, HIGH);
  }
  if(getInputSwitchStatus() == KEY_HOLD){
    //BOTTONE PREMUTO
  }
  if(getInputSwitchStatus() == KEY_REL){
    digitalWrite(ledPin, LOW);
  }
}

int getInputSwitchStatus(){
  //SFHIT stato tasto
  btnStatus <<= 1;
  if(digitalRead(btnPin)){
    btnStatus |= 0x01;
    delay(10);
  }
  if( btnStatus == 0 ) return KEY_OFF;
  else if( btnStatus == 0x7F ) return KEY_PRESS;
  else if( btnStatus == 0xFF ) return KEY_HOLD;
  else if( btnStatus == 0xFE ) return KEY_REL;
  else return "KEY_NO_PRESS";
}

che ve ne pare?

Personalmente adotto 2 letture digitali intervallate da un delay(30), tecnica che non ha mai fallito (almeno per me).

leo72:
Personalmente adotto 2 letture digitali intervallate da un delay(30), tecnica che non ha mai fallito (almeno per me).

Sopratutto se il delay è ottenuto tramite un controllo non bloccante, p.e. con la millis, semplice, funzionale e perfettamente funzionante, a seconda del tipo di contatti può essere necessario portare il tempo di attesa fino a 100 ms.
Usare un buffer circolare per l'antirimbalzo è una complicazione inutile, la tecnica del ritardo dal momento del primo cambio di stato è più sufficiente e non comporta nessun blocco nel programma se gestito tramite millis()/timer.

astrobeed:

leo72:
Personalmente adotto 2 letture digitali intervallate da un delay(30), tecnica che non ha mai fallito (almeno per me).

Sopratutto se il delay è ottenuto tramite un controllo non bloccante, p.e. con la millis, semplice, funzionale e perfettamente funzionante, a seconda del tipo di contatti può essere necessario portare il tempo di attesa fino a 100 ms.

Sì, con i pulsanti non switch basta un intervallo leggermente maggiore.

Ma se devo gestire una tastiera forse conviene questa soluzione, cosi evito stalli inutili (anche quei 30ms fanno la differenza)

Usando i millis non hai stalli.

mancio:
Ma se devo gestire una tastiera forse conviene questa soluzione, cosi evito stalli inutili (anche quei 30ms fanno la differenza)

Non esistono stalli inutili se gestisci i ritardi tramite timer/millis, in tutti i casi i rimbalzi esistono per un determinato tempo e devi comunque aspettare che terminano, anche utilizzando 100 ms come ritardo vuol dire poter premere 10 tasti, o 10 volte lo stesso tasto, al secondo, per un essere umano è quasi impossibile farlo.

Personalmente preferisco un " Pre-Antirimbalzo avanzato" hardware.