【问题标题】:Incrementing Seven Segment by Using Push Buttons使用按钮增加七段
【发布时间】:2014-01-01 19:58:37
【问题描述】:

我的 fpga 是 spartan 3E-100 Cp132。我有四个按钮作为我的输入,我想通过使用它们来增加电路板 7 段上的四个数字。 VHDL代码如下:

 entity main is
    port(b1,b2,b3,b4 : in STD_LOGIC;
          clk         : in STD_LOGIC;
          sseg        : out STD_LOGIC_VECTOR(0 to 6);
          anodes      : out STD_LOGIC_VECTOR(3 downto 0);
          reset           : in STD_LOGIC
          );
end main;

architecture Behavioral of main is
    signal bcd1, bcd2, bcd3, bcd4 : STD_LOGIC_VECTOR (3 downto 0);
    signal clk2 : STD_LOGIC;
    signal pushbuttons : STD_LOGIC_VECTOR(3 downto 0);
    signal db_pushbuttons : STD_LOGIC_VECTOR(3 downto 0);
    signal counter : STD_LOGIC_VECTOR(1 downto 0);
    signal clk_divider : STD_LOGIC_VECTOR(20 downto 0);
    component Debounce is
        port( cclk : in STD_LOGIC;
                inp : in STD_LOGIC_VECTOR(3 downto 0);
                cclr : in STD_LOGIC;
                db  : out STD_LOGIC_VECTOR(3 downto 0)
                );
    end component;
begin
    pushbuttons <= b4 & b3 & b2 & b1;
    Db : Debounce port map
            ( cclk => clk2,
              inp => pushbuttons,
              cclr => reset,
              db  => db_pushbuttons);

process (clk)
begin
    if rising_edge(clk) then
        if clk_divider <= "1100001101010000" then
            clk_divider <= clk_divider + 1;
            clk2 <= '0';
        else
            clk_divider <= (others => '0');
            clk2 <= '1';
        end if;
    end if;
end process;

process (clk2, reset)
begin
    if reset = '1' then
        -- do something here
        bcd1 <= "0000";
        bcd2 <= "0000";
        bcd3 <= "0000";
        bcd4 <= "0000";
    elsif rising_edge(clk2) then
        counter <= counter + 1;
        if db_pushbuttons(0) = '1' then -- db_b1
            if bcd1 <= "1000" then
                bcd1 <= bcd1 + 1;
            else
                bcd1 <= "0000";
            end if;
        elsif db_pushbuttons(1) = '1' then -- db_b2
            if bcd2 <= "1000" then
                bcd2 <= bcd2 + 1;
            else
                bcd2 <= "0000";
            end if;
        elsif db_pushbuttons(2) = '1' then -- db_b3
            if bcd3 <= "1000" then
                bcd3 <= bcd3 + 1;
            else
                bcd3 <= "0000";
            end if;
        elsif db_pushbuttons(3) = '1' then --db_b4
            if bcd4 <= "1000" then
                bcd4 <= bcd4 + 1;
            else
                bcd4 <= "0000";
            end if;
        end if;
    end if;
end process;

process (counter, bcd1, bcd2, bcd3, bcd4)
    variable display : STD_LOGIC_VECTOR(3 downto 0);
begin
    case counter is
        when "00" => anodes <= "1110"; display := bcd1;
        when "01" => anodes <= "1101"; display := bcd2;
        when "10" => anodes <= "1011"; display := bcd3;
        when "11" => anodes <= "0111"; display := bcd4;
        when others => null;
    end case;

    case display is
        when "0000" => sseg <= "0000001"; --0
        when "0001" => sseg <= "1001111"; --1
        when "0010" => sseg <= "0010010"; --2
        when "0011" => sseg <= "0000110"; --3
        when "0100" => sseg <= "1001100"; --4
        when "0101" => sseg <= "0100100"; --5
        when "0110" => sseg <= "0100000"; --6
        when "0111" => sseg <= "0001111"; --7
        when "1000" => sseg <= "0000000"; --8
        when "1001" => sseg <= "0000100"; --9
        when others => sseg <= "0010000"; --e, represents error
    end case;
end process;
end Behavioral;

