mardi 10 septembre 2013

Encodeur en quadrature de phase en VHDL

Le signal de sortie d'un encodeur optique à la forme suivante:


Ce signal est intéressant car déphasé de 90° il permet de déterminer le sens de déplacement. En effet, si la voie A est en avance par rapport à la voie B on se déplace dans un sens, dans le cas contraire on se déplace dans l'autre sens.
Dans le programme VHDL, j'utilise une machine à états finis (FSM Finite State Machine) pour compter ou décompter en fonction du niveau du signal reçu.

Diagramme d'état

Le schéma suivant présente les états possibles en fonction du niveau logique issu du capteur optique. Chaque cycle peut compter jusqu'a 4 incréments ou décréments. Il est toujours possible de modifier le programme de façon à prendre en compte que 1 ou 2 incréments par cycle en fonction de la précision que l'on désire.


Le diagramme d'état:


Le diagramme d'état prend en compte toutes les transitions possibles, ce qui correspond par exemple à des cas ou le cycle ne s'est pas totalement terminé. Imaginons que l'on se trouve à D5, le compteur à déjà compté jusqu'a 3, si on recule avant d'arriver à D6, on passe à l'état G2 qui immédiatement décrémentera d'une unité.

Programme

library ieee;
use ieee.std_logic_1164.all;

entity FSM_encoder is
port (
                clk: in std_logic;
                init: in std_logic;
                wayA_B : in std_logic_vector(1 downto 0);
                en: out std_logic; -- enable
                du: out std_logic); --down/up
end FSM_encoder;


architecture machine_behavior of FSM_encoder is

type state is (idle,D0,D1,D2,D3,D4,D5,D6,G0,G1,G2,G3,G4,G5,G6);
signal next_state,reg_state:state;

begin

process(clk)
        begin
                if rising_edge(clk) then
                        if init='1' then reg_state<=idle;
                        else reg_state<=next_state;
                        end if;
                end if;
end process;
----
process (reg_state,wayA_B)
        begin
        case reg_state is

                        when idle=>
                                        if (wayA_B = "01") then next_state<=G0;
                                        elsif (wayA_B = "10") then next_state<=D0;
                                        else next_state<=idle;
                                        end if;

                        when D0=> next_state<=D1;
                        when D1=>
                                        if (wayA_B = "10") then next_state<=D1;
                                        elsif (wayA_B = "11") then next_state<=D2;
                                        elsif (wayA_B = "00") then next_state<=G6;
                                        else next_state<=idle;
                                        end if;
                        when D2=> next_state<=D3;
                        when D3=>
                                        if (wayA_B = "01") then next_state<=D4;
                                        elsif (wayA_B = "10") then next_state<=G4;
                                        elsif (wayA_B = "11") then next_state<=D3;
                                        else next_state<=idle;
                                        end if;
                        when D4=> next_state<=D5;
                        when D5=>
                                        if (wayA_B = "00") then next_state<=D6;
                                        elsif (wayA_B = "01") then next_state<=D5;
                                        elsif (wayA_B = "11") then next_state<=G2;
                                        else next_state<=idle;
                                        end if;
                        when D6=> next_state<=idle;

                        when G0=> next_state<=G1;
                        when G1=>
                                        if (wayA_B = "01") then next_state<=G1;
                                        elsif (wayA_B = "11") then next_state<=G2;
                                        elsif (wayA_B = "00") then next_state<=D6;
                                        else next_state<=idle;
                                        end if;
                        when G2=> next_state<=G3;
                        when G3=>
                                        if (wayA_B = "01") then next_state<=D4;
                                        elsif (wayA_B = "10") then next_state<=G4;
                                        elsif (wayA_B = "11") then next_state<=G3;
                                        else next_state<=idle;
                                        end if;
                        when G4=> next_state<=G5;
                        when G5=>
                                        if (wayA_B = "00") then next_state<=G6;
                                        elsif (wayA_B = "10") then next_state<=G5;
                                        elsif (wayA_B = "11") then next_state<=D2;
                                        else next_state<=idle;
                                        end if;
                        when G6=> next_state<=idle;
        end case;
end process;

--down/up assignement
en<='1' when (reg_state=D0 or reg_state=D2 or reg_state=D4 or reg_state=D6 or reg_state=G0 or reg_state=G2 or reg_state=G4 or reg_state=G6) else '0';
du<='1' when (reg_state=D0 or reg_state=D2 or reg_state=D4 or reg_state=D6) else '0';

end machine_behavior;
Ce programme est utilisé dans le cas ou la sortie est connectée à des compteurs décimaux mise en cascade. La sortie en(enable) valide le comptage si sa valeur est '1' et du(down/up) détermine si on incrémente ou décrémente suivant sa valeur '0' ou '1'.

Voici un extrait de la simulation sous ModelSim avec l'exemple énoncé précédemment. On remarque bien que la valeur de du passe à '0' quand on revient vers la gauche momentanément.
(cette image est a mettre à jour car on ne distingue pas bien les noms des signaux)



Aucun commentaire:

Enregistrer un commentaire