Newsgroup: it.hobby.elettronica.digitale
Titolo: Un debounce serio

Normalmente riesco a fare un debounce di un tasto meccanico, che ha i 
suoi rimbalzi, utilizzato "manualmente" mediante un semplice algoritmo:
 
- campiono la linea del tasto in una ISR richiamata ogni ms;
- al fronte registro l'evento di pressione e maschero per un
   certo tempo la linea;
- allo scadere del tempo di debounce, torno a campionare la linea alla
   ricerca dell'altro fronte che corrisponde all'evento di rilascio, che
   avrà il suo tempo di debounce
 
Mi sono divertito anche a creare gli eventi di pressione ripetuta quando 
il tasto rimane premuto (un po' come quando si preme sulla tastiera una 
lettera e questa compare ripetuta su un editor di testo ad una velocità 
maggiore rispetto alla prima lettera).
 
Ora sto combattendo con un solito microswitch meccanico che però è 
azionato da una camma che può ruotare a velocità molto diverse tra loro. 
A velocità bassa, gli impulsi (comprensivi di debounce) sono larghi 
anche 15ms. A velocità elevata, gli impulsi sono molto stretti, anche 
2-3ms e sono abbastanza ravvicinati.
 
Un debounce di 5ms non va bene per gli impulsi larghi (conto l'impulso 
due volte) e un debounce di 10ms non va bene per gli impulsi brevi 
(rischio di non vedere il secondo impulso ravvicinato).
 
Esiste qualche algoritmo/approccio serio per risolvere questo problema 
di debounce?

 ha scritto nel messaggio 
news:l1kk21$a10$3...@dont-email.me...

E perche' non usi l'interrupt per 'sentire' il primo fronte del tasto 
premuto?
Mi sembra inefficiente stare li' a testare la linea, 1000 volte al secondo, 
per vedere qualcosa arriva dal tasto
Poi quando arriva il primo fronte inizi a testare che il tasto rimanga 
premuto per almeno tot tempo, io uso 20 mS come debounce tastiere e contatti 
meccanici vari
Non ho ben capito perche', dopo aver 'visto' il fronte di salita ed aver 
atteso il tempo x,  attendi il fronte di discesa del tasto
Dopo aver visto fronte salita ed atteso x mS col tasto premuto non ti basta 
per considerare 'premuto' il tasto?
Certo che su un contatto meccanico che ti fa un 2 mS di segnale, non saprei 
come distinguere i rimbalzi dal contatto vero e proprio
 
 

 di debounce?
 
Macchina a stati finiti?
 
Hai fondamentalmente 6 stati,
 
1) aperto
2) fronte di chiusura, ignori per N ms. l'eventuale bounce
3) dopo N ms, se ritorna aperto è rumore e torni ad 1), se no vai a 4)
4) chiuso
5) fronte di riapertura, ignori per N ms. l'eventuale bounce
6) dopo N ms, se ritorna chiuso è rumore e torni a 4), se no vai a 1)
 
Se proprio vuoi essere sicuro, puoi aggiungere uno stato intermedio 
3bis) (e pure 6bis) e verificare che rimanga chiuso (aperto) senza 
bounce per M ms.

 come distinguere i rimbalzi dal contatto vero e proprio
 
Infatti è questo il problema di fondo.  Il normalissimo microswitch che 
premuto a mano crea impulsi di 10-20ms, con questa camma in rotazione 
veloce crea impulso di 2ms!!
 

 bounce per M ms.
 
Esagerato!
Come dicevo a Roberto, non mi preoccupano gli spike dovuti a problemi di 
EMC, ma solo i rimbalzi che non hanno natura casuale, ma deterministica 
con il tasto.
 
La complicazione che hai con gli stati 2 e 3 (e anche 3bis) io non la 
metto mai: al primo fronte, per me il tasto è stato premuto, punto e 
basta (suppongo, appunto, che non ci siano spike).
 
Come fai per gestire i tempi?  Mediante campionamento (per esempio, ogni 
1ms) oppure facendo "polling" sul tasto?  Il campionamento a 1ms, come 
diceva Roberto, è inefficiente (e con impulsi di 2ms non è possibile 
aumentarlo).  Con il "polling" è anche peggio: se l'impulso dura 10ms, 
sto lì bloccato per 10ms.
 
 

 sto lì bloccato per 10ms.
 
Beh se vuoi catturare eventi di 2ms, non hai alternativa al campionare 
almeno ogni 1ms... Shannon's Law.
 
Quello che puoi fare è una macchina a stati semplice, due stati, 
chiamata anche nell'ISR, per cui ad ogni giro ti bastano un paio di IF 
per uscire (lo stato attuale, e l'output dello switch).
 

 di debounce?
 
Per ogni tasto o switch puoi usare un contatore di eventi consecutivi ed un flag.
Su polling di, diciamo, 1ms campioni la linea ed incrementi il contatore se il nuovo stato è uguale al vecchio stato.
Riesci così a filtrare anche il "make" del tasto con, ad esempio, 5 stati ON consecutivi.
Il "break" può essere dei canonici 20 cicli (20 ms quindi).
Ogni volta che la linea cambia stato si deve resettare il contatore (a saturazione oer evitare il rolling del conteggio).
Per lo switch basta usare conteggio minori.
Non so se mi sono capito.
 
Piccio.

 veloce crea impulso di 2ms!!
 
Se il contatto e' cosi' veloce, io non userei un contatto meccanico
Inevitabilmente il rumore introdotto potrebbe essere piu' grande del segnale 
che ti serve
Usa altro interruttore, ottico, magnetico
 
 

 Usa altro interruttore, ottico, magnetico
 
Su questo hai perfettamente ragione, ma purtroppo non posso :-(
 

 per vedere qualcosa arriva dal tasto
 
No, se hai già a disposizione un timer e quindi l'overhead si limita alla
lettura di un I/O. Fra l'altro il metodo in polling (descritto abilmente da
Piccio) è quello più robusto, in quanto è immune da eventuali comportamenti
"strani" in corrispondenza di forti disturbi in ingresso (che siano
rimbalzi o altro). Gli interrupt sui fronti sono malvagi, e quando sono
usati per gestire segnali provenienti dall'esterno sono diabolici.
 
-- 
Fletto i muscoli e sono nel vuoto.

 usati per gestire segnali provenienti dall'esterno sono diabolici.
 
Sono d'accordo.
 

 evento o della scadenza di un timer, senza fare altro.
 
Questo io lo chiamo "busy wait", ma lo considero sempre un tipo di polling.
