Lets start with some basic definitions,
What is Bouncing?
Bouncing is the tendency of any two metal contacts in an electronic device to generate multiple signals as the contacts close or open.
What is Bouncing?
Bouncing is the tendency of any two metal contacts in an electronic device to generate multiple signals as the contacts close or open.
What is DeBouncing?
Debouncing is any kind of hardware device or software that ensures that only a single signal will be acted upon for a single opening or closing of a contact.
In this post, I want to explain how this is done and even have shared a code in VHDL. When you want to test your piece of code on a FPGA board, you might need to use the push-buttons for taking input from the user.
Some boards have an integrated debouncer which takes care of the bouncing problem of pushbuttons. But if its not already there, its up to you to implement it in HDL.
When a push-button is pressed, this is how the signal, it generates might look like,
Our aim here, is to process this signal and get a single pulse for each push button press.
There are many debouncer codes available online. Here I have implemented, my own method, so use it after going through it carefully.
I created the FSM shown below and implemented it using VHDL.
What I am trying to do here is, every time I detect an activity on the button, I start a counter. When the counter reaches the maximum count, I check again, if the button is still active. If yes, I take it as a valid button input, otherwise I ignore it and wait for another activity on the button.
VHDL code for DeBouncer circuit:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity DeBounce is
port( Clock : in std_logic;
Reset : in std_logic;
button_in : in std_logic;
pulse_out : out std_logic
);
end DeBounce;
architecture behav of DeBounce is
--the below constants decide the working parameters.
--the higher this is, the more longer time the user has to press the button.
constant COUNT_MAX : integer := 20;
--set it '1' if the button creates a high pulse when its pressed, otherwise '0'.
constant BTN_ACTIVE : std_logic := '1';
signal count : integer := 0;
type state_type is (idle,wait_time); --state machine
signal state : state_type := idle;
begin
process(Reset,Clock)
begin
if(Reset = '1') then
state <= idle;
pulse_out <= '0';
elsif(rising_edge(Clock)) then
case (state) is
when idle =>
if(button_in = BTN_ACTIVE) then
state <= wait_time;
else
state <= idle; --wait until button is pressed.
end if;
pulse_out <= '0';
when wait_time =>
if(count = COUNT_MAX) then
count <= 0;
if(button_in = BTN_ACTIVE) then
pulse_out <= '1';
end if;
state <= idle;
else
count <= count + 1;
end if;
end case;
end if;
end process;
end architecture behav;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity DeBounce is
port( Clock : in std_logic;
Reset : in std_logic;
button_in : in std_logic;
pulse_out : out std_logic
);
end DeBounce;
architecture behav of DeBounce is
--the below constants decide the working parameters.
--the higher this is, the more longer time the user has to press the button.
constant COUNT_MAX : integer := 20;
--set it '1' if the button creates a high pulse when its pressed, otherwise '0'.
constant BTN_ACTIVE : std_logic := '1';
signal count : integer := 0;
type state_type is (idle,wait_time); --state machine
signal state : state_type := idle;
begin
process(Reset,Clock)
begin
if(Reset = '1') then
state <= idle;
pulse_out <= '0';
elsif(rising_edge(Clock)) then
case (state) is
when idle =>
if(button_in = BTN_ACTIVE) then
state <= wait_time;
else
state <= idle; --wait until button is pressed.
end if;
pulse_out <= '0';
when wait_time =>
if(count = COUNT_MAX) then
count <= 0;
if(button_in = BTN_ACTIVE) then
pulse_out <= '1';
end if;
state <= idle;
else
count <= count + 1;
end if;
end case;
end if;
end process;
end architecture behav;
Testbench code for DeBouncer circuit:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY tb_alu IS
END tb_alu;
ARCHITECTURE behavior OF tb_alu IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT DeBounce
PORT(
Clock : IN std_logic;
Reset : IN std_logic;
button_in : IN std_logic;
pulse_out : OUT std_logic
);
END COMPONENT;
--Inputs
signal Clock : std_logic := '0';
signal Reset : std_logic := '0';
signal button_in : std_logic := '0';
--Outputs
signal pulse_out : std_logic;
-- Clock period definitions
constant Clock_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: DeBounce PORT MAP (
Clock => Clock,
Reset => Reset,
button_in => button_in,
pulse_out => pulse_out
);
-- Clock process definitions
Clock_process :process
begin
Clock <= '0';
wait for Clock_period/2;
Clock <= '1';
wait for Clock_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
button_in <= '0';
reset <= '1';
-- hold reset state for 100 ns.
wait for 100 ns;
reset <= '0';
wait for Clock_period*10;
--first activity
button_in <= '1'; wait for Clock_period*2;
button_in <= '0'; wait for Clock_period*1;
button_in <= '1'; wait for Clock_period*1;
button_in <= '0'; wait for Clock_period*20;
--second activity
button_in <= '1'; wait for Clock_period*1;
button_in <= '0'; wait for Clock_period*1;
button_in <= '1'; wait for Clock_period*1;
button_in <= '0'; wait for Clock_period*2;
button_in <= '1'; wait for Clock_period*20;
button_in <= '0';
wait;
end process;
END;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY tb_alu IS
END tb_alu;
ARCHITECTURE behavior OF tb_alu IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT DeBounce
PORT(
Clock : IN std_logic;
Reset : IN std_logic;
button_in : IN std_logic;
pulse_out : OUT std_logic
);
END COMPONENT;
--Inputs
signal Clock : std_logic := '0';
signal Reset : std_logic := '0';
signal button_in : std_logic := '0';
--Outputs
signal pulse_out : std_logic;
-- Clock period definitions
constant Clock_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: DeBounce PORT MAP (
Clock => Clock,
Reset => Reset,
button_in => button_in,
pulse_out => pulse_out
);
-- Clock process definitions
Clock_process :process
begin
Clock <= '0';
wait for Clock_period/2;
Clock <= '1';
wait for Clock_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
button_in <= '0';
reset <= '1';
-- hold reset state for 100 ns.
wait for 100 ns;
reset <= '0';
wait for Clock_period*10;
--first activity
button_in <= '1'; wait for Clock_period*2;
button_in <= '0'; wait for Clock_period*1;
button_in <= '1'; wait for Clock_period*1;
button_in <= '0'; wait for Clock_period*20;
--second activity
button_in <= '1'; wait for Clock_period*1;
button_in <= '0'; wait for Clock_period*1;
button_in <= '1'; wait for Clock_period*1;
button_in <= '0'; wait for Clock_period*2;
button_in <= '1'; wait for Clock_period*20;
button_in <= '0';
wait;
end process;
END;
Simulation waveform from Xilinx ISE:
The design was synthesised successfully using Xilinx ISE 14.6. Before you use the code in your design, make sure you choose the correct values for COUNT_MAX and BTN_ACTIVE.