Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

Simple State Machine not working as expected

Hi, guys!

So, I'm new here. I'm a student whose lab professor gave him the following assignment. Translated from spanish to english, it reads like this:

An electrical engine is controlled by a single button. When the button is pushed, the engine is turned on. When the button is pushed again, the engine returns to 'off' status. Syntethize the engine's control circuit in VHDL.
And then I have to program a FPGA with it, SignalTap it, and show the professor that it works as intended. The FPGA I'm using is a Cyclone III EP3C16F484C6.

Since the pushable button I use continuously sends a '1' signal when it's not pushed, and a '0' signal while it's pushed, I wrote the following VHDL code for the assignment.

ENTITY enginecontrol IS
    PORT (clk,button: IN BIT; engine: OUT BIT);
END enginecontrol;
ARCHITECTURE behavior OF enginecontrol IS
TYPE statesec IS (A,B,C,D);
SIGNAL state: statesec:=A;
BEGIN
PROCESS (clk)
    BEGIN
    IF (clk'EVENT AND clk ='1') THEN
        CASE state IS
            WHEN A => 
                IF button ='0' THEN
                    state<=B;
                ELSE
                    state<=A;
                END IF;                
            WHEN B => 
                IF button ='1' THEN 
                    state<=C;
                ELSE
                    state<=B;
                END IF;                
            WHEN C => 
                IF button ='0' THEN 
                    state<=D;
                ELSE 
                    state<=C;                
                END IF;                    
            WHEN D => 
                IF button='1' THEN 
                    state<=A;
                ELSE
                    state<=D;
                END IF;            
        END CASE;    
    END IF;
END PROCESS;
engine<=    '0' WHEN state=A ELSE 
            '1' WHEN state=B ELSE
            '1' WHEN state=C ELSE 
            '0'; 
END behavior;
Here, remember, button pushed is 0 and button released is 1. Engine 'on' is 1 and engine 'off' is 0.

This code, I believe, clearly describes a state machine with four possible states. It starts at state A, with the engine off. If the button is pushed, it goes to state B, and the engine turns on. It will remain on state B as long as the button is pushed, and when the button is released, it goes to state C, engine still on. Push the button again, and you get state D, engine off. Let it go and the cycle begins again, at state A.

This is the desired behavior! Always the same, reliable...

But the real behavior is... random! Around 70% of the time, when you release a button, it goes from state B to A, instead of C, or from state D to C, instead of A. This, of course, has undesired results on the output. Nowhere in the code I can see anything that could produce this behavior! And around 30% of the time, releasing a pushed button works as intended, and the machine goes to the correct next state. Since I won't be seeing my lab professor again until January 10th, can you guys tell me why this is happening?

Many thanks for your time and help!

6 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    According to your spec I don't need state machine just toggle a register upon push.

    Regarding you state transitions, remeber push is momentary and may suffer bouncing. you can add debouncing logic.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I assume by bouncing you mean the fact that you can push the button just for a moment, but several '0' signals are sent, instead of just one. Yes, I knew and explained that... This is why if I only used a toggle, the circuit would never work as intended. The state machine I made is my way of filtering off that bouncing, it is my 'debouncing logic'. Why doesn't it work? Could you explain to me how would you do it instead?

    Many thanks!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Or you mean that sometimes the button sends '0' signals even after being released already? Even after having sent some '1' -I'm released!- signals, a rogue '0' signal can come after that??

    If that's the case... I have no idea how to overcome it.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    There are different ways to debounce keys.

    In your case you want to detect push = '0' once only over some practical interval. For example I will run a counter for 20 msec.

     pseudocode, on the clock edge...
    if push = '0' and count = max then  -- first push detection
       push_L <= '1';
    end if;
    if push = '0' and push_L = '0' then 
       count <= 0;
    end if;
    if count < max then
        count <= count + 1;
    else
        push_L <= '0';
    end if;
    if push = '0' and push_L = '0' then
        push_T <= not push_T; -- to your engine, hopefully without smoke
    end if;
    
    you will need to test this logic as I wrote it off head.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You can also use your state machine for debouncing but add extra interval of time. This could be simpler to control:

    s0: detect push = 0, decide toggle, move to s1

    s1: stay for some time ignoring key, then move to s0
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The second solution you suggested was perfect. I added a counter to lock each state upon arrival for 100 mseconds, staying just there and ignoring all button input during this small lock interval. Now the machine works 100% as intended.

    Thanks a lot for your help! You've made an student happy!