Debouncing di pulsanti e interruttori
Un pulsante reale non genera quasi mai una transizione elettrica perfetta. Quando i contatti si toccano o si separano possono rimbalzare per alcuni millisecondi, producendo più transizioni HIGH/LOW che un microcontrollore può interpretare come pressioni multiple. Vediamo perché accade e come eliminarlo via software o hardware.
Che cos’è il contact bounce?
I contatti metallici di un pulsante possiedono massa ed elasticità. Quando vengono premuti non passano necessariamente da aperti a chiusi in un solo istante: possono toccarsi, separarsi e toccarsi nuovamente più volte prima di stabilizzarsi.
Come appare il rimbalzo di un pulsante?
Idealmente vorremmo una singola transizione netta. Nella realtà il fronte può contenere numerosi cambi di stato ravvicinati.
Perché il bouncing crea problemi?
Se il programma incrementa un contatore ogni volta che rileva una transizione, una sola pressione può incrementarlo diverse volte. Lo stesso problema può interessare menu, relè, interrupt, contatori di impulsi e sistemi di comando.
Quanto dura il rimbalzo?
Non esiste un tempo universale: dipende dalla costruzione del pulsante, dall’usura e dalle condizioni meccaniche. Nei normali comandi manuali il fenomeno è spesso nell’ordine di pochi millisecondi, ma il progetto non dovrebbe basarsi su un numero scelto alla cieca.
Debouncing software
Il metodo software consiste nel considerare valido un nuovo stato soltanto quando rimane stabile per un certo intervallo di tempo.
Debouncing non bloccante con millis()
Con Arduino possiamo memorizzare l’istante dell’ultima variazione letta e accettare il nuovo stato solo dopo che è rimasto invariato abbastanza a lungo.
const byte BUTTON_PIN = 2;
const unsigned long DEBOUNCE_MS = 20;
bool stableState = HIGH;
bool lastReading = HIGH;
unsigned long lastChange = 0;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
bool reading = digitalRead(BUTTON_PIN);
if (reading != lastReading) {
lastChange = millis();
lastReading = reading;
}
if ((millis() - lastChange) >= DEBOUNCE_MS &&
reading != stableState) {
stableState = reading;
if (stableState == LOW) {
// Una nuova pressione valida
}
}
}Debouncing con macchina a stati
Nei programmi più complessi è utile separare chiaramente gli stati: rilasciato, verifica pressione, premuto e verifica rilascio. Questo permette di riconoscere eventi come pressione, rilascio, pressione lunga e ripetizione automatica senza bloccare il programma.
Debouncing hardware
Il rimbalzo può essere filtrato anche prima che il segnale raggiunga il microcontrollore. Le soluzioni più comuni utilizzano reti RC, ingressi con isteresi o circuiti dedicati.
| Metodo | Vantaggio | Limite |
|---|---|---|
| Software | Nessun componente aggiuntivo. | Richiede codice e temporizzazione corretta. |
| RC | Semplice ed economico. | Produce fronti più lenti. |
| RC + Schmitt | Fronte logico pulito e buona immunità. | Richiede componenti aggiuntivi. |
| Debouncer dedicato | Comportamento controllato. | Costo e spazio maggiori. |
Filtro RC per il debouncing
Una resistenza e un condensatore possono trasformare i rapidi rimbalzi in una variazione più lenta della tensione. Il parametro fondamentale è la costante di tempo.
τ = 10.000 × 0,000001 = 10 ms.
Trigger di Schmitt
Un ingresso Schmitt utilizza due soglie differenti: una per la transizione LOW→HIGH e una per HIGH→LOW. Questa isteresi impedisce a piccole oscillazioni attorno alla soglia di produrre molte commutazioni.
Debouncing e interrupt
Collegare direttamente un pulsante meccanico a un interrupt non elimina il bouncing. Al contrario, ogni rimbalzo può generare una nuova richiesta di interrupt.
Encoder rotativi meccanici
Anche gli encoder meccanici possono presentare rimbalzi, ma la gestione è più delicata perché due segnali in quadratura determinano direzione e movimento. Un semplice ritardo applicato indipendentemente ai due canali può perdere transizioni valide.
Debouncing hardware o software?
| Situazione | Scelta pratica |
|---|---|
| Pulsante su Arduino/ESP32 | Debounce software non bloccante. |
| Molti pulsanti | Gestione software centralizzata. |
| Ingresso molto rumoroso | Filtro hardware + software. |
| Segnale critico indipendente dal firmware | Debounce hardware. |
| Ingresso con fronte lento | Valutare Schmitt trigger. |
| Encoder meccanico | Decodifica a stati + filtraggio appropriato. |
Errori comuni
- credere che un pulsante produca sempre un solo fronte;
- usare delay() come unica soluzione in programmi complessi;
- confondere bouncing con un ingresso flottante;
- dimenticare pull-up o pull-down;
- applicare lo stesso tempo di debounce a qualunque dispositivo senza verificarlo;
- eseguire elaborazioni lunghe dentro una ISR;
- usare un semplice RC senza considerare le soglie dell’ingresso;
- filtrare un encoder come se fosse un normale pulsante.

