Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> VHDL

Como criar uma máquina de estado finito em VHDL


Uma máquina de estado finito (FSM) é um mecanismo cuja saída depende não apenas do estado atual da entrada, mas também dos valores passados ​​de entrada e saída.

Sempre que você precisar criar algum tipo de algoritmo dependente do tempo em VHDL, ou se você se deparar com o problema de implementar um programa de computador em um FPGA, ele geralmente pode ser resolvido usando um FSM.

Máquinas de estado em VHDL são processos cronometrados cujas saídas são controladas pelo valor de um sinal de estado. O sinal de estado serve como uma memória interna do que aconteceu na iteração anterior.

Esta postagem do blog faz parte da série de tutoriais básicos de VHDL.

Considere os estados dos semáforos neste cruzamento:


Os semáforos têm um número finito de estados, aos quais demos nomes identificáveis. Nossa máquina de estado de exemplo não tem entradas de controle, a saída é o estado das luzes nas direções norte/sul e oeste/leste. É o tempo decorrido e o estado anterior das saídas que avança esta máquina de estados.

Podemos representar estados em VHDL usando um tipo enumerado . Estes são tipos de dados como signed ou unsigned , mas em vez de números inteiros, podemos fornecer uma lista personalizada de valores possíveis. Na verdade, se você der uma olhada no pacote std_logic_1164, verá que o std_ulogic type nada mais é do que um tipo enumerado com os valores 'U' , 'X' , '0' , '1' , 'Z' , 'W' , 'L' , 'H' e '-' listados como valores de enumeração.

Uma vez que tenhamos nosso tipo enumerado, podemos declarar um sinal do novo tipo que pode ser usado para acompanhar o estado atual do FSM.

A sintaxe para declarar um sinal com um tipo enumerado em VHDL é:
type <type_name> is (<state_name1>, <state_name2>, ...);
signal <signal_name> : <type_name>;


Usando o sinal de estado, a máquina de estado finito pode ser implementada em um processo com uma instrução Case. A instrução Case contém uma instrução When para cada um dos estados possíveis, fazendo com que o programa tome caminhos diferentes para cada estado. A instrução When também pode conter código que deve ser executado enquanto estiver nesse estado específico. O estado normalmente mudará quando uma condição predefinida for atendida.

Este é um modelo para máquina de estado de um processo:
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:
Existem várias maneiras de criar um FSM em VHDL. Leia sobre os diferentes estilos aqui:
Máquina de estado de um processo versus dois processos versus três processos

Exercício


Neste tutorial em vídeo vamos aprender como criar uma máquina de estado finito em VHDL:



O código final para a 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;

O código final para a máquina de estado módulo :
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;

A forma de onda após inserirmos o run 5 min comando no console ModelSim:





Análise


Declaramos um tipo enumerado com todos os oito estados diferentes de nossos semáforos. Em seguida, declaramos um state sinal deste novo tipo que criamos. Isso significa que o sinal pode ter apenas um dos oito valores de estado nomeados e nenhum outro valor.

O FSM foi implementado usando uma instrução Case dentro de um processo cronometrado. Em cada borda ascendente do relógio, o processo é ativado e o state sinal é avaliado. O código dentro de exatamente um dos when escolhas (ramificações) podem ser executadas, dependendo do estado atual.

Em nosso código, é o valor do Counter sinal que desencadeia mudanças de estado. Quando o contador atinge um valor predefinido, representando 5 segundos ou 1 minuto, uma nova codificação de estado é atribuída ao State sinal. Então, quando o processo acorda na próxima borda de subida do relógio após o valor do estado ter sido atualizado, o FSM está em um estado diferente.

Observe que não estamos atribuindo '0' a qualquer sinal em qualquer um dos when escolhas. Isso ocorre porque demos a todos os sinais de saída um valor padrão de '0' no início do processo. Você deve se lembrar de um tutorial anterior que é o último valor atribuído a um sinal que se torna efetivo. As atribuições de sinal tornam-se efetivas somente após o término do processo. Se atribuirmos '0' ao sinal no início do processo e, em seguida, '1' em um dos when escolhas, o sinal terá o valor '1' .

Podemos ver pela forma de onda que o State ciclos de sinal através dos oito estados. Os estados verdes constantes duram um minuto, portanto, a imagem da forma de onda foi cortada no North e West estados.


Retirada


Ir para o próximo tutorial »

VHDL

  1. Máquina de estado finito
  2. Como garantir o melhor desempenho da máquina de estado Qt
  3. Como criar uma lista de strings em VHDL
  4. Como criar um testbench orientado por Tcl para um módulo de bloqueio de código VHDL
  5. Como parar a simulação em um testbench VHDL
  6. Como criar um controlador PWM em VHDL
  7. Como gerar números aleatórios em VHDL
  8. Como criar um testbench de autoverificação
  9. Como criar uma lista vinculada em VHDL
  10. Como a OMNI CNC Laser Machine cria presentes de Natal personalizados?