反弹按钮按下导致连续的状态转换

时间:2017-02-27 18:31:52

标签: vhdl fpga

我正在编程一个使用按钮作为输入信号的FPGA。它有一个有限状态机,有11个状态,使用特定按钮按下从状态转换到状态。

例如,在我的设计中,状态s0使用按钮按下进入状态s1。这是从状态s1到s2以及从状态s2到s3的相同转换情况。这个状态转换系统使用case语句在我的VHDL代码中实现。

LED在每个状态下亮起,以跟踪电路板当前所处的状态。

我的问题是,当my_btnL =' 1'在状态s0中,董事会显示它已移至状态s3。

我认为发生的事实是它确实会进入状态s1和s2,但状态s0中的同一按钮按下也会在状态s1和s2中被读取。这种情况发生得如此之快,以至于电路板没有足够的时间来显示状态s1和s2的LED指示。它在状态s3处停止,因为状态s3使用不同的按钮移动到状态s4。

所以我的问题是如何使按钮按下信号有一个上升沿和一个下降沿,这样一个按钮只能在一个状态下读取,而不是跟随它的那个?

按下按钮信号被反弹,但这只会使信号成为均匀的方波。

在下面的代码中,btnC,btnL,btnR,...是按钮:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;


entity digital_lock is
    Port ( 
            my_btnC, clk, my_btnU, my_btnR, my_btnL, my_btnD: in std_logic;
            my_sw: in std_logic_vector(3 downto 0);
            hex0, hex1, hex2, hex3: out std_logic_vector (3 downto 0);
            my_led: out std_logic_vector(15 downto 0)
            );
end digital_lock;

architecture Behavioral of digital_lock is
type state IS (s0, s1, s2, s3, s4 ,s5  ,s6, s7, s8, s9, s10,s11);

signal my_state: state;
signal my_status: unsigned(1 downto 0);
signal num1, num2, num3, key1, key2, key3: std_logic_vector(3 downto 0);
signal number, final_key: std_logic_vector(11 downto 0);

begin

    FSM: process(clk, my_btnC)
    begin
    if(my_btnC ='1') then
        my_state <= s0;
    elsif rising_edge(clk) then
        case my_state is
            when s0 =>
                my_status <= "00";
                my_led <= "1100000000000000";
                hex3 <= "0000";
                hex2 <= "0000";
                hex1 <= "0000";
                hex0 <= "0000";
                if(my_btnL ='1') then
                    my_state <= s1;
                else
                    my_state <= s0;
                end if;
             when s1 =>
                key1 <= my_sw;
                hex0 <= key1;
                my_led <= "0000000000000001";
                if(my_btnL='1') then
                    my_state <= s2;
                else
                    my_state <= s1;
                end if;
            when s2 =>
                key2 <= my_sw;
                hex0 <= key2;
                my_led <= "0000000000000010";
                if(my_btnL ='1') then
                    my_state <= s3;
                else
                    my_state <= s2;
                end if;
            when s3 =>
                key3 <= my_sw;
                hex0 <= key3;
                my_led <= "0000000000000011";
                if(my_btnR= '1') then
                    my_state <= s4;
                else 
                    my_state <= s3;
                end if;
            when s4 =>
                final_key(11 downto 8) <= key1;
                final_key(7 downto 4) <= key2;
                final_key(3 downto 0) <= key3;
                my_led <= "0000000000000100";
                if(my_btnU ='1') then
                    my_state <= s5;
                else
                    my_state <= s4;
                end if;
            when s5 =>
                num1 <= my_sw;
                hex0 <= num1;
                my_led <= "0000000000000101";
                if(my_btnD ='1') then
                    my_state <= s0;
                elsif (my_btnL ='1') then
                    my_state <= s6;
                else
                    my_state <= s5;
                end if;
            when s6 =>
                num2 <= my_sw;
                hex0 <= num2;
                my_led <= "0000000000000110";
                if(my_btnD ='1') then
                    my_state <= s0;
                elsif(my_btnL ='1') then
                    my_state <= s7;
                else
                    my_state <= s6;
                end if;
            when s7 =>
                num3 <= my_sw;
                hex0 <= num3;
                my_led <= "0000000000000111";
                if(my_btnD ='1') then
                    my_state <= s0;
                elsif(my_btnR = '1') then
                    my_state <= s8;
                else 
                    my_state <= s7;
                end if;
            when s8 =>
                number(11 downto 8) <= num1;
                number(7 downto 4) <= num2;
                number(3 downto 0) <= num3;
                my_led <= "0000000000001000";
                if(number = final_key) then
                    my_state <= s9;
                else
                    my_state <= s10;
                end if; 
            when s9 =>
                my_led <= "1111111111111111";
                if(my_btnD = '1') then
                    my_state <= s0;
                else
                    my_state <= s9;
                end if;
            when s10 =>
                my_status <= my_status + 1;
                if(my_status >= 3) then
                    my_state <= s11;
                elsif(my_status < 3) then
                    my_state <= s5;
                end if;
            when s11 =>
                my_led <= "0000000000000000";
                hex0 <= "1111";
                hex1 <= "1111";
                hex2 <= "1111";
                hex3 <= "1111";
                my_state <= s11;
        end case;
        end if;
    end process;
end Behavioral;

1 个答案:

答案 0 :(得分:2)

用于与状态机在同一时钟域中的反弹信号的边沿检测器可以通过具有信号输入的触发器和用于检测输入上的优选状态(在输入边缘之后)的门来完成。触发器处于另一种状态。

signal my_btnL_event: std_logic;
signal my_btnLd:      std_logic;  -- architecture declarative items

process (clk)
begin
    if rising_edge(clk) then
        my_btnLd <= my_btnL;  
    end if;

my_btnL_event <= my_btnL and not my_btnLd;

您可以使用my_btnL_event代替my_btnL来进行状态转换。

注意这需要my_btnL在再次有效之前进行invaid,假设有足够的去抖动。

my_btnL_event赋值可以用多种方式表示,例如if语句或条件信号赋值。