每个按钮都应将相应的 7 段数字(b1 --> 最右边的数字和 b4--> 最左边的数字)加一。问题是当我按下按钮时,它会完成这项工作,但不会将其增加一,而是增加一些任意数字。原因是它在时钟 2 的每个上升沿递增 1,并且由于该时钟的频率,它发生得太快。我怎样才能摆脱这个问题?我尝试了几个按钮的去抖动代码,但它们并没有太大帮助。我完全被困在这里。我的意思是应该有办法做到这一点,但是怎么做呢?顺便说一句,我在上面的代码中一直使用的去抖动代码是

entity Debounce is
    port(cclk       :   in STD_LOGIC;
          inp    :  in STD_LOGIC_VECTOR(3 downto 0);
          cclr  :  in STD_LOGIC;
          db     :  out STD_LOGIC_VECTOR(3 downto 0)
         );
end Debounce;

architecture Behavioral of Debounce is
    signal delay1, delay2, delay3 : STD_LOGIC_VECTOR(3 downto 0);
begin
    process (cclk, cclr)
    begin
        if cclr = '1' then
            delay1 <= "0000";
            delay2 <= "0000";
            delay3 <= "0000";
        elsif rising_edge(cclk) then
            delay1 <= inp;
            delay2 <= delay1;
            delay3 <= delay2;
        end if;
    end process;
    db <= delay1 and delay2 and delay3;
end Behavioral;

所以任何帮助将不胜感激,在此先感谢!

【问题讨论】:

  • clk的频率是多少?
  • 我猜应该是 50MHz。它是 FPGA 上的标准时钟。

标签: button push vhdl synclock debouncing


【解决方案1】:

如果按钮的预期功能是您只会增加一次,那么无论您按住它多长时间,您都需要在去抖开关输出上实现“边缘检测”。也就是说,只允许 bcd 计数在去抖开关信号的上升沿增加/更新。例如:

...
elsif rising_edge(clk2) then
    counter <= counter + 1;
    db_pushbuttons_previous <= db_pushbuttons;
    if db_pushbuttons(0) = '1' and db_pushbuttons_previous(0) = '0' then --rising edge detect
        if bcd1 <= "1000" then
            bcd1 <= bcd1 + 1;
        else
            bcd1 <= "0000";
        end if;
...

这样,无论db_pushbuttons(0)被断言多久,bcd值都只会增加一次。

【讨论】:

  • 但如果我这样做,我会创建一个 FSM,对吗?我不确定在您的代码中可以将信号分配放在哪里?我需要创建另一个流程还是将其移动到现有流程中?
  • 你先生,终于结束了我的痛苦。非常感谢!
【解决方案2】:

使用 GHDL 进行测试我有以下代码。 文件:sevensegns.vhdl

-----------------------------------------
---- SevenSegNS.vhdl
---- Seven segment driver with 4 input
---- buttons

---- Author: Derby Russell
---- Date: 12-13-2013
-----------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.ALL;

entity main_7_seg is
     port(b1,b2,b3,b4 : in std_logic;
          clk         : in std_logic;
          sseg        : out std_logic_vector(0 to 6);
          anodes      : out std_logic_vector (3 downto 0);
          reset       : in std_logic
          );
end main_7_seg;

architecture behavioral of main_7_seg is
    signal bcd1, bcd2, bcd3, bcd4 : unsigned (3 downto 0) := "0000";
    signal clk2 : std_logic := '0';
    signal pushbuttons : std_logic_vector(3 downto 0) := "0000";
    signal db_pushbuttons : std_logic_vector(3 downto 0) := "0000";
    signal counter : unsigned (1 downto 0) := "00";
    component Debounce is
        port( cclk : in std_logic;
                inp : in std_logic_vector(3 downto 0);
                cclr : in std_logic;
                db  : out std_logic_vector(3 downto 0)
                );
    end component;
begin
    pushbuttons <= b4 & b3 & b2 & b1;
    Db : Debounce port map
            ( cclk => clk2,
              inp => pushbuttons,
              cclr => reset,
              db  => db_pushbuttons);
process (clk)
begin
    if rising_edge(clk) then
        clk2 <= '1';
    else
        clk2 <= '0';

    --  FOR RUNNING ON ACTUAL HARDWARE:
    --  RESTORE NEXT 6 LINES AND COMMENT OUT ABOVE 4 LINES.

    --    if clk_divider <= "1100001101010000" then
    --        clk_divider <= clk_divider + 1;
    --        clk2 <= '0';
    --    else
    --        clk_divider <= (others => '0');
    --        clk2 <= '1';


    end if;
end process;

