loading

When you press a button, there is a chance that the button will not simply go from open to close. Since a button is a mechanical device, the contacts can bounce. (From Embedded Micro) For a short period after the button is pressed the value you read from an IO pin may toggle between 0 and 1 a few times before settling on the actual value.

To debounce a button, you just need to require that for a button to register as being pressed, it must look like it's being pressed for a set amount of time. In this case, being pressed is when the value of the button is 1. If you read enough 1's in a row it is safe to assume that the button has stopped bouncing and you can register one button press. If you fail to do this and you are using the button to increment a counter, then the counter may increase by more than 1 per button press since it will appear that each bounce was a separate press.

In this project, we will deb


Note: If you want to know more about clock domain, synchronization and metastability, you can visit the following websites:

https://filebox.ece.vt.edu/~athanas/4514/ledadoc/h...

https://embeddedmicro.com/tutorials/mojo/metastabi...

Step 1: Step 1: Input & Output Signals and Internal Variables

Input

  1. clk - Clock signal to synchronize the button input
  2. btn - Button pressed

Output

  1. LED - Light up LED when button is pressed
  2. dbsig - Output the debounced signal to the scope
  3. button_out1 - Output the flip flop 1 signal to scope
  4. button_out2 - Output the flip flop 2 signal to scope

Internal variables

  1. button_ff1 (reg) - Btn flip-flop1 for synchronization
  2. button_ff2 (reg) - Btn flip-flop2 for synchronization
  3. [20:0] count (reg) - 21 bits counter to increment when button is pressed or released
  4. threshold (constant /parameter) - Gauge how long the button should be pressed. In this case, we want 2ms, so the number we need to count is 100,000 for 100MHz clock

Step 2: Step 2: How Does the Logic Work

Firstly, we use two flip-flops (reg button_ff1 & reg button_ff2) to synchronize the button signal to the clock domain “clk”. When the push-button is pushed or released, we increment or decrement the counter “count”. The counter has to reach threshold before we decide that the push-button state has changed. We implement this by conditional statements:

Condition 1: Button flip-flop 2 (reg button_ff2) is high “1” and count “count” isn't at the count limit.

This makes sure that we won't count up at the limit. If this condition matches, we will count up (this means btn pressed)

Condition 2: Button flip-flop 2 (reg button_ff2) is low “0” and the count has at least 1 in it.

This makes sure no subtraction when count is 0. If this condition matches, we will count down (btn released)

Now, we need to decide when the button is pressed or not. To do this, we create a constant (parameter) “threshold” gauge how long button pressed to determine it is in pressed state. If the count is greater the threshold, the debounced signal “dbsign” will be high “1”. Otherwise, it will be low “0”.

We first simulate the logic and then scope out two signals (button_out1 and button_out2) through Pmod connectors to the Logic Analyzer and look at the timing diagram. In addition, we assign LED to debounced signal (dbsig), i.e. if the dbsig is “1”, LED lights up. Otherwise, it will be off.

Step 3: Step 3: Simulation

Follow the step to create the testbench and run the simulation https://www.instructables.com/id/How-to-Use-Vivado...

A 20ns clock is created and btn input is set as 0 and then 1 after 10ns. The dbsig and LED signal will be “1” at 2ms. Run the simulation at 20ms by change the simulation time (see picture)

Remember to create two procedure block (one always for clock generation and one for stimulus (btn)) to avoid any intra signal delay.

There is 30ns delay between button_ff1 and button_ff2. It shows in the simulation of button_out1 and button_out2.

Step 4: Step 4: Implemenation

Create constraint file from Vivado. Refer to http://www.xilinx.com/support/documentation/sw_manuals/xilinx2015_2/ug935-vivado-io-clock-planning-tutorial.pdf (see Lab 2: Post-Synthesis I/O Planning) and http://www.xilinx.com/support/documentation/sw_manuals/xilinx2012_2/ug945-vivado-using-constraints-tutorial.pdf for timing constraint

