Bird
Raised Fist0
Arduinoprogramming~10 mins

Debouncing a button in software in Arduino - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Debouncing a button in software
Button Press Detected
Start Timer for Debounce Delay
Wait for Delay to Pass
Check Button State Again
Yes No
Confirm Press
Perform Action
End
When a button press is detected, the program waits a short time to ignore quick bounces, then checks the button state again to confirm a real press before acting.
Execution Sample
Arduino
const int buttonPin = 2;
int buttonState = LOW;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup() {
  pinMode(buttonPin, INPUT);
}

void loop() {
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        // Button pressed action
      }
    }
  }
  lastButtonState = reading;
}
This code reads a button input and waits 50 milliseconds after a change before confirming the press to avoid false triggers from bouncing.
Execution Table
StepreadinglastButtonStatelastDebounceTimemillis()Condition (reading != lastButtonState)ActionbuttonStateOutput
1LOWLOW01000FalseNo timer resetLOWNo action
2HIGHLOW01010TrueReset timer to 1010LOWNo action
3HIGHHIGH10101055FalseNo timer resetLOWNo action (waiting)
4HIGHHIGH10101061FalseNo timer resetHIGHButton press confirmed
5HIGHHIGH10101070FalseNo timer resetHIGHNo action (button held)
6LOWHIGH10101080TrueReset timer to 1080HIGHNo action
7LOWLOW10801135FalseNo timer resetLOWButton release confirmed
8LOWLOW10801140FalseNo timer resetLOWNo action
Exit-------Loop continues waiting for next press
💡 Loop continues indefinitely, checking button state and debouncing each change.
Variable Tracker
VariableStartAfter Step 2After Step 4After Step 6After Step 7Final
readingLOWHIGHHIGHLOWLOWLOW
lastButtonStateLOWLOWHIGHHIGHLOWLOW
lastDebounceTime010101010108010801080
buttonStateLOWLOWHIGHHIGHLOWLOW
Key Moments - 3 Insights
Why do we wait for debounceDelay before changing buttonState?
Because the button can quickly change state due to bouncing, waiting debounceDelay ensures the button state is stable before confirming a press, as shown in steps 3 and 4 of the execution_table.
Why do we compare reading with lastButtonState before resetting the timer?
To detect a change in button input. Only when reading differs from lastButtonState do we reset lastDebounceTime, starting the debounce delay. This is shown in steps 2 and 6.
What happens if we update buttonState immediately without waiting?
The program might register multiple false presses due to bouncing. The debounce delay prevents this by confirming the state after it stabilizes, as seen between steps 2 and 4.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 2. What happens when reading changes from LOW to HIGH?
AThe debounce timer is reset to current millis()
BbuttonState is immediately set to HIGH
CNo action is taken
DThe program exits the loop
💡 Hint
Check the 'Action' column at step 2 in execution_table.
At which step does the button press get confirmed after debounce delay?
AStep 3
BStep 4
CStep 6
DStep 7
💡 Hint
Look for when buttonState changes to HIGH in execution_table.
If debounceDelay was set to 0, what would happen in the execution_table?
Areading would never change
BlastDebounceTime would never update
CbuttonState would update immediately on any reading change
DThe program would stop running
💡 Hint
Think about the condition checking millis() - lastDebounceTime > debounceDelay.
Concept Snapshot
Debouncing a button in software:
- Detect button state change
- Start a timer (debounceDelay)
- Wait for delay to confirm stable state
- Update buttonState only after stable reading
- Prevents false triggers from button bounce
Full Transcript
This visual execution shows how software debouncing works for a button on Arduino. When the button reading changes, the program resets a timer. It waits for a short delay (debounceDelay) before confirming the button press or release. This avoids false multiple triggers caused by the mechanical bouncing of the button contacts. The execution table traces each step, showing readings, timer resets, and when the button state is updated. Key moments clarify why waiting is necessary and how the timer works. The quiz tests understanding of these steps. This method ensures reliable button input in embedded programs.

Practice

(1/5)
1. What is the main purpose of debouncing a button in software on an Arduino?
easy
A. To ignore rapid, repeated signals caused by mechanical noise
B. To increase the button press speed
C. To make the button LED blink faster
D. To reduce power consumption of the Arduino

Solution

  1. Step 1: Understand button noise

    Mechanical buttons create multiple quick signals when pressed due to bouncing contacts.
  2. Step 2: Purpose of debouncing

    Debouncing filters these quick repeated signals to register only one clean press.
  3. Final Answer:

    To ignore rapid, repeated signals caused by mechanical noise -> Option A
  4. Quick Check:

    Debouncing = Ignore noise [OK]
Hint: Debouncing stops false multiple presses from one button push [OK]
Common Mistakes:
  • Thinking debouncing speeds up button presses
  • Confusing debouncing with power saving
  • Assuming debouncing controls LED blinking
