Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> VHDL

Cómo crear una máquina de estados finitos en VHDL

Una máquina de estados finitos (FSM) es un mecanismo cuya salida depende no solo del estado actual de la entrada, sino también de valores pasados ​​de entrada y salida.

Siempre que necesite crear algún tipo de algoritmo dependiente del tiempo en VHDL, o si se enfrenta al problema de implementar un programa de computadora en un FPGA, generalmente se puede resolver usando un FSM.

Las máquinas de estado en VHDL son procesos cronometrados cuyas salidas están controladas por el valor de una señal de estado. La señal de estado sirve como memoria interna de lo que sucedió en la iteración anterior.

Esta publicación de blog es parte de la serie Tutoriales básicos de VHDL.

Considere los estados de los semáforos en esta intersección:

Los semáforos tienen un número finito de estados, a los que les hemos dado nombres identificables. Nuestra máquina de estado de ejemplo no tiene entradas de control, la salida es el estado de las luces en las direcciones norte/sur y oeste/este. Es el tiempo transcurrido y el estado anterior de las salidas lo que hace avanzar esta máquina de estados.

Podemos representar estados en VHDL usando un tipo enumerado . Estos son tipos de datos como signed o unsigned , pero en lugar de números enteros, podemos proporcionar una lista personalizada de valores posibles. De hecho, si echa un vistazo al paquete std_logic_1164, encontrará que el std_ulogic type no es más que un tipo enumerado con los valores 'U' , 'X' , '0' , '1' , 'Z' , 'W' , 'L' , 'H' y '-' enumerados como valores de enumeración.

Una vez que tengamos nuestro tipo enumerado, podemos declarar una señal del nuevo tipo que se puede usar para realizar un seguimiento del estado actual del FSM.

La sintaxis para declarar una señal con un tipo enumerado en VHDL es:
type <type_name> is (<state_name1>, <state_name2>, ...);
signal <signal_name> : <type_name>;

Usando la señal de estado, la máquina de estados finitos se puede implementar en un proceso con una declaración Case. La sentencia Case contiene una sentencia When para cada uno de los estados posibles, lo que hace que el programa tome caminos diferentes para cada estado. La declaración When también puede contener código que debe ejecutarse mientras se encuentra en ese estado en particular. Por lo general, el estado cambiará cuando se cumpla una condición predefinida.

Esta es una plantilla para una máquina de estado de un proceso:
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;

Nota:
Hay varias formas de crear un FSM en VHDL. Lea acerca de los diferentes estilos aquí:
Máquina de estado de un proceso, dos procesos y tres procesos

Ejercicio

En este videotutorial aprenderemos a crear una máquina de estados finitos en VHDL:

El código final para la máquina de estado 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;

El código final para el módulo de la máquina de estado :

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 forma de onda después de que ingresamos el run 5 min comando en la consola de ModelSim:

Análisis

Declaramos un tipo enumerado con los ocho estados diferentes de nuestros semáforos. Luego, declaramos un state señal de este nuevo tipo que creamos. Esto significa que la señal solo puede tener uno de los ocho valores de estado nombrados y ningún otro valor.

El FSM se implementó utilizando una declaración de caso dentro de un proceso cronometrado. En cada flanco ascendente del reloj, el proceso se despierta y el state se evalúa la señal. El código dentro de exactamente uno de los when Las opciones (ramas) pueden ejecutarse, dependiendo del estado actual.

En nuestro código, es el valor del Counter Señal que desencadena cambios de estado. Cuando el Contador alcanza un valor predefinido, que representa 5 segundos o 1 minuto, se asigna una nueva codificación de estado al State señal. Luego, cuando el proceso se despierta en el siguiente flanco ascendente del reloj después de que se haya actualizado el valor del estado, el FSM se encuentra en un estado diferente.

Tenga en cuenta que no estamos asignando '0' a cualquier señal en cualquiera de los when opciones Esto se debe a que le hemos dado a todas las señales de salida un valor predeterminado de '0' al inicio del proceso. Puede recordar de un tutorial anterior que es el último valor que se asigna a una señal que se vuelve efectivo. Las asignaciones de señales se hacen efectivas solo después de que finaliza el proceso. Si asignamos '0' a la señal al comienzo del proceso, y luego '1' en uno de los when opciones, la señal obtendrá el valor '1' .

Podemos ver en la forma de onda que el State la señal recorre los ocho estados. Los estados verdes fijos duran un minuto, por lo que la imagen de la forma de onda se ha cortado en el North y West estados.

Para llevar

Ir al siguiente tutorial »


VHDL

  1. Máquina de estado finito
  2. Cómo garantizar el mejor rendimiento de la máquina de estado Qt
  3. Cómo crear una lista de cadenas en VHDL
  4. Cómo crear un banco de pruebas controlado por Tcl para un módulo de bloqueo de código VHDL
  5. Cómo detener la simulación en un banco de pruebas VHDL
  6. Cómo crear un controlador PWM en VHDL
  7. Cómo generar números aleatorios en VHDL
  8. Cómo crear un FIFO de búfer de anillo en VHDL
  9. Cómo crear un banco de pruebas de autocomprobación
  10. Cómo crear una lista enlazada en VHDL
  11. ¿Cómo la máquina láser CNC OMNI crea regalos de Navidad personalizados?