
FPGA programming. The study of the phenomenon of "bounce of contacts" and the method of getting rid of it

So, the goal of the work: To study the phenomenon of “ bounce of contacts ”, create a project in Xilinx ISE Project Navigator : When you click on the button, the value of the register increases by 1.
Part 1. What is a "bounce of contacts"?
“Shocking is a phenomenon that occurs in electric and electronic switches, in which instead of some stable signal they produce random high-frequency oscillations at the output” (c) Wikipedia.
Simply put, when you press and release the button, it does not immediately enter the desired state. For some time, the button contacts “rattle” among themselves, which will be perceived by the microcontroller as multiple pulses. The number of these pulses can exceed thousands. Visually, bounce can be seen on the oscillogram, which shows the moment the button is released:

Part 2. Creating a project.
In my previous article , the creation of a new project for the Spartan-3E Starter Kit in Xilinx ISE Project Navigator v12.3 was described in detail. Let's create the project again, call it, for example, drebezg_habr and make some changes to it:
1. We need one button and eight LEDs. Add the btn input signal and 8 led output signals to the ports:
entity drebezg_habr is
Port (clk: in STD_LOGIC;
btn: in STD_LOGIC;
led: out STD_LOGIC_VECTOR (7 downto 0));
end drebezg_habr;
2. In the pin.ucf file, write the names of the legs corresponding to the button and each LED:
NET "clk" LOC = "C9";
NET "led <0>" LOC = "F12";
NET "led <1>" LOC = "E12";
NET "led <2>" LOC = "E11";
NET "led <3>" LOC = "F11";
NET "led <4>" LOC = "C11";
NET "led <5>" LOC = "D11";
NET "led <6>" LOC = "E9";
NET "led <7>" LOC = "F9";
NET "btn" LOC = "K17";
NET "btn" PULLUP;
Leg K17 corresponds to the bottom button from the available ones:

The word PULLUP connects the button according to the following scheme (directly inside the FPGA):

Part 3. Programming.
Go to the drebezg_habr.vhd file. Let's create an 8-bit register-counter, which we will try to add by one when the button is pressed once: between architecture and begin we write
signal count_led: std_logic_vector (7 downto 0);
And immediately, after the word begin, we direct this counter to our LEDs:
led <= count_led;
Now our task is to add one to the counter count_led when the button is pressed. Immediately the decision arises to make a variable that would store the previous state of the button and compare with its current state. Let's do this:
architecture Behavioral of drebezg_habr is
signal count_led: std_logic_vector (7 downto 0);
signal old_btn: std_logic;
begin
process (clk)
begin
if rising_edge (clk) then
old_btn <= btn;
if old_btn = '0' and btn = '1' then
count_led <= count_led + 1;
end if;
end if;
end process;
led <= count_led;
end Behavioral;
We broadcast, sew, test. I am sure that the result will not suit you at all, because the diodes will simply blink completely randomly. This is due to the fact that if old_btn = '0' and btn = '1' then there are a lot of events during the pressing and releasing of the button due to the rattling of contacts. To get rid of this phenomenon, we need to wait for a clearly established value of the logical unit. To do this, we will start the counter, which increases by 1, while the button has a value of a logical unit. The counter is reset if the button has accepted a value of logical zero. Thus, no matter how many pulses there are during a button being pressed due to bounce, there will come a moment when the btn value is clearly set to a logical unit, the counter will reach a certain value, and we will be able to judge whether what really was the click of a button. Now we do not need the variable old_btn.
architecture Behavioral of drebezg_habr is
signal count_led: std_logic_vector (7 downto 0);
constant clk_freq: integer: = 50_000_000; - quartz frequency
constant btn_wait: integer: = clk_freq / 4; - we will wait 0.25 seconds for the establishment of the unit
signal count: integer range 0 to btn_wait: = 0;
begin
process (clk)
begin
if rising_edge (clk) then
if btn = '1' then
count <= count + 1;
if count = btn_wait then
count_led <= count_led + 1;
count <= 0;
end if;
else
count <= 0;
end if;
end if;
end process;
led <= count_led;
end Behavioral;
The btn_wait value was selected 0.25 seconds so that the count_led value would not be added too often while the button is in the clamped state.
Another version of anti-bounce (even more reliable) is adding count to 1 when btn is a logical unit, and subtracting from count 1 when btn is zero. Moreover, if the value of count drops to 0, then the button is not pressed, or there was a chatter. Well, if count is counted to the coveted btn_wait, then there was a press =)
As a homework, I can advise you to add a project: add count_led after the button has been pressed and released.
So, we got acquainted in practice with the phenomenon of "bounce of contacts" and learned to get rid of it. This phenomenon can be observed not only in buttons, toggle switches and other similar things, but even sometimes in various protocols, for example RS-232.
The source code of the project is here . I wish you all success in mastering FPGAs!