[FPGA] Créer un circuit logique pour gérer les rebonds d’un interrupteur
par
, 11/08/2022 à 08h00 (1219 Affichages)
Les interrupteurs mécaniques en général (boutons-poussoirs, interrupteurs à bascule, à glissière, à levier, etc.) ont une fâcheuse habitude : ils sont sujets aux rebonds à la fermeture ou à l’ouverture du circuit. Ces rebonds sont parfois néfastes pour le fonctionnement de votre application, et il faut trouver des systèmes matériels ou logiciels pour les éviter.
Je présente ici la configuration d’un circuit logique d’une solution antirebonds sur une carte de développement FPGA, au travers de sa description avec un langage HDL (ici, Verilog).
L’objectif est décrit par les chronogrammes ci-dessous (simulation) :
En haut, le signal issu de la fermeture/ouverture d’un circuit par un interrupteur ou bouton. Le signal est « parasité » avec de multiples rebonds rapprochés. En bas, le signal debounce « nettoyé ». Une fois que le système considère le signal stabilisé (après un délai repéré en rouge), il bascule.
On utilisera les principes déjà vus lors des précédents billets :
- [FPGA] Créer un circuit logique pour détecter les fronts d’un signal
- [FPGA] Créer un circuit logique pour faire un compteur
En effet, le circuit logique à synthétiser est le suivant :
Le circuit est synchronisée avec l’horloge principale de la carte (entrée CLOCK_50), ici à la fréquence de 50MHz.
La structure de la partie gauche avec les deux bascules et la porte XOR (OU exclusif) a été vue dans le billet [FPGA] Créer un circuit logique pour détecter les fronts d’un signal.
Cette structure permet d’avoir une impulsion envoyée sur la sortie de la porte XOR à chaque rebond du bouton (front montant ou descendant).
La sortie de la porte XOR est reliée à l’entrée SCLR (Synchronous clear) d’un compteur (voir [FPGA] Créer un circuit logique pour faire un compteur), qui est donc remis à zéro à chaque rebond. C’est ce compteur qui contribue à définir la stabilité du signal après les rebonds. Le signal sera considéré comme stable si le compteur a le temps d’évoluer jusqu’à une valeur maximale. Si les rebonds sont trop rapprochés, le compteur est remis à zéro à chaque rebond avant d’attendre cette valeur maximale.
Après chaque rebond, le compteur revient à zéro. Le signal n’est pas stable…
Quand le compteur atteint sa valeur limite, la sortie TC du compteur (Terminal count) bascule à l’état haut. En configurant un compteur 19 bits, une impulsion est donc envoyée sur la sortie TC si le compteur peut atteindre la valeur 219-1 sans être interrompu par un rebond, soit pendant une durée de (1/50.106)x219=10,49ms. Après cette durée, on considère que les rebonds du bouton sont terminés.
À ce moment-là, les choses s’enchaînent, suivez les connexions du circuit…
- Le compteur se bloque (parce que son entrée ENA (enable) est reliée au signal TC inversé). Il sera débloqué au prochain rebond (par la remise à zéro du compteur qui va abaisser le signal TC, et donc réactiver le compteur).
- La sortie TC étant bloquée à l’état haut en attendant le prochain rebond, la dernière bascule c est activée et le signal stabilisé du bouton est dirigé vers la sortie debounce.
On rappelle le code du compteur (counter.v) :
Code verilog : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 module counter (CLK, ENA, SCLR, TC); parameter N = 4; // compteur N bits, valeur N par défaut input CLK, // horloge 'clock' ENA, // enable SCLR; // synchronous clear output TC; // terminal count reg [N-1 : 0] count; // compteur N bits assign TC = (count == {N{1'b1}}); // concaténation de 1, N fois always @(posedge CLK) begin // sur front montant de l'horloge if (SCLR) count <= 0; // synchronous clear else begin if (ENA) count <= count + 1'b1; end end endmodule
On donne le code du module principal top.v (top level hierarchy) :
Code verilog : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 module top(CLOCK_50, button, debounce); input CLOCK_50, // horloge principale 50MHz button; // signal du bouton, avec rebonds output debounce; // signal sans les rebonds reg a, b, c; // registres internes wire bounce, stability; // noeuds internes counter #(.N(19)) U1 // instanciation compteur 19 bits, paramètre N=19 (.CLK(CLOCK_50), .SCLR(bounce), // à chaque rebond, il faut remettre à 0 le compteur .ENA(~stability), // comptage si pas de stabilité .TC(stability) // stable si le compteur atteint la valeur Terminal Count ); assign bounce = a ^ b; // ^ : opérateur Xor assign debounce = c; always @(posedge CLOCK_50) begin // processus sur front montant de l'horloge a <= button; b <= a; if (stability) c <= b; end endmodule
Notez comment le compteur est instancié (lignes 11 à 16) et comment ses entrées-sorties sont raccordées aux nœuds du circuits.