Differenze tra Interrupt e campionamento per il pulsante hardware?


8

Ho un pulsante hardware collegato a un interrupt, ma il mio problema è che rimbalza un po ', rendendo il pulsante premuto inaffidabile. Penso che una buona parte di questi problemi sarebbe risolta campionando nel circuito principale, ma questo sembra tecnicamente sbagliato.

Gli interrupt sono più appropriati per la comunicazione all'interno del circuito o sono appropriati anche per gli switch hardware? In tal caso, quali tecniche di rimbalzo posso usare?

Ho provato a mantenere una variabile timer e a confrontarla con l'ora corrente, i ritardi e altre tecniche. Sembra che i rimbalzi siano così veloci che non importa.



Non c'è nulla di sbagliato nel campionamento nel loop principale, se si reagisce nel loop principale. Gli interrupt sono più appropriati se si desidera reagire in modo asincrono. A volte lo fai, a volte no.
Eugene Ryabtsev il

Il modo migliore per rimbalzare è un semplice filtro passa-basso.
lucas92,

Risposte:


8

Il debouncing è una FAQ. Dovresti essere in grado di trovare ... un numero pressoché illimitato di pagine Web sull'argomento. Smith ha anche commentato il PDF ampiamente letto di Jack Ganssle sull'argomento. E con tutte queste risposte hai entrambi i metodi hardware e software.

Aggiungerò a questa "letteratura" solo un po 'parlando principalmente di idee che non sono già state trattate bene. Ma prima di me, un punto o due:

  1. Il debounc in hardware analogico può ottenere risultati che non è possibile ottenere da uno switch "osservato" solo digitalmente su base periodica mediante polling o persino da eventi di cambio pin hardware. Ma puoi fare "abbastanza bene" a tutti gli effetti, in modo digitale. Quasi nessuno oggigiorno utilizza soluzioni di debouncing analogico esterno. Ma ho usato di tutto, dall'allungamento del polso usando gli one-shot (74121) alle tecniche menzionate da Jack Ganssle qui .
  2. Per coloro che eseguono solo la programmazione integrata e non sono affatto interessati all'apprendimento dell'elettronica, il rimbalzo degli switch è probabilmente uno dei due set di competenze di base necessari. Il funzionamento dei LED è probabilmente l'altro. E con questo, non intendo avere una sola abilità in questi. Intendo essere in grado di farlo in diversi modi. Così realmente fare bisogno di completamente apprehend quanto scrive Jack Ganssle circa, e più ancora, per quanto riguarda gli interruttori.

Da quando ho citato lo stiramento del polso usando un 74121 e poiché Jack Ganssle non lo menziona, e nessuno lo fa ancora qui, potrei anche fornire questo link aggiuntivo come ulteriore lettura suggerita sull'uso del 74121 o 555 come un colpo solo timer per interruttori di rimbalzo.


Ora, continuiamo a farlo attraverso l'osservazione con un microcontrollore.

Di solito uso una macchina a stati per gestire il rimbalzo. Questo è quasi sempre guidato da un normale "battito cardiaco" che ho impostato su8SM, dove possibile. (In genere NON uso eventi di interruzione triggerati da bordi per diversi motivi.)

La macchina a stati si presenta così:

schematico

simula questo circuito - Schema creato usando CircuitLab

Il valore di DEBOUNCED per lo switch potrebbe assumere i valori "inattivo", "attivo" e "sconosciuto". In questo modo, è possibile assicurarsi che il software sia in attesa fino a quando il valore dell'interruttore non si stabilizza dopo l'inizializzazione. Ma di solito non mi preoccupo di questo. Sostituisco il valore "sconosciuto" con un valore predefinito e utilizzo invece un sistema di valori binari.

La macchina a stati viene inserita impostando prima il valore debounce sul suo valore predefinito e quindi inserendo lo stato "CAMBIAMENTO" della macchina a stati. Ad ogni intervallo di tempo (in genere8SMse riesco a cavarmela), leggerò il valore di commutazione corrente ed eseguirò un aggiornamento dello stato corrente e possibilmente del valore rimbalzato. Quindi esco. Il codice di alto livello accede quindi solo allo stato rimbalzato.

