Incrementing Seven Segment by Using Push Buttons

4.3k views Asked by At

My fpga is spartan 3E-100 Cp132. I have four push buttons as my inputs and I want to increment the four digits on 7-segment of the board by using them. The VHDL code is below:

 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;

Every pushbutton should increment the corresponding 7-segment digit (b1 --> rightmost digit and b4--> leftmost digit) by one. The problem is when I push the button, it does the job but not increment it by one but some arbitrary number. The reason is that it increments by one at every rising edge of the clock 2 and it happens too quickly due to the frequency of this clock. How can I manage to get rid of this problem? I tried several debouncing code for the push buttons but they weren't helpful so much. I am totally stuck here. I mean there should be a way to do it, but how? By the way, the debouncing code that I have been using with the code above is

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;

So any help will be appreciated, thanks in advance!

2

There are 2 answers

2
Josh On BEST ANSWER

If the intended function of the button is that you will only increment once, no matter how long you hold it down, you need to implement an "edge detect" on the debounced switch output. That is, only allow the bcd count to increment/update on the rising edge of the debounced switch signal. For example:

...
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;
...

This way, no matter how long db_pushbuttons(0) is asserted, the bcd value will only be incremented once.

3
user2737761 On

Testing with GHDL I have the following code. file: 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;

file: 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;

I processed these two files with a data file sevensegns_tb.vhdl Then I ran the files and observed the data with gtkwave here is the output: gtkwave output
(source: googlecode.com)

And I have posted all the code and results to: Google Code sevenseg
Click on the Source tab to see all the files created.