Zustandsmaschine mit Case erhält unerwartetes Ergebnis

Ich versuche, eine sehr einfache Zustandsmaschine zu schreiben, die ein Kombinationsschloss implementiert.

Der Code lautet: Switch1 -> Switch2 -> Switch3 -> Switch4

Ich erkenne, dass es Schalter 7, 6, 5, 4 entsprechend im Code ist.

Wenn dies nicht in dieser Reihenfolge erfolgt, wird der Fehlerstatus (falsch) angezeigt.

stateDas Problem, das ich habe, ist, dass es sich zwar state_start(wie ich es auf den LEDs sehe) nicht ändert state_1_rightund stattdessen nur die error_state. Ich weiß, dass es in diese if-Anweisung geht, weil ich das elsein geändert habe state <= "00001010";und es zeigt das an.

Was mache ich falsch? Ich sehe keinen Fehler in meiner Logik (es sei denn, es gibt einen seltsamen Schaltersprung).

Hier ist der Code, den ich jetzt versuche:

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;

Vielen Dank an Brian Drummond für das Finden des Fehlers in meiner Logik und den Vorschlag einer Uhr. Ich musste den if-Anweisungen etwas zusätzliche Logik hinzufügen, da die Uhr den case-Block schnell durchläuft und der Zustand gleich bleiben konnte.

Hier ist der aktualisierte Code, der das Problem behebt:

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;
Wie hast du die LEDs angeschlossen? Long Shot, aber vielleicht ist alles invertiert, also z. B. wenn die LEDs 10000000 sagen, ist es tatsächlich 01111111
@geometrische LEDs sind in Ordnung und selbst wenn es rückwärts war, beträgt der Fehler 4 Lichter hintereinander, sodass Sie es nicht wirklich durcheinander bringen können.

Antworten (2)

Die andere Antwort ist richtig, dass eine Uhr benötigt wird.

Ignorieren Sie jedoch das von ihm verlinkte Zwei-Prozess-Beispiel: Suchen Sie an den üblichen Stellen nach "VHDL Single Process State Machine", um eine bessere Lösung zu finden.

http://www.openhdl.com/vhdl/664-vhdl-tip-single-process-vhdl-state-machine-design.html für einen.

Ich habe eine Uhr hinzugefügt und die Anweisung "rising_edge" um meinen Fall gelegt, aber es gibt keine Änderung.
würden Sie nicht Switches in einer eigenen Prozessanweisung benötigen, sonst würde es direkt in den Fehlerzustand takten.
@MLM: (1) und ist "clk" das einzige, was in der Sensitivitätsliste steht? es sollte sein. (2) Fehler in Ihrer Logik: Nachdem Sie mit dem richtigen Schaltermuster zu Zustand 1 gelangt sind, müssen Sie dort bleiben, bis sich die Schalter ändern. Angesichts dieses Hinweises ist es eine einfache Änderung des "if" -Ausdrucks. Gleiches gilt für andere Bundesländer...
@BrianDrummond Ich habe es nur mit dem clk in der Empfindlichkeitsliste versucht und es gibt keine Änderung. Sie bleiben auf state_1, bis Sie es vermasseln oder zu state_2 wechseln. Obwohl ich nicht einmal zu state_1 gelangen kann. Ich bin mir nicht einmal sicher, ob ich eine Uhr brauche ...
Simulieren Sie es. Der beste Weg, um zu sehen, was es wirklich tut ... Es gibt mehrere kostenlose Simulatoren, einschließlich ghdl.
@BrianDrummond Gerade simuliert und es ging sogar mit der Sync-Uhr direkt zu einem Fehler. Glaubst du, es könnte sein, weil der Zustand, von dem es abhängt, in der "if-Anweisung" steht und dann geändert wird, wenn die "if-Anweisung" wahr ist? Könnte eine seltsame Übersetzung von Code zu Schema sein.
Kannst du nochmal nachschauen? Wenn es getaktet ist, wenn Sie den Schalter auf 1000 setzen, würde ich erwarten, dass es EINEN Zyklus im richtigen Zustand verbringt, bevor es zu einem Fehler kommt. Das verlangt zumindest der Code.
@BrianDrummond Okay, es wechselt für einen Taktzyklus in den richtigen Zustand "01000000", aber warum bleibt es nicht dort?
Weil der Code in dieser "if"-Anweisung sagt, dass es nicht dort bleiben soll.
@BrianDrummond ahhhhhhh, du hast es in einem früheren Kommentar erwähnt, aber es machte für mich damals keinen Sinn und zumal ich nicht die Uhr hatte, die das Gehäuse so stark getaktet hatte, anstatt nur die Schalter in der Empfindlichkeitsliste. Ich werde den aktualisierten Code in Kürze posten.
Es ist in Ordnung. Ein früherer Kommentar würde ohne die Möglichkeit, ihn in der Simulation zu sehen, nicht viel Sinn machen. Ich denke, Sie haben auf dem Weg zum Auffinden des Problems viel mehr von dem Prozess gesehen, was nützlich sein wird ... Wenn Sie sich andere SMs ansehen, werden Sie feststellen, dass Ihres im Grunde auf den Kopf gestellt ist - herkömmlicherweise wird der Zustand getestet die äußere Fallanweisung - aber es ist ein vollkommen gültiger Code für all das und zeigt Originalität. Es könnte zu mehr Logiknutzung (LUTs, FFs) in der Synthese führen, aber Synthesewerkzeuge sind ziemlich gut in der Optimierung ... Ich habe jedoch immer noch nicht über ihre Immunität gegen SW-Bounce nachgedacht!

Möglicherweise benötigen Sie eine Uhr, um die Statusänderungen zu synchronisieren.

Könnte Switch Bounce sein, aber wenn der erste springt, scheint es, als würde er zu start_state zurückkehren, nicht zu state_error, denke ich. Verwenden Sie physische Schalter?

Ich drucke Beispielcode von hier http://esd.cs.ucr.edu/labs/tutorial/fsm.vhd nach, zum Beispiel für die Synchronisierung mit der Uhr für die Statusänderungen.

-----------------------------------------------------
-- 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;

-----------------------------------------------------
Ich verwende physische Schalter auf der Platine. Ich werde mich mit dem Hinzufügen einer Synchronisierungsuhr befassen, bin mir aber nicht sicher, warum Sie dies in dieser Situation tun müssten.
Ich habe eine Uhr hinzugefügt und die Anweisung "rising_edge" um meinen Fall gelegt, aber es gibt keine Änderung.