La máquina de estados usando el caso obtiene un resultado inesperado

1

Estoy intentando escribir una máquina de estado muy simple que implementa un bloqueo de combinación.

El código es: Switch1 - > Switch2 - > Switch3 - > Switch4

Me doy cuenta de que es el Switch 7, 6, 5, 4 en consecuencia en el código.

Si no se realiza en ese orden, da el estado de error (incorrecto).

El problema que tengo es que, a pesar de que state es state_start (como lo veo en los LED), no cambiará a state_1_right y en su lugar solo bombeará error_state . Sé que entra en esa declaración if porque cambié el else a state <= "00001010"; y lo muestra.

¿Qué estoy haciendo mal? No veo ningún error en mi lógica (a menos que haya algún rebote extraño del interruptor).

Aquí está el código que estoy intentando ahora:

entity CombinationLockFSM is
    Port(
        Switches: in std_logic_vector(7 downto 0);
        LEDs: out std_logic_vector(7 downto 0)
    );
end CombinationLockFSM;

architecture Behavioral of CombinationLockFSM is
    constant state_start: std_logic_vector(7 downto 0) := "10000000";
    constant state_1_right: std_logic_vector(7 downto 0) := "01000000";
    constant state_2_right: std_logic_vector(7 downto 0) := "00100000";
    constant state_3_right: std_logic_vector(7 downto 0) := "00010000";
    constant state_error: std_logic_vector(7 downto 0) := "00001111";

    signal state: std_logic_vector(7 downto 0) := (others => '0');
begin

    LEDs <= state;

    process(Switches)
    begin
        case Switches is
            when "00000000" => 
                state <= state_start;
            when "10000000" => 
                if state = state_start then
                    state <= state_1_right;
                else
                    state <= state_error;
                end if;
            when "11000000" => 
                if state = state_1_right then
                    state <= state_2_right;
                else
                    state <= state_error;
                end if;
            when "11100000" => 
                if state = state_2_right then
                    state <= state_3_right;
                else
                    state <= state_error;
                end if;
            when "11110000" => 
                if state = state_3_right then
                    state <= "11110000";
                else
                    state <= state_error;
                end if;


            when others =>
                state <= state_error;
        end case;

    end process;

end Behavioral;

Gracias a Brian Drummond por encontrar el error en mi lógica y sugerir un reloj. Tuve que agregar un poco de lógica adicional en las sentencias if, ya que el reloj recorre rápidamente el bloque de casos y el estado podría seguir igual.

Aquí está el código actualizado que resuelve el problema:

entity CombinationLockFSM is
    Port(
        mclk: in std_logic;
        sw: in std_logic_vector(7 downto 0);
        Led: out std_logic_vector(7 downto 0)
    );
end CombinationLockFSM;

architecture Behavioral of CombinationLockFSM is
    constant state_start: std_logic_vector(7 downto 0) := "10000000";
    constant state_1_right: std_logic_vector(7 downto 0) := "01000000";
    constant state_2_right: std_logic_vector(7 downto 0) := "00100000";
    constant state_3_right: std_logic_vector(7 downto 0) := "00010000";
    constant state_4_right: std_logic_vector(7 downto 0) := "11110000";
    constant state_error: std_logic_vector(7 downto 0) := "00001111";

    signal state: std_logic_vector(7 downto 0) := (others => '0');
begin

    Led <= state;

    process(mclk)
    begin
        if rising_edge(mclk) then
            case sw is
                when "00000000" => 
                    state <= state_start;
                when "10000000" => 
                    if state = state_start or state = state_1_right then
                        state <= state_1_right;
                    else
                        state <= state_error;
                    end if;
                when "11000000" => 
                    if state = state_1_right or state = state_2_right then
                        state <= state_2_right;
                    else
                        state <= state_error;
                    end if;
                when "11100000" => 
                    if state = state_2_right or state = state_3_right then
                        state <= state_3_right;
                    else
                        state <= state_error;
                    end if;
                when "11110000" => 
                    if state = state_3_right or state = state_4_right then
                        state <= state_4_right;
                    else
                        state <= state_error;
                    end if;


                when others =>
                    state <= state_error;
            end case;
        end if;

    end process;

end Behavioral;
    
pregunta MLM

2 respuestas

3

La otra respuesta es correcta sobre la necesidad de un reloj.

Pero ignore el ejemplo de dos procesos al que se vinculó: buscar en los lugares habituales para "Máquina de estado de proceso único VHDL" para una mejor solución.

enlace por una.

    
respondido por el Brian Drummond
0

Quizás necesite un reloj para sincronizar los cambios de estado.

Podría ser un cambio de interruptor, pero si el primero fue un rebote parece que volvería a start_state no a state_error, creo. ¿Estás utilizando interruptores físicos?

Reimprimo el código de ejemplo desde aquí enlace , por ejemplo, de sincronización con el reloj para los cambios de estado .

-----------------------------------------------------
-- VHDL FSM (Finite State Machine) modeling
-- (ESD book Figure 2.7)
-- by Weijun Zhang, 04/2001
--
-- FSM model consists of two concurrent processes
-- state_reg and comb_logic
-- we use case statement to describe the state 
-- transistion. All the inputs and signals are
-- put into the process sensitive list.  
-----------------------------------------------------

library ieee ;
use ieee.std_logic_1164.all;

-----------------------------------------------------

entity seq_design is
port(   a:      in std_logic;
    clock:      in std_logic;
    reset:      in std_logic;
    x:      out std_logic
);
end seq_design;

-----------------------------------------------------

architecture FSM of seq_design is

    -- define the states of FSM model

    type state_type is (S0, S1, S2, S3);
    signal next_state, current_state: state_type;

begin

    -- cocurrent process#1: state registers
    state_reg: process(clock, reset)
    begin

    if (reset='1') then
            current_state <= S0;
    elsif (clock'event and clock='1') then
        current_state <= next_state;
    end if;

    end process;                          

    -- cocurrent process#2: combinational logic
    comb_logic: process(current_state, a)
    begin

    -- use case statement to show the 
    -- state transistion

    case current_state is

        when S0 =>  x <= '0';
            if a='0' then
                next_state <= S0;
            elsif a ='1' then
                next_state <= S1;
            end if;

        when S1 =>  x <= '0';
            if a='0' then 
                next_state <= S1;
            elsif a='1' then 
                next_state <= S2;
            end if;

        when S2 =>  x <= '0';
            if a='0' then
                next_state <= S2;
            elsif a='1' then
                next_state <= S3;
            end if;

        when S3 =>  x <= '1';
            if a='0' then 
                next_state <= S3;
            elsif a='1' then 
                next_state <= S0;
            end if;

        when others =>
            x <= '0';
            next_state <= S0;

    end case;

    end process;

end FSM;

-----------------------------------------------------
    
respondido por el geometrikal

Lea otras preguntas en las etiquetas