Se per me è importante, posso anche mantenere uno stato di rimbalzo precedente. In questi casi, quando aggiorno lo stato rimbalzato stesso, copierò innanzitutto tale stato in uno "stato rimandato precedente". Posso quindi utilizzare la coppia di valori per determinare se c'è stata una transizione rimbalzata. A volte, non mi importa delle transizioni. Qualche volta lo faccio. Quindi dipende. Ma in tutti i casi, voglio solo conoscere le transizioni che sono state rimbalzate. Non mi preoccupo mai delle transizioni runt . Quindi il codice di alto livello non utilizza mai lo stato interno utilizzato dalla macchina a stati per il proprio lavoro.

Una delle cose belle di questo metodo è che posso rimbalzare un'intera porta di switch, contemporaneamente. E posso farlo anche senza un singolo ramo nel codice di interruzione. Ciò significa un codice di debouncing molto veloce e breve fino alla larghezza della porta del microcontrollore (generalmente 8 bit di larghezza.) Un esempio di Atmel AT90 mostra come questo si ottiene utilizzando un evento di interruzione Timer0:

.equ    SWPORTPINS  =   PINB
.def    SwRawCurr   =   r4
.def    SwRawPrev   =   r5
.def    SwState     =   r6
.def    SwDebCurr   =   r7
.def    SwDebPrev   =   r8

            ; Debounce the input switches.

                mov     SwRawPrev, SwRawCurr
                in      SwRawCurr, SWPORTPINS
                mov     Timer0Tmp1, SwRawCurr
                eor     Timer0Tmp1, SwRawPrev
                mov     Timer0Tmp0, Timer0Tmp1
                or      Timer0Tmp1, SwState
                mov     SwState, Timer0Tmp0
                mov     Timer0Tmp0, Timer0Tmp1
                com     Timer0Tmp0
                and     Timer0Tmp1, SwDebCurr
                and     Timer0Tmp0, SwRawCurr
                or      Timer0Tmp1, Timer0Tmp0
                mov     SwDebPrev, SwDebCurr
                mov     SwDebCurr, Timer0Tmp1

Ora, questo esempio mostra l'intero affare, inclusi i valori di switch debounce precedenti e attuali. Ed esegue anche tutte le transizioni di stato necessarie. Non mostro l'inizializzazione di questo codice. Ma quanto sopra capisce quanto sia facile far funzionare la macchina a stati e quanto poco codice è necessario per farlo. È abbastanza veloce e semplice e non richiede ramificazioni (che a volte comporta cicli aggiuntivi e spazio di codice aggiuntivo).


Preferisco usare 8SMtempismo perché lunghi, lunghi test con una varietà di persone diverse che utilizzano attrezzature su cui ho lavorato in passato mi hanno portato lì. Ho provato periodi più lunghi e quando lo faccio, inizio a convincere la gente a dirmi che la "reattività" non è "vivace". (Al giorno d'oggi, con i bambini che crescono a lavorare in tempo reale "sparagli", potrei anche accorciarlo ulteriormente. Si lamenteranno amaramente anche dei lievi ritardi causati dai moderni televisori digitali nell'installazione e nella visualizzazione di un frame.)

Alcune persone avranno sentimenti molto chiari su quanto dovrebbe essere nitido e reattivo un sistema. Fresco e reattivo significa campionare più spesso, non meno. Ma personalmente, trovo20SMperiodi di osservazione accettabili. (Io non trovo volte più a lungo abbastanza buono anche per me, però.)

Si noti che la macchina a stati che ho citato deve prima entrare nello stato SETTAGGI e quindi rimanere lì per un altro tempo di campionamento prima che il valore di DEBOUNCED venga aggiornato. Quindi premere un pulsante e tenerlo premuto, anche nelle migliori circostanze, richiederà queste transizioni:

  1. passare da SETTLED a CHANGING
  2. passare da MODIFICA a IMPOSTATO
  3. rimanere in SETTLED, aggiornando DEBOUNCED

Pertanto, per ottenere un nuovo stato rimbalzato sono necessari almeno 3 periodi di campionamento.

Un pulsante richiederà almeno 6 volte di campionamento per passare da inattivo, a attivo, e quindi di nuovo a inattivo.


Ho citato i dettagli di cui sopra in modo che sia assolutamente chiaro che un tempo di campionamento di 8SM significa che da qualche parte in mezzo 16SM<t24SMper passare da inattivo a un risultato rimbalzato attivo riconosciuto. E ci vorrà un altro24SMprima che lo stato possa tornare inattivo. Questo è un minimo di40SM<t48SM per passare attraverso un intero ciclo di pulsanti.

