Bird
Raised Fist0
Embedded Cprogramming~10 mins

Debouncing as a state machine in Embedded C - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Debouncing as a state machine
Start: Button Released
↓
Detect Button Press?
No→Stay Released
Yes↓
Start Debounce Timer
↓
Timer Expired?
No→Wait
Yes↓
Confirm Button Press
↓
Button Pressed State
↓
Detect Button Release?
No→Stay Pressed
Yes↓
Start Debounce Timer
↓
Timer Expired?
No→Wait
Yes↓
Confirm Button Released
↓
Back to Start
This flow shows how the button state changes with debounce timing to avoid false triggers.
Execution Sample
Embedded C
enum State {RELEASED, DEBOUNCE_PRESS, PRESSED, DEBOUNCE_RELEASE};
enum State state = RELEASED;
int timer = 0;

// In loop:
// Check button input and update state machine accordingly
This code snippet shows a simple state machine for button debouncing using states and a timer.
Execution Table
StepStateButton InputTimerConditionActionNext State
1RELEASEDPressed0Button Pressed?Start debounce timerDEBOUNCE_PRESS
2DEBOUNCE_PRESSPressed1Timer expired?No action, waitDEBOUNCE_PRESS
3DEBOUNCE_PRESSPressed5Timer expired?Confirm pressPRESSED
4PRESSEDPressed0Button Released?No action, stay pressedPRESSED
5PRESSEDReleased0Button Released?Start debounce timerDEBOUNCE_RELEASE
6DEBOUNCE_RELEASEReleased1Timer expired?No action, waitDEBOUNCE_RELEASE
7DEBOUNCE_RELEASEReleased5Timer expired?Confirm releaseRELEASED
8RELEASEDReleased0Button Pressed?No action, stay releasedRELEASED
💡 Loop continues indefinitely to monitor button state changes with debounce.
Variable Tracker
VariableStartAfter Step 1After Step 3After Step 5After Step 7Final
stateRELEASEDDEBOUNCE_PRESSPRESSEDDEBOUNCE_RELEASERELEASEDRELEASED
timer000000
button_inputReleasedPressedPressedReleasedReleasedReleased
Key Moments - 3 Insights
Why do we wait for the timer to expire before confirming the button press?
Waiting for the timer ensures the button state is stable and avoids reacting to quick, noisy changes (see steps 2 and 3 in execution_table).
Why do we have separate debounce states for press and release?
Separate debounce states let us handle press and release events independently, ensuring each transition is stable before changing the main state (see DEBOUNCE_PRESS and DEBOUNCE_RELEASE in execution_table).
What happens if the button input changes during debounce timer?
If the input changes before timer expires, the state machine resets or returns to the previous stable state, preventing false triggers (implied by waiting and checking conditions in debounce states).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the state after step 3?
ARELEASED
BPRESSED
CDEBOUNCE_PRESS
DDEBOUNCE_RELEASE
💡 Hint
Check the 'Next State' column at step 3 in execution_table.
At which step does the debounce timer confirm the button release?
AStep 7
BStep 5
CStep 6
DStep 8
💡 Hint
Look for 'Confirm release' action in execution_table.
If the button input changes to Released during DEBOUNCE_PRESS, what should happen?
AStay in DEBOUNCE_PRESS state
BContinue to PRESSED state
CReset to RELEASED state
DMove to DEBOUNCE_RELEASE state
💡 Hint
Consider debounce logic to avoid false press confirmation; see key_moments about input changes during debounce.
Concept Snapshot
Debouncing as a state machine:
- Use states: RELEASED, DEBOUNCE_PRESS, PRESSED, DEBOUNCE_RELEASE
- On input change, start debounce timer
- Confirm state change only after timer expires
- Prevents false triggers from noisy button signals
- Loop continuously to monitor button input
Full Transcript
This visual execution shows how a button debounce works as a state machine in embedded C. The machine starts in the RELEASED state. When the button is pressed, it moves to DEBOUNCE_PRESS and starts a timer. Only after the timer expires and the button is still pressed does it confirm the PRESSED state. Similarly, when the button is released, it moves to DEBOUNCE_RELEASE and waits for the timer before confirming RELEASED. This prevents false triggers caused by noisy button signals. The execution table traces each step, showing state, input, timer, conditions, and actions. The variable tracker shows how state, timer, and input change over time. Key moments clarify why waiting for the timer is important and why separate debounce states exist. The quiz tests understanding of state transitions and debounce logic. This approach ensures reliable button input handling in embedded systems.

Practice

(1/5)
1.

What is the main purpose of using debouncing in embedded C button handling?

easy
A. To avoid false triggers caused by mechanical noise
B. To speed up button press detection
C. To reduce power consumption
D. To increase button press sensitivity

Solution

  1. Step 1: Understand mechanical noise in buttons

    Mechanical buttons can create multiple rapid on/off signals when pressed or released, called noise.
  2. Step 2: Purpose of debouncing

    Debouncing filters out these rapid changes to detect a single clean press or release.
  3. Final Answer:

    To avoid false triggers caused by mechanical noise -> Option A
  4. Quick Check:

    Debouncing = Avoid false triggers [OK]
Hint: Debouncing stops noisy signals from causing multiple presses [OK]
Common Mistakes:
  • Thinking debouncing speeds up detection
  • Confusing debouncing with power saving
  • Assuming it increases sensitivity
2.

Which of the following is the correct way to declare a state variable for a debounce state machine in embedded C?

