The Debounced Switch Guard

JSS 1 MakeCode micro:bit Simulation first Taming Mechanical Noise
Simulation lab
Board: BBC micro:bit
Open MakeCode ↗
Simulator preview
☀️ 80

Change the slider level and observe the 5x5 LED display.

📁 Tools ▴
  • Web browser (Chrome, Edge, Firefox)
  • Internet connection
  • MakeCode (micro:bit) online editor

🔧 Build Your Debounced Switch Guard

1 Connect a tactile momentary push button between digital Pin 2 and GND using internal pull-up.
2 Wire an indicator LED with a 220-ohm current-limiting resistor to digital Pin 13.
3 Sample Pin 2 and compare the current reading with the previous loop state.
4 Implement a 50-millisecond time deadband using millis() to eliminate false mechanical contact bounces!
🧩 Block plan / Starter code ▴
const int BUTTON_PIN = 2;
const int LED_PIN = 13;

int buttonState = HIGH;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50; // 50ms cooldown deadband

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("Debounced Switch Guard Ready.");
}

void loop() {
  int reading = digitalRead(BUTTON_PIN);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle LED
        Serial.println("Stable press confirmed - clean trigger!");
      }
    }
  }
  lastButtonState = reading;
}

millis() timestamp comparison filters out sub-millisecond mechanical chatter without blocking execution.

⚗️ Test your model

Test Condition / ActionExpected Result
Rapid Button TapLED toggles cleanly exactly once per press; no double-clicks
Hold Button DownLED remains stable; does not flicker or oscillate
Electrical NoiseMechanical contacts settle within 50ms; false transients ignored
⚑ Try a challenge

Change debounceDelay to 2ms to observe how mechanical noise causes double-counting, then set it to 40ms for optimal tactile response!

❓ Quick check
What physically happens when two spring-metal contacts touch inside a push button switch?

📖 Our Story & Concepts

When you press a physical push button, two flexible metal contacts touch inside. To human eyes, this looks instant. But at the microscopic level, the metal leaves bounce against each other violently dozens of times within 5 milliseconds before making stable contact.

Because microcontrollers execute millions of instructions per second, an undebounced input pin registers every microscopic bounce as an individual user click! In an automated voting booth or ATM keyboard, an undebounced switch would dispense 5 times the requested money or cast 10 duplicate votes. Software debouncing guarantees that only genuine, stable transitions trigger actions.

</> Full Annotated Code Walkthrough

// Complete Debounce Engine with Real-Time Event Counter
const int BUTTON_PIN = 2;
const int LED_PIN = 13;

int buttonState = HIGH;
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
unsigned int validPressCount = 0;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("--- Switch Debounce Diagnostic System ---");
}

void loop() {
  int reading = digitalRead(BUTTON_PIN);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == LOW) {
        validPressCount++;
        digitalWrite(LED_PIN, !digitalRead(LED_PIN));
        Serial.print("Clean Press #");
        Serial.print(validPressCount);
        Serial.print(" at Timestamp: ");
        Serial.print(millis());
        Serial.println(" ms");
      }
    }
  }
  lastButtonState = reading;
}

millis() timestamp comparison filters out sub-millisecond mechanical chatter without blocking execution.

▷ Expected Results & Troubleshooting

Test Condition / ActionExpected Result
Rapid Button TapLED toggles cleanly exactly once per press; no double-clicks
Hold Button DownLED remains stable; does not flicker or oscillate
Electrical NoiseMechanical contacts settle within 50ms; false transients ignored

⚑ Extension Challenges & Blueprints

⚑ Extension Challenges
  • Level 1: Log the raw un-debounced transitions alongside clean debounced presses to measure bounce count.
  • Level 2: Implement hardware debouncing using a 100nF ceramic capacitor in parallel with the switch.
  • Level 3: Add long-press detection: holding for 2 seconds triggers a secondary action.

❓ Check Your Understanding

Question 1: What physically happens when two spring-metal contacts touch inside a push button switch?

Question 2: Why does a raw microcontroller like the micro:bit or Arduino count 5 to 10 presses from a single human finger tap on an un-debounced switch?

Question 3: How does software debouncing solve this contact bounce problem?

Question 4: What would happen if an engineer sets the debounce cooldown time too long, such as 3,000 milliseconds (3 seconds)?

Feedback appears after you check your answer.