L'uso di tempi di campionamento più lunghi avrà periodi di conseguenza più lunghi. Usando il20SM Ho già detto "accettabile" per me, quindi significa da qualche parte in giro 100SM<t120SMper un intero ciclo di pulsanti. E che sta ottenendo esattamente su nella zona dove la gente non tendono a notare. Certamente non mi piace la "sensazione" se si allunga.

Se segui questa strada, non essere sprezzante nell'utilizzare tempi di campionamento più lunghi. Se è necessario, penso che anche tu debba fare molti test con utenti / consumatori.

E se stai sviluppando codice per una tastiera di battitura, usa tempi più brevi. Il record per una dattilografa è stato stabilito decenni fa a 217 wpm. Ciò si traduce in circa una chiave ogni45SM. I dattilografi del genere colpiscono più chiavi in ​​un ordine controllato. Per ottenere buone prestazioni per dattilografi molto veloci utilizzando un sistema di commutazione relè reed bagnato con mercurio, ho scoperto che2SM ha funzionato bene.


i tempi di rimbalzo variano da 0 per interruttori a mercurio a "pochi" tipi di ms per interruttori micro tattili a 30 ms per interruttori a levetta, quindi 8 ms è un buon numero considerando l'aumento del tempo di rimbalzo con l'invecchiamento.
Tony Stewart Sunnyskyguy EE75

@ TonyStewart.EEsince'75 Ho scelto di eseguire test approfonditi con gli utenti utilizzando apparecchiature con una varietà di diversi tipi di interruttori e la cifra di 8 ms proviene da una distillazione di tutto ciò che funziona. (Non mi sono preoccupato così tanto della "teoria" poiché la pratica di costruire e realizzare switch, e la loro pura varietà, ha reso scoraggiante la raccolta e l'analisi di quei dati.) Uso sempre 8 ms, quando possibile, poiché sembra per essere il punto debole data la lunga esperienza nella scrittura di software che funziona e dove i reclami post-vendita raggiungono lo zero esatto (su quel punto, comunque.)
Jon

