【问题标题】:VHDL: button debounce inside a Mealy State MachineVHDL:Mealy 状态机内的按钮去抖动
【发布时间】:2015-12-11 22:33:39
【问题描述】:

您好,我正在尝试使用 VHDL 实现一个粉状机器,但我需要消除按钮按下的抖动。我的问题是我不确定我应该在哪里实现去抖动。我现在的工作是这样的:

process(clk)
begin
    if(clk' event and clk = '1') then
        if rst = '1' then
            curr_state <= state0;
        else
            curr_state <= next_state;
        end if;
    end if;
end process;

process(curr_state, op1,op0,rst)  --here op1,op0 and rst are all physical buttons and I need to debounce op1 and op0
begin
    if rst = '1' then
        ...some implementation
    else
        ...implement the debounce logic first
        ...process some input
        case curr_state is
            when state0=>...implementation
            ...similar stuff
        end case; 
end process;

我不确定我的做法是否正确。在第二个过程中,我应该像这样放置第一个处理,还是应该在 state0 阻塞时将它放在里面?另外,由于去抖动的处理需要计数,我是否像这样把它放在 case 块之外?谢谢!

【问题讨论】:

    标签: vhdl fsm debouncing


    【解决方案1】:

    我会使用完全独立的代码块来消除任何按钮信号的抖动,让您的状态机进程只关注状态机,而不必担心其他任何事情。

    您可以使用这样的过程来消除输入的抖动。您当然可以在此示例中为信号交换变量(使用相关的赋值运算符替换)。

    process (clk)
      constant DEBOUNCE_CLK_PERIODS : integer := 256;  -- Or whatever provides enough debouncing
      variable next_button_state : std_logic := '0';  -- Or whatever your 'unpressed' state is
      variable debounce_count : integer range 0 to DEBOUNCE_CLK_PERIODS-1 := 0;
    begin
      if (rising_edge(clk)) then
        if (bouncy_button_in /= next_button_state) then
          next_button_state := bouncy_button_in;
          debounce_count := 0;
        else
          if (debounce_count /= DEBOUNCE_CLK_PERIODS-1) then
            debounce_count := debounce_count + 1;
          else
            debounced_button_out <= next_button_state;
          end if;
        end if;
      end if;
    end process;
    

    另一种选择是以慢速采样bouncy_button_in

    process (clk)
      constant DEBOUNCE_CLK_DIVIDER : integer := 256;
      variable debounce_count : integer range 0 to DEBOUNCE_CLK_DIVIDER-1 := 0;
    begin
      if (rising_edge(clk)) then
        if (debounce_count /= DEBOUNCE_CLK_DIVIDER-1) then
          debounce_count := debounce_count + 1;
        else
          debounce_count := 0;
          debounced_button_out <= bouncy_button_in;
        end if;
      end if;
    end process;
    

    第一种方法的优点是它会拒绝输入中的毛刺。无论哪种情况,您都可以在状态机中使用debounced_button_out(或任何您想调用的名称,也许是rst),然后其代码仅包含核心状态机功能。

    如果您想要更多的去抖动,您可以使用另一个计数器为上述进程创建一个启用信号,以有效地分频时钟频率。这可能比将除法常数设置为非常高的数字要好,因为如果计数器超出特定大小,您可能无法满足计时要求。

    您甚至可以在一个单独的文件中创建一个去抖动实体,它可以为每个按钮实例化。在上述过程中,它可以有一个常量的泛型。

    还有硬件去抖动,但我想这超出了这个问题的范围。

    【讨论】:

    • 不确定所有合成器都能正确处理您的第一个进程。我建议将button_state 转换为信号并将最后一个信号分配移出进程。
    • 感谢@RenaudPacalet,我想我已经编辑了答案,因为你写了这个,但如果没有让我知道。
    【解决方案2】:

    在第二个过程中,我应该像这样放置第一个处理,还是 state0阻塞时我应该把它放在里面吗?

    只放在State0块中

    另外,作为处理 debounce 需要计数,我是否将它放在 case 块之外 这?

    计数需要在时钟过程中完成。由于您正在执行两个进程状态机,因此您不能在 case 块中执行此操作。无论如何,我通常将这些资源放在一个单独的时钟进程中。

    对于州,您需要:IS_0、TO_1、IS_1、TO_0。
    TO_1 和 TO_0 是您的过渡状态。当我看到 1 持续 16 毫秒时,我从 TO_1 转换到 IS_1。当我看到 0 持续 16 毫秒时,我从 TO_0 转换到 IS_0。当您处于 TO_1 或 TO_0 状态时运行您的计数器。当您处于 IS_1 或 IS_0 状态时清除您的计数器。

    这应该让你明白。

    【讨论】:

      猜你喜欢
      • 2017-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-16
      • 2011-12-24
      相关资源
      最近更新 更多