In digital hardware systems, input signals often come from mechanical switches or push buttons. These switches do not produce a clean transition from 0 → 1 or 1 → 0. Instead, they generate multiple rapid transitions due to mechanical vibrations inside the switch contacts.
This unwanted behavior is called switch bouncing.
A debounce circuit is used to eliminate these unwanted transitions and produce a stable digital signal.
Mechanical switches consist of metal contacts that physically touch each other when pressed. Because of mechanical elasticity and vibration, the contacts bounce several times before settling.
Example:
Instead of: 0 → 1
The switch produces: 0 → 1 → 0 → 1 → 0 → 1
within a few milliseconds.
Digital circuits interpret each transition as a separate input, which can cause:
- Multiple counter increments
- Multiple FSM state transitions
- Incorrect control signals
- Unexpected system behavior
Therefore, debouncing ensures that only one stable transition is detected.
Debouncing originated when early digital systems began using mechanical input devices, such as:
- Push buttons
- Keyboards
- Toggle switches
Engineers observed that pressing a button once could generate multiple digital pulses, causing systems like counters and microcontrollers to behave incorrectly.
To solve this, designers introduced debounce circuits using:
- RC filters
- Flip-flops
- Counters
- Software delays
Today, debouncing is widely implemented in FPGA, ASIC, and embedded systems.
Debouncing prevents:
- Multiple triggering of events
- False clock pulses
- Incorrect FSM transitions
- Erroneous counter increments
- Unstable input signals
Without debouncing:
1 button press → multiple digital pulses
With debouncing:
1 button press → single clean pulse
No. Debounce, Frequency Divider, and PWM are completely different concepts.
| Feature | Debounce | Frequency Divider | PWM |
|---|---|---|---|
| Purpose | Remove switch noise | Reduce clock frequency | Control power/analog behavior |
| Input | Mechanical switch | Clock signal | Clock signal |
| Output | Clean digital signal | Slower clock | Variable duty cycle signal |
| Application | Buttons, switches | Clock management | Motor control, LEDs |
- Removes unwanted signal transitions
- Ensures single valid input event
- Used with switches and buttons
-
Controls power delivered to a device
-
Changes duty cycle of a periodic signal
-
Used in:
- Motor control
- LED brightness control
- Power electronics
So,
Debounce → Signal Cleaning
PWM → Power Control
A common digital debounce circuit uses synchronizers and counters.
Switch
|
v
+------------------+
| Synchronizer FF |
+------------------+
|
v
+---------------+
| Stability |
| Counter |
+---------------+
|
v
+---------------+
| Debounced |
| Output |
+---------------+
-
Synchronizer
- Prevents metastability when input is asynchronous.
-
Counter
- Waits for input to remain stable for a fixed time.
-
Output Register
- Updates only after signal stability is confirmed.
This is a generic debounce module that works for any clock frequency by adjusting the counter limit.
module debounce
#(
parameter CLK_FREQ = 50000000, // clock frequency
parameter DEBOUNCE_TIME = 20 // debounce time in ms
)
(
input clk,
input reset,
input noisy_in,
output reg clean_out
);
localparam COUNT_MAX = (CLK_FREQ / 1000) * DEBOUNCE_TIME;
reg sync_0;
reg sync_1;
reg [$clog2(COUNT_MAX):0] counter;
wire stable;
assign stable = (counter == COUNT_MAX);
// Synchronizer
always @(posedge clk)
begin
sync_0 <= noisy_in;
sync_1 <= sync_0;
end
// Counter logic
always @(posedge clk or posedge reset)
begin
if(reset)
counter <= 0;
else if(sync_1 != clean_out)
counter <= counter + 1;
else
counter <= 0;
end
// Output update
always @(posedge clk or posedge reset)
begin
if(reset)
clean_out <= 0;
else if(stable)
clean_out <= sync_1;
end
endmoduleAnother commonly used debounce implementation is based on a Finite State Machine with Datapath (FSMD).
This approach separates the design into:
- Control Path → FSM that manages button states
- Data Path → Counter that measures signal stability time
This design is widely used in FPGA boards such as DE10-Lite, where push buttons are connected to a 50 MHz system clock.
The debounce circuit waits until the input remains stable for a certain duration (typically 10–40 ms) before confirming a valid press or release.
The debounce FSM typically contains the following states:
| State | Meaning |
|---|---|
| ZERO | Button not pressed |
| WAIT1 | Button press detected, waiting for stability |
| ONE | Button confirmed pressed |
| WAIT0 | Button release detected, waiting for stability |
State transition concept: ZERO → WAIT1 → ONE → WAIT0 → ZERO
Explanation:
- ZERO → WAIT1 : Button press detected
- WAIT1 → ONE : Button stable for debounce duration
- ONE → WAIT0 : Button release detected
- WAIT0 → ZERO : Button stable released
Button
|
v
+----------------+
| Synchronizer |
+----------------+
|
v
+----------------+
| FSM Control |
| (State Machine) |
+----------------+
|
v
+----------------+
| Counter |
| (Debounce Time)|
+----------------+
|
v
+----------------+
| Debounced Out |
+----------------+
`timescale 1ns / 1ps
module debounce_fsm
#(
parameter CLK_FREQ = 50000000,
parameter DEBOUNCE_TIME = 20
)
(
input clk,
input reset,
input noisy_in,
output reg db_level,
output reg db_tick
);
localparam COUNT_MAX = (CLK_FREQ/1000)*DEBOUNCE_TIME;
localparam N = $clog2(COUNT_MAX);
parameter [1:0]
ZERO = 2'b00,
WAIT1 = 2'b01,
ONE = 2'b10,
WAIT0 = 2'b11;
reg [1:0] state_reg, next_state;
reg [N-1:0] count_reg;
reg [N-1:0] count_next;
wire count_done;
always @(posedge clk or posedge reset)
begin
if(reset)
begin
state_reg <= ZERO;
count_reg <= 0;
end
else
begin
state_reg <= next_state;
count_reg <= count_next;
end
end
assign count_done = (count_reg == COUNT_MAX-1);
always @*
begin
count_next = count_reg;
if(state_reg == WAIT1 || state_reg == WAIT0)
count_next = count_reg + 1;
else
count_next = 0;
end
always @*
begin
next_state = state_reg;
db_tick = 0;
case(state_reg)
ZERO:
begin
db_level = 0;
if(noisy_in)
next_state = WAIT1;
end
WAIT1:
begin
db_level = 0;
if(~noisy_in)
next_state = ZERO;
else if(count_done)
begin
next_state = ONE;
db_tick = 1;
end
end
ONE:
begin
db_level = 1;
if(~noisy_in)
next_state = WAIT0;
end
WAIT0:
begin
db_level = 1;
if(noisy_in)
next_state = ONE;
else if(count_done)
next_state = ZERO;
end
default:
next_state = ZERO;
endcase
end
endmoduleDebouncing is used in many digital systems such as:
FPGA / ASIC Designs
- Push button inputs
- Reset buttons
- User interface controls
Embedded Systems
- Microcontroller switches
- Keypad inputs
- Interrupt triggering
Consumer Electronics
- Keyboards
- Remote controllers
- Control panels
- Eliminates switch noise
- Prevents multiple triggers
- Improves system reliability
- Ensures correct digital input detection
Debounce circuits also introduce some trade-offs:
-
Delay
Debounce requires waiting time (typically 10–20 ms) before confirming input. -
Resource Usage
In FPGA designs, debouncing requires:
Flip-flops
Counters
Logic gates -
Not Suitable for High-Speed Signals
Debouncing should only be used for slow mechanical inputs, not for high-speed digital signals.
Without debouncing, systems may experience:
Multiple counter increments
Unstable FSM transitions
Incorrect interrupt triggers
Unpredictable system behavior
Eample : Button Press → Counter increases by 5 instead of 1