@ TonyStewart.EEsince'75 A proposito, questo test COMPRENDE l'uso di relè reed a contatto con il mercurio come parte degli interruttori a chiave utilizzati nelle tastiere (che, penso, non sembrano essere più realizzati). In questi casi, però, Vado a campionamento 1-2 ms (dipende dall'unità.)
Jon

Quella luce da giardino laser che ho menzionato una volta fa ... ha interruttori di controllo a membrana tattile con basso tempo di rimbalzo, ma il programmatore li ha fatti commutare a una frequenza di 10Hz, quindi bisogna rilasciarli in <100ms altrimenti l'alimentazione si spegne. ? su un'altra nota .. La tastiera per pianoforte Yamaha è estremamente veloce e supporta il rollover a 10 tasti mentre solo la tastiera per PC IBM originale supporta il vero rollover all'avanguardia. Da allora tutte le tastiere sono le prime battute sono all'avanguardia e quindi ribaltamento del bordo finale che è una PITA per le abilità di digitazione scarse come la mia
Tony Stewart Sunnyskyguy EE75

@ TonyStewart.EEsince'75 Questa area di campionamento degli switch è un punto dolente. L'avvento di micro economici con zero debouncing esterno e interruttore chissà cosa, aggiunti all'ignoranza del programmatore incorporato, ha fatto sì che trovo effettivamente problemi con quasi OGNI SINGOLO strumento incorporato con una tastiera o un pulsante. Funzionano TUTTI terribilmente, a mia discrezione. E penso che sia principalmente perché i programmatori hanno poca o nessuna esperienza, basta "cercarlo e applicarlo" senza pensarci. A volte, salando il loro codice con punti di polling casuali, anche. È spazzatura. Sconvolgente. È facile da ottenere.
Jon

5

Il debounce può essere eseguito nel software mascherando gli IRQ per il tempo di rimbalzo o nell'hardware aggiungendo un condensatore di mantenimento con RC = T> tempo di rimbalzo che varia da 1 a 15ms a seconda delle dimensioni dell'interruttore.

  • ad es. 100k pullup e 0.1μF sull'interruttore = 10ms @ 63% o ~ 8ms al 50% Vdd o se si utilizza la porta di trigger Schmitt @ 1.33V = Vil da 5V o ~ 73% V + ~ 12ms

4

Per effettuare un de-bounce SW, registra la data / ora dell'evento corrente e controlla il ritardo dall'ultimo evento valido:

#define DELAY_DEBOUNCE       150

uint32_t    __ts_lastpress = 0;

ISR(some_vector)
{
    uint32_t    now = millis(); // some timer tick counter

    if ( now - __ts_lastpress < DELAY_DEBOUNCE )
        return; // ignore it

    __ts_lastpress = now;
    // do the job here
}

UPD: con poche modifiche è possibile registrare un doppio clic:

#define DELAY_DEBOUNCE       150
#define DELAY_DOUBLE_CLICK   600

uint32_t    __ts_lastpress = 0;

ISR(some_vector)
{
    uint32_t    now = millis(); // some timer tick counter

    if ( now - __ts_lastpress < DELAY_DEBOUNCE )
        return; // ignore it

    // do the job here
    if ( now - __ts_lastpress < DELAY_DOUBLE_CLICK )
    {
        // it is double click
    }
    else
    {
        // it is single click
    }

    __ts_lastpress = now;
}

2

Gli interrupt sono sicuramente ottimi anche per gli switch hardware. Usando gli interrupt, stai evitando un grande spreco di risorse e possibilmente energia, specialmente se hai a che fare con dispositivi alimentati a batteria.

Inoltre, man mano che il codice diventa sempre più grande, vedrai che è ancora più semplice implementare gli interrupt per i pulsanti piuttosto che eseguirne il polling nel tuo ciclo principale.

Per quanto riguarda il tuo rimbalzo, è probabilmente un problema di codifica. In genere utilizzo un timer di ~ 10ms per il rimbalzo, mentre controllo il rilascio del pulsante. Assicurati di disabilitare temporaneamente anche l'interruzione del pulsante mentre lo rimbalzi, quindi la routine di interruzione non viene eseguita più volte.

Se i problemi persistono, pubblica qui il codice, in modo che possiamo aiutarti.


1

Questo è abbastanza simile alla risposta di Tony Stewart, ma penso che potrebbe essere ampliato un po '.

Lo schema superiore è per un interrupt sul fronte basso o sul fronte di discesa. Lo schema inferiore è per un interrupt in alto o in fronte di salita.

schematico

simula questo circuito - Schema creato usando CircuitLab

personalmente, dato il costo di un condensatore, vale la pena per me semplicemente usarlo, piuttosto che preoccuparmi se il mio debounce del software è difettoso.

Si noti che, come ha detto Tony Stewart, la costante di tempo in questo circuito è di 10ms (R*C o 10KΩ*1μF). Ci vorranno da tre a cinque costanti di tempo (a seconda della sensibilità del microcontrollore per il reset del pulsante stesso, quindi se il microcontrollore ha problemi con la ripetizione della funzione di interruzione, potrebbe essere la causa e potrebbe essere necessario regolare il cappuccio / resistenza in modo che l'interruzione non si verifichi più volte (ovvero solo se l'interruzione è impostata per funzionare su un segnale alto o basso e non sul fronte di salita o di discesa.

Relativo al debouncing hardware


1
Entrambe le versioni funzionano sia per + ve che per -ve edge, specialmente se il pin di interrupt ha una caratteristica di input in stile schmitt (molti lo fanno). Sia SW1 che SW2 subiscono un'impennata di corrente alla chiusura. Alcuni pulsanti a bottone in carbonio possono dare risultati diversi rispetto ai pulsanti a cupola in metallo.
glen_geek,

1

Gli esseri umani sono lenti, non abbiamo bisogno dell'attenzione immediata di un micro che si trova nella gamma dei microsecondi.

Questo, ovviamente, non è l'unico né il modo giusto di farlo sempre, ma trovo generalmente più sensato impostare un timer (molti micro hanno tick di sistema) per sparare un interruzione a intervalli fissi e spostare lo stato del pin in un variabile per il codice da esaminare in seguito. Si finisce con un var che è pieno di cenere durante il rimbalzo

10010110 frassino

ma in alcuni punti nel tempo otterrai questi 4 valori:
01111111 fronte di salita appena rimosso il
pulsante 11111111 in stato stabile su
10000000 fronte di discesa appena rimosso il
pulsante 00000000 in stato stabile verso il basso

Il più delle volte, però, uso solo un contatore che si ripristina durante il rimbalzo. È veloce, testato e facile da fare.
Se fallisce, provo qualcosa di più intelligente dal documento Ganssle suggerito da altri!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.