2. Which Arduino function is commonly used to measure time for software debouncing?
easy
A. delay()
B. analogWrite()
C. digitalRead()
D. millis()

Solution

  1. Step 1: Identify timing functions

    delay() pauses the program but is not ideal for debouncing timing checks.
  2. Step 2: Use millis() for non-blocking timing

    millis() returns the time since the program started, allowing to check elapsed time without stopping code.
  3. Final Answer:

    millis() -> Option D
  4. Quick Check:

    Debounce timing uses millis() [OK]
Hint: Use millis() to track time without stopping code [OK]
Common Mistakes:
  • Using delay() which blocks code execution
  • Confusing digitalRead() with timing
  • Using analogWrite() which controls PWM output
3. What will be the output on the serial monitor if the following code is run and the button is pressed once?
const int buttonPin = 2;
int buttonState = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup() {
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  int reading = digitalRead(buttonPin);
  if (reading != buttonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        Serial.println("Button pressed");
      }
    }
  }
}
medium
A. Button pressed printed multiple times rapidly
B. Button pressed printed once
C. Syntax error, code won't compile
D. No output printed

Solution

  1. Step 1: Analyze initial buttonState and reading

    buttonState starts at 0 (LOW). If button is pressed, reading becomes HIGH (1).
  2. Step 2: Check debounce logic

    The code updates lastDebounceTime when reading differs from buttonState, and after debounce delay, if reading still differs, buttonState updates and prints.
  3. Step 3: Confirm output

    After debounce delay, buttonState updates and "Button pressed" is printed once.
  4. Final Answer:

    Button pressed printed once -> Option B
  5. Quick Check:

    Debounce logic allows one print after stable press [OK]
Hint: Debounce logic prints once after stable press [OK]
Common Mistakes:
  • Assuming print happens immediately on press
  • Ignoring debounce delay effect
  • Thinking code has syntax errors
4. Identify the error in this debounce code snippet and select the fix:
const int buttonPin = 3;
int buttonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void loop() {
  int reading = digitalRead(buttonPin);
  if (reading != buttonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    buttonState = reading;
    if (buttonState == HIGH) {
      Serial.println("Pressed");
    }
  }
}
medium
A. Initialize buttonState as HIGH instead of LOW
B. Move buttonState = reading inside the first if block
C. Add pinMode(buttonPin, INPUT_PULLUP) in setup()
D. Change debounceDelay to 5000 for longer delay

Solution

  1. Step 1: Check hardware setup assumptions

    Without enabling INPUT_PULLUP, the button pin may float causing unreliable readings.
  2. Step 2: Importance of INPUT_PULLUP

    Using INPUT_PULLUP activates internal pull-up resistor, stabilizing input and making debounce logic reliable.
  3. Final Answer:

    Add pinMode(buttonPin, INPUT_PULLUP) in setup() -> Option C
  4. Quick Check:

    Use INPUT_PULLUP for stable button input [OK]
Hint: Use INPUT_PULLUP to avoid floating pin errors [OK]
Common Mistakes:
  • Changing initial buttonState without hardware reason
  • Moving state update incorrectly breaking debounce logic
  • Setting too long debounce delay unnecessarily
5. You want to detect a single button press and toggle an LED state only once per press using software debounce. Which approach below correctly implements this behavior?
const int buttonPin = 4;
const int ledPin = 13;
int ledState = LOW;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, ledState);
  Serial.begin(9600);
}

void loop() {
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != lastButtonState) {
      lastButtonState = reading;
      if (lastButtonState == LOW) {
        ledState = !ledState;
        digitalWrite(ledPin, ledState);
        Serial.println(ledState ? "LED ON" : "LED OFF");
      }
    }
  }
}
hard
A. This code toggles LED once per press correctly
B. LED toggles multiple times due to missing debounce
C. LED never toggles because lastButtonState is not updated
D. Code causes syntax error due to missing semicolons

Solution

  1. Step 1: Check debounce timing logic

    The code updates lastDebounceTime when reading changes, then waits debounceDelay before accepting new state.
  2. Step 2: Confirm state update and toggle

    Inside debounce check, lastButtonState updates to reading, and LED toggles only when button is pressed (LOW due to INPUT_PULLUP).
  3. Step 3: Verify output and toggle behavior

    LED state flips once per valid press, and serial prints correct status.
  4. Final Answer:

    This code toggles LED once per press correctly -> Option A
  5. Quick Check:

    Debounce + toggle once per press = Correct [OK]
Hint: Toggle LED only when stable press detected after debounce [OK]
Common Mistakes:
  • Not updating lastButtonState causing repeated toggles
  • Ignoring debounce delay causing multiple toggles
  • Confusing HIGH/LOW logic with INPUT_PULLUP