gpt4 book ai didi

VHDL:按钮去抖动(或不去抖动,视情况而定)

转载 作者:行者123 更新时间:2023-12-05 09:10:21 28 4
gpt4 key购买 nike

我已经通读了其他帖子,但似乎无法修复我的问题。我是 VHDL 的新手,所以我确信这是一个简单的修复。

简而言之,按钮没有去抖动。代码编译和比特流程序。在测试台中,按钮可以正常工作,但输出 LED 不会改变。在板上,按下按钮会使随机 LED 点亮(我想是因为弹跳)。根据原理图,输入通过去抖器。

谁能找出问题所在?以及任何其他提示和技巧总是很感激 :)

谢谢!

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

Schematic

按钮计数器.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;

反跳器.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;

最佳答案

在您的代码更新后,还存在几个问题:

  1. 时钟未在测试平台中生成

  2. 测试平台中的刺激(按钮按下)时间不够

  3. 去抖器不会为单个时钟生成启用

为了便于模拟以进行设计验证,您的设计已被修改以允许使用较慢的时钟(看起来您实际上使用的是 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 以反射(reflect)不同开关或按钮的使用情况,包括老化严重的薄膜开关。去抖间隔是特定开关或按钮的机械特性的结果。传递这些通用常量允许一定程度的平台独立性。

第三点是通过更改去抖器解决的:

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 名称保持不变,仅对一个时钟为真,可用作启用。

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 或简单地传递最大计数。

关于VHDL:按钮去抖动(或不去抖动,视情况而定),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61630181/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com