Reputation: 15
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!
Upvotes: 1
Views: 4485
Reputation: 115
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:
(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.
Upvotes: 0
Reputation: 3655
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.
Upvotes: 1