?
easy
A. char state = 0;
B. int state = "IDLE";
C. enum ButtonState {IDLE, DEBOUNCE, PRESSED}; ButtonState state = IDLE;
D. bool state = false;

Solution

  1. Step 1: Identify proper state variable type

    Using an enum clearly names states and improves code readability.
  2. Step 2: Check syntax correctness

    enum ButtonState {IDLE, DEBOUNCE, PRESSED}; ButtonState state = IDLE; correctly declares an enum and initializes the state variable.
  3. Final Answer:

    enum ButtonState {IDLE, DEBOUNCE, PRESSED}; ButtonState state = IDLE; -> Option C
  4. Quick Check:

    Enum for states = enum ButtonState {IDLE, DEBOUNCE, PRESSED}; ButtonState state = IDLE; [OK]
Hint: Use enum for clear, readable state variables [OK]
Common Mistakes:
  • Assigning string to int variable
  • Using bool for multiple states
  • Using char without clear meaning
3.

Given this snippet of a debounce state machine, what will be the value of state after 3 calls if the button is pressed and held?

enum State {IDLE, DEBOUNCE, PRESSED};
State state = IDLE;
int timer = 0;

void update(bool buttonPressed) {
  switch(state) {
    case IDLE:
      if(buttonPressed) {
        state = DEBOUNCE;
        timer = 2;
      }
      break;
    case DEBOUNCE:
      if(timer > 0) timer--;
      else state = PRESSED;
      break;
    case PRESSED:
      if(!buttonPressed) state = IDLE;
      break;
  }
}

// Calls:
update(true);
update(true);
update(true);
medium
A. PRESSED
B. Undefined
C. IDLE
D. DEBOUNCE

Solution

  1. Step 1: Trace state changes through calls

    First call: state IDLE -> DEBOUNCE, timer=2. Second call: DEBOUNCE, timer=2>0, timer-- to 1, still DEBOUNCE. Third call: DEBOUNCE, timer=1>0, timer-- to 0, still DEBOUNCE (else not executed).
  2. Step 2: Confirm final state after 3 calls

    Button is still pressed, state=DEBOUNCE (timer=0 now, changes to PRESSED on next call).
  3. Final Answer:

    DEBOUNCE -> Option D
  4. Quick Check:

    Timer counts down, state changes only if timer==0 at start of DEBOUNCE [OK]
Hint: Count timer ticks before state changes to PRESSED [OK]
Common Mistakes:
  • Thinking PRESSED after exactly 3 calls
  • Not decrementing timer
  • Resetting state incorrectly
4.

Identify the bug in this debounce state machine code snippet:

enum State {IDLE, DEBOUNCE, PRESSED};
State state = IDLE;
int timer = 0;

void update(bool buttonPressed) {
  switch(state) {
    case IDLE:
      if(buttonPressed) {
        state = DEBOUNCE;
        timer = 3;
      }
      break;
    case DEBOUNCE:
      if(timer == 0) state = PRESSED;
      else timer--;
      break;
    case PRESSED:
      if(!buttonPressed) state = IDLE;
      break;
  }
}

What is the problem?

medium
A. State never changes from DEBOUNCE
B. Timer decrements after checking zero, causing one extra cycle
C. Timer is never initialized
D. Button press is ignored in PRESSED state

Solution

  1. Step 1: Analyze timer decrement logic

    The code checks if timer == 0 before decrementing, so timer reaches 0 but state changes only next call.
  2. Step 2: Identify effect on debounce timing

    This causes the debounce to last one extra cycle longer than intended.
  3. Final Answer:

    Timer decrements after checking zero, causing one extra cycle -> Option B
  4. Quick Check:

    Check timer before decrement causes delay [OK]
Hint: Decrement timer before zero check to fix timing [OK]
Common Mistakes:
  • Thinking state never changes
  • Ignoring timer initialization
  • Assuming button ignored in PRESSED
5.

You want to implement a debounce state machine that only confirms a button press if the button is held for at least 5 cycles. Which approach below correctly implements this behavior?

enum State {IDLE, DEBOUNCE, PRESSED};
State state = IDLE;
int timer = 0;

void update(bool buttonPressed) {
  switch(state) {
    case IDLE:
      if(buttonPressed) {
        state = DEBOUNCE;
        timer = 5;
      }
      break;
    case DEBOUNCE:
      if(buttonPressed) {
        if(timer > 0) timer--;
        else state = PRESSED;
      } else {
        state = IDLE;
      }
      break;
    case PRESSED:
      if(!buttonPressed) state = IDLE;
      break;
  }
}

What happens if the button is pressed for 3 cycles then released?

hard
A. State returns to IDLE without reaching PRESSED
B. State changes to PRESSED after 3 cycles
C. State stays in DEBOUNCE indefinitely
D. State immediately changes to PRESSED on press

Solution

  1. Step 1: Trace timer decrement with button held 3 cycles

    Timer starts at 5, decrements each cycle while buttonPressed is true, so after 3 cycles timer = 2.
  2. Step 2: Button released before timer reaches zero

    On release, state immediately returns to IDLE without reaching PRESSED.
  3. Final Answer:

    State returns to IDLE without reaching PRESSED -> Option A
  4. Quick Check:

    Hold less than 5 cycles resets state [OK]
Hint: Hold button full timer cycles to reach PRESSED [OK]
Common Mistakes:
  • Assuming PRESSED reached early
  • Thinking DEBOUNCE lasts indefinitely
  • Believing immediate PRESSED on press
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard