Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> VHDL

Comment créer une machine à états finis en VHDL

Une machine à états finis (FSM) est un mécanisme dont la sortie dépend non seulement de l'état actuel de l'entrée, mais également des valeurs d'entrée et de sortie passées.

Chaque fois que vous avez besoin de créer une sorte d'algorithme dépendant du temps en VHDL, ou si vous êtes confronté au problème de l'implémentation d'un programme informatique dans un FPGA, cela peut généralement être résolu en utilisant un FSM.

Les machines à états en VHDL sont des processus cadencés dont les sorties sont contrôlées par la valeur d'un signal d'état. Le signal d'état sert de mémoire interne de ce qui s'est passé lors de l'itération précédente.

Cet article de blog fait partie de la série de didacticiels VHDL de base.

Tenez compte de l'état des feux de circulation à cette intersection :

Les feux de circulation ont un nombre fini d'états, auxquels nous avons donné des noms identifiables. Notre exemple de machine d'état n'a pas d'entrées de contrôle, la sortie est l'état des lumières dans les directions nord/sud et ouest/est. C'est le temps écoulé et l'état précédent des sorties qui fait avancer cette machine d'état.

Nous pouvons représenter les états en VHDL en utilisant un type énuméré . Ce sont des types de données comme signed ou unsigned , mais au lieu de nombres entiers, nous pouvons fournir une liste personnalisée de valeurs possibles. En fait, si vous regardez dans le package std_logic_1164, vous constaterez que le std_ulogic type n'est rien de plus qu'un type énuméré avec les valeurs 'U' , 'X' , '0' , '1' , 'Z' , 'W' , 'L' , 'H' , et '-' répertoriés comme valeurs d'énumération.

Une fois que nous avons notre type énuméré, nous pouvons déclarer un signal du nouveau type qui peut être utilisé pour garder une trace de l'état actuel du FSM.

La syntaxe pour déclarer un signal avec un type énuméré en VHDL est :
type <type_name> is (<state_name1>, <state_name2>, ...);
signal <signal_name> : <type_name>;

En utilisant le signal d'état, la machine à états finis peut ensuite être implémentée dans un processus avec une instruction Case. L'instruction Case contient une instruction When pour chacun des états possibles, obligeant le programme à emprunter des chemins différents pour chaque état. L'instruction When peut également contenir du code qui doit être exécuté dans cet état particulier. L'état changera alors généralement lorsqu'une condition prédéfinie est remplie.

Ceci est un modèle pour une machine d'état à processus unique :
process(Clk) is
begin
    if rising_edge(Clk) then
        if nRst = '0' then
            State <= <reset_state>;
        else
            case State is
                when <state_name> =>
                    <set_outputs_for_this_state_here>
                    if <state_change_condition_is_true> then
                        State <= <next_state_name>;
                    end if;
                ...
            end case;
        end if;
    end if;
end process;

Remarque :
Il existe plusieurs façons de créer un FSM en VHDL. Découvrez les différents styles ici :
Machine d'état à un processus vs à deux processus vs à trois processus

Exercice

Dans ce didacticiel vidéo, nous allons apprendre à créer une machine à états finis en VHDL :

Le code final pour la machine d'état testbench :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T20_FiniteStateMachineTb is
end entity;

architecture sim of T20_FiniteStateMachineTb is

    -- We are using a low clock frequency to speed up the simulation
    constant ClockFrequencyHz : integer := 100; -- 100 Hz
    constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;

    signal Clk         : std_logic := '1';
    signal nRst        : std_logic := '0';
    signal NorthRed    : std_logic;
    signal NorthYellow : std_logic;
    signal NorthGreen  : std_logic;
    signal WestRed     : std_logic;
    signal WestYellow  : std_logic;
    signal WestGreen   : std_logic;

begin

    -- The Device Under Test (DUT)
    i_TrafficLights : entity work.T20_TrafficLights(rtl)
    generic map(ClockFrequencyHz => ClockFrequencyHz)
    port map (
        Clk         => Clk,
        nRst        => nRst,
        NorthRed    => NorthRed,
        NorthYellow => NorthYellow,
        NorthGreen  => NorthGreen,
        WestRed     => WestRed,
        WestYellow  => WestYellow,
        WestGreen   => WestGreen);

    -- Process for generating clock
    Clk <= not Clk after ClockPeriod / 2;

    -- Testbench sequence
    process is
    begin
        wait until rising_edge(Clk);
        wait until rising_edge(Clk);

        -- Take the DUT out of reset
        nRst <= '1';

        wait;
    end process;

end architecture;

Le code final pour la machine d'état module :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T20_TrafficLights is
generic(ClockFrequencyHz : integer);
port(
    Clk         : in std_logic;
    nRst        : in std_logic; -- Negative reset
    NorthRed    : out std_logic;
    NorthYellow : out std_logic;
    NorthGreen  : out std_logic;
    WestRed     : out std_logic;
    WestYellow  : out std_logic;
    WestGreen   : out std_logic);
end entity;

architecture rtl of T20_TrafficLights is

    -- Enumerated type declaration and state signal declaration
    type t_State is (NorthNext, StartNorth, North, StopNorth,
                        WestNext, StartWest, West, StopWest);
    signal State : t_State;

    -- Counter for counting clock periods, 1 minute max
    signal Counter : integer range 0 to ClockFrequencyHz * 60;

begin

    process(Clk) is
    begin
        if rising_edge(Clk) then
            if nRst = '0' then
                -- Reset values
                State   <= NorthNext;
                Counter <= 0;
                NorthRed    <= '1';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '1';
                WestYellow  <= '0';
                WestGreen   <= '0';

            else
                -- Default values
                NorthRed    <= '0';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '0';
                WestYellow  <= '0';
                WestGreen   <= '0';

                Counter <= Counter + 1;

                case State is

                    -- Red in all directions
                    when NorthNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= StartNorth;
                        end if;

                    -- Red and yellow in north/south direction
                    when StartNorth =>
                        NorthRed    <= '1';
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= North;
                        end if;

                    -- Green in north/south direction
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        -- If 1 minute has passed
                        if Counter = ClockFrequencyHz * 60 -1 then
                            Counter <= 0;
                            State   <= StopNorth;
                        end if;

                    -- Yellow in north/south direction
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= WestNext;
                        end if;

                    -- Red in all directions
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= StartWest;
                        end if;

                    -- Red and yellow in west/east direction
                    when StartWest =>
                        NorthRed   <= '1';
                        WestRed    <= '1';
                        WestYellow <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= West;
                        end if;

                    -- Green in west/east direction
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        -- If 1 minute has passed
                        if Counter = ClockFrequencyHz * 60 -1 then
                            Counter <= 0;
                            State   <= StopWest;
                        end if;

                    -- Yellow in west/east direction
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= NorthNext;
                        end if;

                end case;

            end if;
        end if;
    end process;

end architecture;

La forme d'onde après avoir saisi le run 5 min commande dans la console ModelSim :

Analyse

Nous avons déclaré un type énuméré avec les huit états différents de nos feux de circulation. Ensuite, nous avons déclaré un state signal de ce nouveau type que nous avons créé. Cela signifie que le signal ne peut avoir qu'une seule des huit valeurs d'état nommées, et aucune autre valeur.

Le FSM a été implémenté à l'aide d'une déclaration de cas dans un processus cadencé. A chaque front montant de l'horloge, le processus se réveille, et le state signal est évalué. Le code dans exactement l'un des when choix (branches) est autorisé à s'exécuter, en fonction de l'état actuel.

Dans notre code, c'est la valeur du Counter signal qui déclenche les changements d'état. Lorsque le Compteur atteint une valeur prédéfinie, représentant 5 secondes ou 1 minute, un nouvel encodage d'état est attribué au State signal. Ensuite, lorsque le processus se réveille sur le prochain front montant de l'horloge après la mise à jour de la valeur d'état, le FSM est dans un état différent.

Notez que nous n'attribuons pas '0' à n'importe quel signal dans l'un des when les choix. C'est parce que nous avons donné à tous les signaux de sortie une valeur par défaut de '0' au début du processus. Vous vous souvenez peut-être d'un tutoriel précédent que c'est la dernière valeur affectée à un signal qui devient effective. Les affectations de signal ne deviennent effectives qu'après la fin du processus. Si nous attribuons '0' au signal au début du processus, puis '1' dans l'un des when choix, le signal prendra la valeur '1' .

Nous pouvons voir sur la forme d'onde que le State le signal passe par les huit états. Les états verts fixes durent une minute, l'image de la forme d'onde a donc été coupée dans le North et West états.

À emporter

Aller au tutoriel suivant »


VHDL

  1. Machine à états finis
  2. Comment garantir les meilleures performances de la machine d'état Qt
  3. Comment créer une liste de chaînes en VHDL
  4. Comment créer un banc d'essai piloté par Tcl pour un module de verrouillage de code VHDL
  5. Comment arrêter la simulation dans un testbench VHDL
  6. Comment créer un contrôleur PWM en VHDL
  7. Comment créer un banc d'essai d'auto-vérification
  8. Comment créer une liste chaînée en VHDL
  9. Comment la machine laser CNC OMNI crée des cadeaux de Noël personnalisés ?