Debouncing as a state machine in Embedded C - Mini Project: Build & Apply
DebounceState with these exact states: BUTTON_UP, BUTTON_FALLING, BUTTON_DOWN, BUTTON_RISING.Use typedef enum { ... } DebounceState; to define the states.
currentState of type DebounceState and initialize it to BUTTON_UP.Declare currentState as DebounceState and set it to BUTTON_UP.
debounceUpdate that takes an int buttonInput (0 or 1) and updates currentState using a switch statement on currentState. Implement these transitions:-
BUTTON_UP: if buttonInput == 0, stay BUTTON_UP, else go to BUTTON_FALLING-
BUTTON_FALLING: if buttonInput == 1, go to BUTTON_DOWN, else go to BUTTON_UP-
BUTTON_DOWN: if buttonInput == 1, stay BUTTON_DOWN, else go to BUTTON_RISING-
BUTTON_RISING: if buttonInput == 0, go to BUTTON_UP, else go to BUTTON_DOWNUse a switch on currentState and update it based on buttonInput as described.
main function that calls debounceUpdate with these button inputs in order: 0, 1, 1, 0, 0. After each call, print the current debounced state as an integer using printf. Use printf("%d\n", currentState);.Call debounceUpdate with each input and print currentState after each call.
Practice
What is the main purpose of using debouncing in embedded C button handling?
Solution
Step 1: Understand mechanical noise in buttons
Mechanical buttons can create multiple rapid on/off signals when pressed or released, called noise.Step 2: Purpose of debouncing
Debouncing filters out these rapid changes to detect a single clean press or release.Final Answer:
To avoid false triggers caused by mechanical noise -> Option AQuick Check:
Debouncing = Avoid false triggers [OK]
- Thinking debouncing speeds up detection
- Confusing debouncing with power saving
- Assuming it increases sensitivity
Which of the following is the correct way to declare a state variable for a debounce state machine in embedded C?
?Solution
Step 1: Identify proper state variable type
Using an enum clearly names states and improves code readability.Step 2: Check syntax correctness
enum ButtonState {IDLE, DEBOUNCE, PRESSED}; ButtonState state = IDLE; correctly declares an enum and initializes the state variable.Final Answer:
enum ButtonState {IDLE, DEBOUNCE, PRESSED}; ButtonState state = IDLE; -> Option CQuick Check:
Enum for states = enum ButtonState {IDLE, DEBOUNCE, PRESSED}; ButtonState state = IDLE; [OK]
- Assigning string to int variable
- Using bool for multiple states
- Using char without clear meaning
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);
Solution
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).Step 2: Confirm final state after 3 calls
Button is still pressed, state=DEBOUNCE (timer=0 now, changes to PRESSED on next call).Final Answer:
DEBOUNCE -> Option DQuick Check:
Timer counts down, state changes only if timer==0 at start of DEBOUNCE [OK]
- Thinking PRESSED after exactly 3 calls
- Not decrementing timer
- Resetting state incorrectly
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?
Solution
Step 1: Analyze timer decrement logic
The code checks if timer == 0 before decrementing, so timer reaches 0 but state changes only next call.Step 2: Identify effect on debounce timing
This causes the debounce to last one extra cycle longer than intended.Final Answer:
Timer decrements after checking zero, causing one extra cycle -> Option BQuick Check:
Check timer before decrement causes delay [OK]
- Thinking state never changes
- Ignoring timer initialization
- Assuming button ignored in PRESSED
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?
Solution
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.Step 2: Button released before timer reaches zero
On release, state immediately returns to IDLE without reaching PRESSED.Final Answer:
State returns to IDLE without reaching PRESSED -> Option AQuick Check:
Hold less than 5 cycles resets state [OK]
- Assuming PRESSED reached early
- Thinking DEBOUNCE lasts indefinitely
- Believing immediate PRESSED on press
Ready to prove it?
Pass the test and this pattern moves unknown