P2: process (clk2, reset)
begin
    if reset = '1' then
        -- do something here
        bcd1 <= "0000";
        bcd2 <= "0000";
        bcd3 <= "0000";
        bcd4 <= "0000";
    elsif rising_edge(clk2) then
        counter <= counter + 1;
        if db_pushbuttons(0) = '1' then -- db_b1
            if bcd1 <= "0010" then
                if bcd1 = "0000" then
                    bcd1 <= bcd1 + 1;
                end if;
            else
                bcd1 <= "0000";
            end if;
        elsif db_pushbuttons(1) = '1' then -- db_b2
            if bcd2 <= "0010" then
                if bcd2 = "0000" then
                    bcd2 <= bcd2 + 1;
                end if;
            else
                bcd2 <= "0000";
            end if;
        elsif db_pushbuttons(2) = '1' then -- db_b3
            if bcd3 <= "0010" then
                if bcd3 = "0000" then
                    bcd3 <= bcd3 + 1;
                end if;
            else
                bcd3 <= "0000";
            end if;
        elsif db_pushbuttons(3) = '1' then --db_b4
            if bcd4 <= "0010" then
                if bcd4 = "0000" then
                    bcd4 <= bcd4 + 1;
                end if;
            else
                bcd4 <= "0000";
            end if;
        end if;
    end if;
end process P2;

P3: process (counter, bcd1, bcd2, bcd3, bcd4)
    -- variable display : std_logic_vector(3 downto 0);
    variable display : unsigned (3 downto 0);
begin
    case counter is
        when "00" => anodes <= "1110"; display := bcd1;
        when "01" => anodes <= "1101"; display := bcd2;
        when "10" => anodes <= "1011"; display := bcd3;
        when "11" => anodes <= "0111"; display := bcd4;
        when others => null;
    end case;

    case display is
        when "0000" => sseg <= "0000001"; --0
        when "0001" => sseg <= "1001111"; --1
        when "0010" => sseg <= "0010010"; --2
        when "0011" => sseg <= "0000110"; --3
        when "0100" => sseg <= "1001100"; --4
        when "0101" => sseg <= "0100100"; --5
        when "0110" => sseg <= "0100000"; --6
        when "0111" => sseg <= "0001111"; --7
        when "1000" => sseg <= "0000000"; --8
        when "1001" => sseg <= "0000100"; --9
        when others => sseg <= "0010000"; --e, represents error
    end case;
end process P3;
end behavioral;

文件:debounce.vhdl

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

entity Debounce is
    port(cclk       :   in std_logic;
          inp    :  in std_logic_vector(3 downto 0);
          cclr  :  in std_logic;
          db     :  out std_logic_vector(3 downto 0)
         );
end Debounce;

architecture behavioral_2 of Debounce is
    signal delay1, delay2, delay3 : std_logic_vector(3 downto 0);
begin
    process (cclk, cclr)
    begin
        if cclr = '1' then
            delay1 <= "0000";
            delay2 <= "0000";
            delay3 <= "0000";
        elsif rising_edge(cclk) then
            delay1 <= inp;
            delay2 <= delay1;
            delay3 <= delay2;
        end if;
    end process;
    db <= delay1 and delay2 and delay3;
end behavioral_2;

我用数据文件sevensegns_tb.vhdl处理了这两个文件 然后我运行文件并用 gtkwave 观察数据 这是输出:
(来源:googlecode.com

我已将所有代码和结果发布到: Google Code sevenseg
单击“源”选项卡以查看创建的所有文件。

【讨论】:

  • 感谢您的回复!也许我错了,但是,在模拟中,当相应的按钮被释放时,bcd 似乎会增加。而且我不明白为什么你不划分 clk 来获得频率为 50 KHz 的 clk2 (因为否则你无法在七段上观察到任何东西)。但是,您使用两个相同的时钟。当我尝试运行您的代码时,Xilinix 给出了一个错误,指出 clk2 由于同步描述错误而无法合成。也许我做错了什么,但如果你能解释一下,我会很高兴。
  • 哦,我改变了时钟,这样我的测试床就不会长 20 页了。时钟可以放回原处而不会造成伤害。
  • 将时钟恢复为您拥有的代码,我在我的代码中留下了该代码的注释。
猜你喜欢
  • 2015-09-20
  • 1970-01-01
  • 2017-01-20
  • 2018-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 2015-04-25
相关资源
最近更新 更多