Then, run the synthesis and implementation and eventually generate bitstream file to program it on FPGA. (If you are not familiar with these two processes, you can take a look at https://www.instructables.com/id/How-to-use-Verilog-and-Basys-3-to-do-3-bit-binary-/ from step 8-11.

Step 5: Step 5: Timing Analysis Through Logic Analyzer

We port button flip flop signals (button_out1 and button_out2) and dbsig to Pmod port JC1, JC2 and JC3 of Basys 3 and then connect ports to Digilent Analog Discovery 2 digital channels 0, 1 and 2

Step 6: Verilog Code (design & Simulation) & Project File

Verilog Code:

`timescale 1ns / 1ps

/////////////////////////////////////////////////////////////////////////////////

/ Company:

// Engineer:

//

// Create Date: 07/17/2016 05:01:56 PM

// Design Name:

// Module Name: debouncing

// Project Name:

// Target Devices:

// Tool Versions:

// Description:

//

// Dependencies:

//

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

//

//////////////////////////////////////////////////////////////////////////////////

module debouncing #(parameter threshold = 100000 )// set parameter thresehold to guage how long button pressed

(

input clk, //clock signal

input btn, //input button

output LED, //LED output. Light up when btn is pressed

output reg dbsig, //debounced signal to logic analyzer

output button_out1, //flip-flop1 signal to logic analyzer

output button_out2 //flip-flop2 signal to logic analyzer

);

reg button_ff1 = 0; //button flip-flop for synchronization. Initialize it to 0

reg button_ff2 = 0; //button flip-flop for synchronization. Initialize it to 0

reg [20:0]count = 0; //20 bits count for increment & decrement when button is pressed or released. Initialize it to 0

// First use two flip-flops to synchronize the button signal the "clk" clock domain

always @(posedge clk)begin

button_ff1 <= btn;

button_ff2 <= button_ff1;

end

// When the push-button is pushed or released, we increment or decrement the counter

// The counter has to reach threshold before we decide that the push-button state has changed

always @(posedge clk) begin

if (button_ff2) //if button_ff2 is 1

begin

if (~&count)//if it isn't at the count limit. Make sure won't count up at the limit. First AND all count and then not the AND

count <= count+1; // when btn pressed, count up

end else begin

if (|count)//if count has at least 1 in it. Make sure no subtraction when count is 0

count <= count-1; //when btn relesed, count down

end

if (count > threshold)//if the count is greater the threshold

dbsig <= 1; //debounced signal is 1

else

dbsig <= 0; //debounced signal is 0

end

assign LED = dbsig; // assign debounced signal to LED

assign button_out1 = button_ff1; //assign button_out1 to button_ff1

assign button_out2 = button_ff2; //assign button_out2 to button_ff2

endmodule

`timescale 1ns / 1ps

/////////////////////////////////////////////////////////////////////////////////

/ Company:

// Engineer:

//

// Create Date: 12/19/2016 09:21:44 PM

// Design Name:

// Module Name: debounce_tb

// Project Name:

// Target Devices:

// Tool Versions:

// Description:

//

// Dependencies:

//

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

//

//////////////////////////////////////////////////////////////////////////////////

module debounce_tb();

//Inputs in the module enable_sr. Need to use register type

reg clk = 0; //clock signal

reg btn; //input button

//Outputs in the module enable_sr. Need to use net type

wire LED; //LED output. Light up when btn is pressed

wire dbsig; //debounced signal to logic analyzer

wire button_out1; //flip-flop1 signal to logic analyzer

wire button_out2; //flip-flop2 signal to logic analyzer

// Instantiate the Unit Under Test (UUT) for module debouncing

debouncing uut(

.clk(clk),

.btn(btn),

.LED(LED),

.dbsig(dbsig),

.button_out1(button_out1),

.button_out2(button_out2)

);

// Generate the continuous clock signal. Wait for 10ns. Period is 20ns

always #10 clk = ~clk;

//Generate the button stimulus

initial begin

btn = 0;

#10 btn = 1;

end

// Need initial whenever we run finish or we need to include it in the begin end

initial

#4000 $finish;

endmodule

About This Instructable

1,038views

21favorites

License:

Bio: I work in the Digilent sales team and promote engineering education hardware to students, educator or who wants to learn engineering and technology. I like ... More »
More by alexwonglik:UART communication on Basys 3, FPGA dev board powered by Xilinx Artix 7 Part II UART communication on Basys 3, FPGA dev board powered by Xilinx Artix 7 Part I Debonucing Button on Basys 3, Xilinx FPGA Development Board 
Add instructable to: