Verilog Code for Debouncer: Syntax, Example, and Tips
A debouncer in Verilog filters noisy button signals by sampling the input over time and confirming stability before changing output. Use a
counter and state register to detect a stable input, as shown in the debouncer module example below.Syntax
The debouncer module typically has an input signal (noisy button), a clock, and a clean output signal. It uses a counter to measure how long the input stays stable before updating the output.
- clk: Clock input to synchronize sampling.
- btn_in: Noisy button input signal.
- btn_out: Debounced clean output signal.
- counter: Counts clock cycles while input is stable.
- threshold: Number of cycles input must be stable to confirm.
verilog
module debouncer(
input wire clk,
input wire btn_in,
output reg btn_out
);
reg [19:0] counter = 0; // 20-bit counter for delay
reg btn_sync_0 = 0, btn_sync_1 = 0;
// Synchronize input to clock domain
always @(posedge clk) begin
btn_sync_0 <= btn_in;
btn_sync_1 <= btn_sync_0;
end
always @(posedge clk) begin
if (btn_sync_1 == btn_out) begin
counter <= 0; // reset counter if input matches output
end else begin
counter <= counter + 1; // increment counter if input differs
if (counter == 20'd1000000) begin // threshold for stable input
btn_out <= btn_sync_1; // update output after stable period
counter <= 0;
end
end
end
endmoduleExample
This example shows a debouncer module that cleans a noisy button input by waiting for the input to be stable for about 1 million clock cycles before changing the output. It uses a 20-bit counter and input synchronization to avoid glitches.
verilog
module testbench;
reg clk = 0;
reg btn_in = 0;
wire btn_out;
debouncer uut(
.clk(clk),
.btn_in(btn_in),
.btn_out(btn_out)
);
// Clock generation: 10ns period
always #5 clk = ~clk;
initial begin
// Simulate noisy button press
btn_in = 0;
#20 btn_in = 1; // button pressed
#10 btn_in = 0; // noise
#10 btn_in = 1; // stable press
#10000000; // wait long enough for debounce
#20 btn_in = 0; // button released
#10000000; // wait for debounce
$finish;
end
initial begin
$monitor("Time=%0t btn_in=%b btn_out=%b", $time, btn_in, btn_out);
end
endmoduleOutput
Time=20 btn_in=1 btn_out=0
Time=1000020 btn_in=1 btn_out=1
Time=1000040 btn_in=0 btn_out=1
Time=2000040 btn_in=0 btn_out=0
Common Pitfalls
Common mistakes when writing a debouncer include:
- Not synchronizing the input signal to the clock domain, causing metastability.
- Using too short or too long a counter threshold, leading to false triggers or slow response.
- Not resetting the counter when input matches output, causing delayed updates.
Always synchronize inputs and choose a threshold based on your clock frequency and desired debounce time.
verilog
/* Wrong: No input synchronization and no counter reset */ module bad_debouncer( input wire clk, input wire btn_in, output reg btn_out ); reg [19:0] counter = 0; always @(posedge clk) begin if (btn_in != btn_out) begin counter <= counter + 1; if (counter == 20'd1000000) btn_out <= btn_in; end end endmodule /* Right: Synchronize input and reset counter */ module good_debouncer( input wire clk, input wire btn_in, output reg btn_out ); reg [19:0] counter = 0; reg btn_sync_0 = 0, btn_sync_1 = 0; always @(posedge clk) begin btn_sync_0 <= btn_in; btn_sync_1 <= btn_sync_0; end always @(posedge clk) begin if (btn_sync_1 == btn_out) counter <= 0; else begin counter <= counter + 1; if (counter == 20'd1000000) begin btn_out <= btn_sync_1; counter <= 0; end end end endmodule
Quick Reference
Tips for writing a Verilog debouncer:
- Use a multi-stage synchronizer for input signals crossing clock domains.
- Choose a counter width and threshold based on your clock frequency and debounce time (e.g., 10-20 ms).
- Reset the counter whenever input matches output to avoid false triggers.
- Test with noisy input signals to verify stability.
Key Takeaways
Synchronize noisy inputs to the clock domain before debouncing to avoid glitches.
Use a counter to confirm input stability over a set time before changing output.
Reset the counter when input matches output to ensure timely updates.
Choose debounce delay based on clock frequency and button characteristics.
Test your debouncer with noisy signals to ensure reliable output.