VHDL:按钮反跳(或视情况而定,不反跳)

问题描述 投票:1回答:3

我已经阅读了其他文章,但似乎无法解决我的问题。我是VHDL的新手,所以我确定这是一个简单的修复。

简而言之,该按钮没有抖动。代码进行编译并生成位流程序。在测试台中,按下按钮即可工作,但输出LED不会改变。在板上,按一个按钮会使随机的LED点亮(我想是因为弹跳)。根据原理图,输入通过去抖动器。

任何人都可以识别问题吗?和任何其他提示和技巧总是很感激:)

谢谢!

编辑1:添加了riseing_edge(clk)。另请注意,当我按下任一按钮时,按下该按钮时,所有LED都会亮起。

Schematic

button_counter.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity button_counter is
    port( clk : in std_logic;
         btnU : in std_logic;
         btnD : in std_logic;
          led : out std_logic_vector (15 downto 0));
end button_counter;

architecture behavioral of button_counter is

    component debouncer is
        port(    clk : in std_logic;
                 btn : in std_logic;
             btn_clr : out std_logic);
    end component;

    signal btnU_clr : std_logic;
    signal btnD_clr : std_logic;

    begin

    debouncer_btnU : debouncer port map (clk => clk, btn => btnU, btn_clr => btnU_clr);
    debouncer_btnD : debouncer port map (clk => clk, btn => btnD, btn_clr => btnD_clr);

    process(clk)
        variable count : integer := 0;
        begin
        if (rising_edge(clk)) then
            if(btnU_clr = '1') then count := count + 1;
            elsif(btnD_clr = '1') then count := count - 1;
            end if;
            led <= std_logic_vector(to_unsigned(count, led'length));
        end if;
    end process;

end behavioral;

Debouncer.vhd

library IEEE;
    use IEEE.std_logic_1164.all;
    use IEEE.numeric_std.all;

entity debouncer is
    port(    clk : in std_logic;
             btn : in std_logic;
         btn_clr : out std_logic);
end debouncer;

architecture behavioural of debouncer is

    constant delay : integer := 650000; -- 6.5ms
    signal count : integer := 0;
    signal btn_tmp : std_logic := '0';

    begin

    process(clk)
    begin
        if rising_edge(clk) then
            if (btn /= btn_tmp) then
                btn_tmp <= btn;
                count <= 0;
            elsif (count = delay) then
                btn_clr <= btn_tmp;
            else
                count <= count + 1;
            end if;
        end if;
    end process;

end behavioural;

button_counter_tb.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity button_counter_tb is
end button_counter_tb;

architecture behavioral of button_counter_tb is

signal clk_tb    : std_logic;
signal btnU_tb   : std_logic;
signal btnD_tb   : std_logic;
signal led_tb    : std_logic_vector (15 downto 0);

component button_counter
port(clk    : in std_logic; 
     btnU   : in std_logic;
     btnD   : in std_logic;
     led    : out std_logic_vector (15 downto 0));
end component;

begin

UUT: button_counter port map (clk => clk_tb, btnU => btnU_tb, btnD => btnD_tb, led => led_tb);

process
begin

btnU_tb <= '0';
btnD_tb <= '0'; 

wait for 100ns;
btnU_tb <= '1';

wait for 100ns;
btnU_tb <= '0';

wait for 100ns;
btnU_tb <= '1';

wait for 100ns;
btnD_tb <= '1';

wait for 100ns;
btnU_tb <= '0';

wait for 100ns;
btnD_tb <= '0';

end process;

end behavioral;
vhdl fpga xilinx vivado debounce
3个回答
3
投票

    测试台中没有生成时钟
  1. 刺激(按钮按下)在测试台中的时间不足

  2. 去抖动器不会为单个时钟产生

  3. enable

为了简化仿真进行设计

验证,您的设计已被修改为允许使用较慢的时钟(看来您实际上是在使用100 MHz时钟)。目的是减少计算需求并显示波形存储。

前两点在测试平台中解决:library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity button_counter_tb is end entity button_counter_tb; architecture behavioral of button_counter_tb is -- NOTE: suffix _tb has been removed, it's annoying to type over and over signal clk: std_logic := '0'; -- ADDED default value '0' signal btnU: std_logic; signal btnD: std_logic; signal led: std_logic_vector (15 downto 0); component button_counter generic ( -- ADDED generic CLKP: time := 10 ns; DEBT: time := 6.5 ms -- debounce time supports different ); -- mechanical buttons/switches port ( clk: in std_logic; btnU: in std_logic; btnD: in std_logic; led: out std_logic_vector (15 downto 0) ); end component; constant CLKP: time := 12.5 us; -- ADDED just long enough to show debounce constant DEBT: time := 6.5 ms; -- ADDED begin CLOCK: -- ADDED clock process process begin wait for CLKP/2; clk <= not clk; if now > 2 sec then -- stop simulation wait; end if; end process; UUT: button_counter generic map ( -- ADDED generic map CLKP => CLKP, DEBT => DEBT ) port map ( clk => clk, btnU => btnU, btnD => btnD, led => led ); -- STIMULI: -- process -- begin -- btnU_tb <= '0'; -- btnD_tb <= '0'; -- wait for 100 ns; -- btnU_tb <= '1'; -- wait for 100 ns; -- btnU_tb <= '0'; -- wait for 100 ns; -- btnU_tb <= '1'; -- wait for 100 ns; -- btnD_tb <= '1'; -- wait for 100 ns; -- btnU_tb <= '0'; -- wait for 100 ns; -- btnD_tb <= '0'; -- wait; -- ADDED -- stops simulation -- end process; UP_BUTTON: process begin btnU <= '0'; wait for 2 ms; btnU <= '1'; -- first button press wait for 0.5 ms; btnU <= '0'; wait for 0.25 ms; btnU <= '1'; wait for 7 ms; btnU <= '0'; wait for 100 us; btnU <= '1'; wait for 20 us; btnU <= '0'; wait for 200 ms; btnU <= '1'; -- second button press wait for 20 us; btnU <= '0'; wait for 20 us; btnU <= '1'; wait for 6.6 ms; btnU <= '0'; wait for 250 ms; btnU <= '1'; -- third button press wait for 20 us; btnU <= '0'; wait for 20 us; btnU <= '1'; wait for 6.6 ms; btnU <= '0'; wait for 200 ms; btnU <= '1'; -- second button press wait for 20 us; btnU <= '0'; wait for 20 us; btnU <= '1'; wait for 6.6 ms; btnU <= '0'; wait for 50 us; btnU <= '1'; wait for 1 ms; btnU <= '0'; wait; end process; DOWN_BUTTON: process begin btnD <= '0'; wait for 800 ms; btnD <= '1'; -- first button press wait for 0.5 ms; btnD <= '0'; wait for 0.25 ms; btnD <= '1'; wait for 0.5 ms; btnD <= '0'; wait for 1 ms; btnD <= '1'; wait for 7 ms; btnD <= '0'; wait for 100 us; btnD <= '1'; wait for 20 us; btnD <= '0'; wait for 200 ms; btnD <= '1'; -- second button press wait for 20 us; btnD <= '0'; wait for 20 us; btnD <= '1'; wait for 6.6 ms; btnD <= '0'; wait for 250 ms; wait; end process; end architecture behavioral;

信号名称的_tb后缀已被删除(重复输入很麻烦)。>>

选择了一个时钟周期,并保证了反弹周期与时钟周期的比率,以允许“反弹”下降。刺激按钮的按下可以扩展,模拟可以任意扩展。

请注意,确保按钮按下值跨越一个或多个时钟间隔。这些应允许通过修改CLKP来更改时钟周期。

防抖动间隔DEBT可以修改以反映不同开关或按钮的使用,包括严重老化的薄膜开关。防抖动间隔是特定开关或按钮的机械特性的结果。传递这些通用常量可以实现一定程度的平台独立性。

第三点通过更改去抖动器来解决:

library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity debouncer is generic ( -- ADDED GENERICS to speed up simulation CLKP: time := 10 ns; DEBT: time := 6.5 ms ); port ( clk: in std_logic; btn: in std_logic; btn_clr: out std_logic ); end entity debouncer; architecture behavioural of debouncer is -- constant delay: integer := 650000; -- 6.5ms constant DELAY: integer := DEBT/CLKP; signal count: integer := 0; signal b_enab: std_logic := '0'; -- RENAMED, WAS btn_tmp signal btnd0: std_logic; -- ADDED for clock domain crossing signal btnd1: std_logic; -- DITTO begin CLK_DOMAIN_CROSS: -- ADDED process process (clk) begin if rising_edge(clk) then btnd0 <= btn; btnd1 <= btnd0; end if; end process; DEBOUNCE_COUNTER: -- ADDED LABEL process (clk) begin if rising_edge(clk) then -- if btn /= btn_tmp then -- REWRITTEN -- btn_tmp <= btn; -- count <= 0; -- elsif count = DELAY then -- btn_clr <= btn_tmp; -- else -- count <= count + 1; -- end if; btn_clr <= '0'; -- btn_clr for only one clock, used as enable if btnd1 = '0' then -- test for btn inactive state count <= 0; elsif count < DELAY then -- while btn remains in active state count <= count + 1; end if; if count = DELAY - 1 then -- why btn_clr '1' or 1 clock btn_clr <= '1'; end if; end if; end process; end architecture behavioural;

防抖器已修改为获得时钟域按钮值,该值用于重置和启用计数器count。输出btn_clr名称保留不变,仅在一个时钟内为true,可以用作启用。

[CLKPDEBT一起使用可允许更快的仿真执行,同时经过相同的仿真时间。

注意,按钮输入的激活状态是硬编码的。它们将连接到可以指定输入极性的设备引脚。

对button_counter的修改将通用常量CLKPDEBT传递给去抖动器:

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity button_counter is generic ( CLKP: time := 10 ns; -- GENERIC CONSTANTS for faster simulation DEBT: time := 6.5 ms -- supports diffeent switches/buttons ); port ( clk: in std_logic; btnU: in std_logic; btnD: in std_logic; led: out std_logic_vector (15 downto 0) ); end entity button_counter; architecture behavioral of button_counter is component debouncer is generic ( CLKP: time := 10 ns; DEBT: time := 6.5 ms ); port ( clk: in std_logic; btn: in std_logic; btn_clr: out std_logic ); end component; signal btnU_clr: std_logic; signal btnD_clr: std_logic; begin debouncer_btnU: debouncer generic map ( CLKP => CLKP, DEBT => DEBT ) port map ( clk => clk, btn => btnU, btn_clr => btnU_clr ); debouncer_btnD: debouncer generic map ( CLKP => CLKP, DEBT => DEBT ) port map ( clk => clk, btn => btnD, btn_clr => btnD_clr ); process (clk) variable count: integer := 0; begin if rising_edge(clk) then if btnU_clr = '1' then count := count + 1; elsif btnD_clr = '1'then count := count - 1; end if; led <= std_logic_vector(to_unsigned(count, led'length)); end if; end process; end architecture behavioral;

并且当进行仿真时,我们现在看到LED上下计数:button_counter_tb

运行测试台并显示各种波形将允许“放大”以显示两个去抖动器中的毛刺处理。

zoom in

通过时钟时钟周期和去抖动间隔通过设计层次结构的修改不是严格必要的。它们有助于仿真,此处将其用于设计验证。 (测试台中显示的刺激不能完全验证设计)。

通过使用通用默认设置(时钟频率为100MHz),该设计很有可能在目标平台上实施时能够正常工作。 (在去抖动器中选择了按钮输入的活动极性以支持原始实现。如果您怀疑按钮在增加或减少时会发生抖动,则可以增加DEBT值。)

如果特定的综合工具无法处理作为通用常量传递的time类型的值,则可以将CLKPDEBT的各种声明转换为integer类型,或者简单地传递最大计数。


3
投票

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.