You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VHDL实现引擎启动控制FSM:解决单次输入多时钟识别问题

VHDL FSM按键单次输入识别解决方案

问题背景

需实现一个VHDL有限状态机(FSM)作为引擎启动控制器:

  • 当按键按A-B-B顺序输入时,输出ut(1) = 1(引擎启动)
  • 输入错误顺序时,输出ut(0) = 1,需复位后才能重新输入
  • 当前问题:单次按键会被多个时钟周期识别为多次输入,导致状态跳转异常

问题核心原因

按键按下/释放时的电平状态会持续多个时钟周期,当前FSM直接检测电平状态,只要时钟沿到来时按键处于按下状态就会触发状态跳转,导致一次按键被多次识别。若为实际硬件场景,按键还会存在10~20ms的机械抖动,进一步加剧该问题。

解决方案

通过边沿检测确保单次按键动作仅被识别一次,若适配实际硬件,可在边沿检测前增加按键消抖逻辑。以下是带边沿检测的实现方案:

修改后的FSM代码

entity engine is
    Port ( ab : in  STD_LOGIC_VECTOR(1 downto 0);
           clock : in  STD_LOGIC;
           ut : out  STD_LOGIC_VECTOR(1 downto 0);
           reset : in  STD_LOGIC);
end engine;

architecture Behavioral of engine is
   type state_type is (S0, S1, S2, S3, S4);
   signal state, next_state : state_type;
   -- 寄存上一周期按键状态,用于边沿检测
   signal ab_prev : STD_LOGIC_VECTOR(1 downto 0);
   -- 有效按键触发信号:仅在按键从释放变为按下时置1
   signal a_press, b_press : STD_LOGIC;
   
begin
    -- 边沿检测与状态更新进程
    process(clock, reset)
    begin
      if reset = '1' then
         next_state <= S0;
         ab_prev <= "00";
         a_press <= '0';
         b_press <= '0';
      elsif rising_edge(clock) then
         -- 更新上一周期按键状态
         ab_prev <= ab;
         -- 检测A按键上升沿(从释放到按下)
         a_press <= '1' when (ab = "10" and ab_prev /= "10") else '0';
         -- 检测B按键上升沿(从释放到按下)
         b_press <= '1' when (ab = "01" and ab_prev /= "01") else '0';
         
         state <= next_state;   
         case state is
            when S0 =>
               if a_press = '1' then -- 仅在A按下边沿触发跳转
                 next_state <= S1;    
               end if;
            when S1 =>             
               if b_press = '1' then -- 仅在B按下边沿触发跳转
                  next_state <= S2;
               end if;
            when S2 =>              
               if b_press = '1' then 
                  next_state <= S3; 
               elsif a_press = '1' then 
                  next_state <= S4;
               end if;
            when S3 =>
               next_state <= S3;               
            when S4 =>
               next_state <= S4;                      
         end case;
      end if;
   end process;
   
   -- 输出逻辑进程
   process(state)
   begin     
         case state is
            when S0 => ut <= "00";
            when S1 => ut <= "00";
            when S2 => ut <= "00";
            when S3 => ut <= "10"; -- 正确顺序,引擎启动
            when S4 => ut <= "01"; -- 错误顺序
         end case;   
   end process;
end Behavioral;

调整后的测试平台代码

ENTITY egninetest IS
END egninetest;
 
ARCHITECTURE behavior OF egninetest IS 
 
    COMPONENT engine
    PORT(
         ab : IN  std_logic_vector(1 downto 0);
         clock : IN  std_logic;
         ut : OUT  std_logic_vector(1 downto 0);
         reset : IN  std_logic
        );
    END COMPONENT;
    
   --Inputs
   signal ab : std_logic_vector(1 downto 0) := (others => '0');
   signal clock : std_logic := '0';
   signal reset : std_logic := '0';

   --Outputs
   signal ut : std_logic_vector(1 downto 0);

   -- Clock period definitions
   constant clock_period : time := 15 ns;
 
BEGIN
 
   uut: engine PORT MAP (
          ab => ab,
          clock => clock,
          ut => ut,
          reset => reset
        );

   -- Clock process definitions
   clock_process :process
   begin
        clock <= '0';
        wait for clock_period;
        clock <= '1';
        wait for clock_period;
   end process;
 

   -- 模拟按键按下后释放,触发边沿检测
   stim_proc: process
   begin             
      reset <= '1';
      wait for 40 ns;   
      reset <= '0';
      
      -- 测试错误输入:按下B后释放
      ab <= "01";  
      wait for 30 ns;
      ab <= "00";
      wait for 55 ns;     
      
      reset <= '1'; -- 复位
      wait for 40 ns;
      reset <= '0';
 
      -- 测试正确输入序列A-B-B
      -- 按下A后释放
      ab <= "10";
      wait for 30 ns;
      ab <= "00";
      wait for 40 ns;
      
      -- 按下B后释放
      ab <= "01";
      wait for 30 ns;
      ab <= "00";
      wait for 40 ns;
      
      -- 按下B后释放
      ab <= "01";
      wait for 30 ns;
      ab <= "00";

      wait;
   end process;

END;

关键修改说明

  1. 添加ab_prev信号寄存上一周期按键状态,用于判断边沿变化
  2. 定义a_press和b_press脉冲信号,仅在按键从释放变为按下时置1,确保单次按键仅产生一次有效触发
  3. FSM状态跳转条件改为检测脉冲信号,避免持续电平导致多次状态跳转

内容的提问来源于stack exchange,提问作者flacko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 08:07:34