IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Le blog de f-leb

[FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif

Noter ce billet
par , 15/08/2022 à 08h00 (6039 Affichages)
Les encodeurs rotatifs sont des dispositifs électromécaniques qui convertissent la position angulaire d'un axe en signaux électriques. Les encodeurs optiques qui fonctionnent en quadrature proposent deux sorties A et B en décalage de phase (90°). Le nombre d’impulsions par tour de l’axe étant une caractéristique spécifique de l’encodeur, compter les impulsions donne une image du décalage angulaire (et le nombre d’impulsions par seconde donne une image de la vitesse de rotation). L’avance ou le retard de phase d’une sortie par rapport à l’autre renseigne sur le sens de rotation.

Nom : quadrature.png
Affichages : 594
Taille : 47,3 Ko
Sens de rotation horaire (ClockWise), signal A en avance de phase sur B.
Sens de rotation antihoraire (CounterClockWise), signal B en avance de phase sur A

On fournit les chronogrammes d’une simulation ci-dessous :

Nom : encoder1.png
Affichages : 521
Taille : 124,6 Ko

En entrée de notre décodeur, les signaux A et B en quadrature sont délivrés en fonction de la rotation de l’axe à la même vitesse dans un sens sur la première moitié du temps (compteur POSCNT qui croît de 0 à 12), puis dans l’autre sens sur la seconde moitié (compteur POSCNT qui décroît de 12 à 0). Le signal de sortie UPDN renseigne aussi sur le sens de rotation de l’axe (état bas quand le compteur croît, état haut quand il décroît).
Pour une résolution maximale, le compteur doit évoluer sur tous les fronts montants et descendants des signaux A et B (signal interne count_enable, avec une impulsion pour chaque front détecté sur les signaux A et B).

Pour détecter les fronts, on reprend les principes détaillés dans un billet précédent [FPGA] Créer un circuit logique pour détecter les fronts d’un signal avec les signaux A et B qui traversent des bascules D en cascade :

Nom : cha-chb.png
Affichages : 525
Taille : 23,0 Ko
Schéma partiel

Code verilog : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
reg [2:0] chA, chB;  // chA et chB, tableaux de 3 registres
…
	always @(posedge CLOCK_50) chA <= {chA[1:0], A};		
	always @(posedge CLOCK_50) chB <= {chB[1:0], B};

Les bascules en entrée chA[0] et chB[0] synchronisent les signaux de l’encodeur sur l’horloge. Chaque bascule traversée ensuite « retarde » le signal afin de déterminer les transitions :
Formule mathématique

En prenant en compte tous les fronts :
Formule mathématique

Soit en Verilog :
Code verilog : Sélectionner tout - Visualiser dans une fenêtre à part
assign count_enable = (chA[1] ^ chA[2]) || (chB[1] ^ chB[2]);

La détection du sens de rotation est plus délicate, mais son équation logique est révélée si on pose la table de vérité :


chA[1] chB[1] chA[2] chB[2] Incrément UPDN
1 1 0 1 +1 0
0 0 1 0 +1 0
0 1 0 0 +1 0
1 0 1 1 +1 0
1 0 0 0 -1 1
0 1 1 1 -1 1
1 1 1 0 -1 1
0 0 0 1 -1 1
x x x x 0 x
On en déduit :
Formule mathématique

Et en Verilog :
Code verilog : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
assign count_direction = (chA[1] ^ chB[2]);
…
always @(posedge CLOCK_50) begin	// sur front montant de l'horloge
	if (count_enable) begin
		UPDN <= count_direction;
	…

Le code complet :
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, A, B, POSCNT, UPDN);
    localparam N = 8;   // compteur 8 bits

    input       CLOCK_50,           // horloge principale 50MHz
                A, B;               // signaux de l'encodeur en quadrature
    output  reg [N-1:0] POSCNT,     // position, compteur N bits
            reg UPDN;               // sens de rotation 

    reg [2:0] chA, chB;             // chA et chB, tableaux de 3 registres


    assign count_enable = (chA[1] ^ chA[2]) || (chB[1] ^ chB[2]); // ^ : opérateur Xor
    assign count_direction = (chA[1] ^ chB[2]);   
                  
    always @(posedge CLOCK_50) chA <= {chA[1:0], A};        
    always @(posedge CLOCK_50) chB <= {chB[1:0], B};
    
    always @(posedge CLOCK_50) begin  // sur front montant de l'horloge   
        if (count_enable) begin
            UPDN <= count_direction;
            if (count_direction)
                POSCNT <= POSCNT - 1'b1;
            else 
                POSCNT <= POSCNT + 1'b1;
        end
    end 
endmodule

Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog Viadeo Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog Twitter Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog Google Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog Facebook Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog Digg Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog Delicious Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog MySpace Envoyer le billet « [FPGA] Créer un circuit logique pour décoder les signaux en quadrature d’un encodeur rotatif » dans le blog Yahoo

Tags: fpga, verilog
Catégories
Programmation , FPGA

Commentaires