📖 Scenario: You are programming a simple device that changes its behavior based on events like button presses. This device has three states: OFF, ON, and BLINKING. It starts in the OFF state.
🎯 Goal: Build a small event-driven state machine in C that changes the device state when events occur. You will create the states, define events, write the logic to handle events and update the state, and finally print the current state.
📋 What You'll Learn
Define an enum called State with values OFF, ON, and BLINKING
Define an enum called Event with values BUTTON_PRESS and TIMER_EXPIRE
Create a variable current_state of type State initialized to OFF
Write a function handle_event that takes an Event and updates current_state based on the rules:
OFF + BUTTON_PRESS -> ON
ON + BUTTON_PRESS -> BLINKING
BLINKING + BUTTON_PRESS -> OFF
BLINKING + TIMER_EXPIRE -> ON
Print the current state as a string after handling an event
💡 Why This Matters
🌍 Real World
Event-driven state machines are used in embedded devices like remote controls, appliances, and IoT gadgets to manage behavior based on user input or timers.
💼 Career
Understanding event-driven state machines is essential for embedded software engineers working on firmware for hardware devices.
Progress0 / 4 steps
1
Define states and initial state
Define an enum called State with values OFF, ON, and BLINKING. Then create a variable called current_state of type State and set it to OFF.
Embedded C
Hint
Use typedef enum { OFF, ON, BLINKING } State; and then State current_state = OFF;.
2
Define events
Define an enum called Event with values BUTTON_PRESS and TIMER_EXPIRE.
Embedded C
Hint
Use typedef enum { BUTTON_PRESS, TIMER_EXPIRE } Event;.
3
Write event handler function
Write a function called handle_event that takes an Event parameter named event. Inside, use switch on current_state and nested switch on event to update current_state following these rules: OFF + BUTTON_PRESS -> ON, ON + BUTTON_PRESS -> BLINKING, BLINKING + BUTTON_PRESS -> OFF, BLINKING + TIMER_EXPIRE -> ON. Do nothing for other cases.
Embedded C
Hint
Use nested switch statements to check current_state and event, then update current_state accordingly.
4
Print current state after event
Write a main function that calls handle_event with BUTTON_PRESS, then prints the current state as a string. Then call handle_event with BUTTON_PRESS again and print the state. Finally, call handle_event with TIMER_EXPIRE and print the state. Use printf and a switch on current_state to print "OFF", "ON", or "BLINKING".
Embedded C
Hint
Call handle_event with the events in order, then print the state after each call using a switch and printf.
Practice
(1/5)
1. What is the main purpose of an event-driven state machine in embedded C?
easy
A. To change behavior based on events and current state
B. To execute code sequentially without conditions
C. To store large amounts of data in memory
D. To perform mathematical calculations only
Solution
Step 1: Understand the concept of event-driven state machine
An event-driven state machine changes its behavior depending on the current state and the events it receives.
Step 2: Compare options with the concept
To change behavior based on events and current state correctly describes this behavior. Other options describe unrelated concepts.
Final Answer:
To change behavior based on events and current state -> Option A
Quick Check:
Event-driven state machine = change behavior by events [OK]
Hint: Remember: state machines react to events and states [OK]
Common Mistakes:
Thinking state machines just run code sequentially
Confusing state machines with data storage
Assuming state machines only do math
2. Which of the following is the correct way to define states in an event-driven state machine using embedded C?
easy
A. int STATE_IDLE = 0; int STATE_RUN = 1; int STATE_STOP = 2;
B. #define STATE_IDLE 0 #define STATE_RUN 1 #define STATE_STOP 2
C. typedef enum {STATE_IDLE, STATE_RUN, STATE_STOP} State;
D. char* states[] = {"IDLE", "RUN", "STOP"};
Solution
Step 1: Identify proper enum syntax in embedded C
Using typedef enum with named states is the standard and clear way to define states.
Step 2: Check options for correctness and clarity
The typedef enum syntax is the preferred choice for type safety and readability. Using separate ints, #defines, or string arrays lacks these benefits and is less idiomatic.
Final Answer:
typedef enum {STATE_IDLE, STATE_RUN, STATE_STOP} State; -> Option C
Quick Check:
Use enum typedef for states [OK]
Hint: Use typedef enum for clear state names [OK]
Common Mistakes:
Using #define instead of enum for states
Using strings instead of enums for states
Not using typedef with enum
3. Given the following code snippet, what will be the value of current_state after handle_event(EVENT_START) is called?
typedef enum {STATE_IDLE, STATE_RUN, STATE_STOP} State;
typedef enum {EVENT_START, EVENT_STOP} Event;
State current_state = STATE_IDLE;
void handle_event(Event e) {
switch(current_state) {
case STATE_IDLE:
if (e == EVENT_START) current_state = STATE_RUN;
break;
case STATE_RUN:
if (e == EVENT_STOP) current_state = STATE_STOP;
break;
case STATE_STOP:
break;
}
}
handle_event(EVENT_START);
medium
A. Compilation error
B. STATE_RUN
C. STATE_STOP
D. STATE_IDLE
Solution
Step 1: Check initial state and event
The initial state is STATE_IDLE. The event passed is EVENT_START.
Step 2: Follow the switch-case logic
In STATE_IDLE, if event is EVENT_START, current_state changes to STATE_RUN.
Final Answer:
STATE_RUN -> Option B
Quick Check:
EVENT_START in STATE_IDLE moves to STATE_RUN [OK]
Hint: Trace event in current state switch-case [OK]
Common Mistakes:
Ignoring event condition inside the case
Assuming state changes without event match
Thinking code has syntax errors
4. Identify the bug in this event-driven state machine code snippet:
typedef enum {STATE_IDLE, STATE_RUN} State;
typedef enum {EVENT_START, EVENT_STOP} Event;
State current_state = STATE_IDLE;
void handle_event(Event e) {
switch(current_state) {
case STATE_IDLE:
if (e = EVENT_START) current_state = STATE_RUN;
break;
case STATE_RUN:
if (e == EVENT_STOP) current_state = STATE_IDLE;
break;
}
}
medium
A. State enum missing STATE_STOP
B. Missing default case in switch statement
C. current_state not initialized
D. Using assignment '=' instead of comparison '==' in if condition
Solution
Step 1: Inspect the if condition in STATE_IDLE case
The condition uses 'if (e = EVENT_START)', which assigns EVENT_START to e instead of comparing.
Step 2: Understand the effect of assignment in condition
Assignment returns the assigned value, which is non-zero, so condition is always true, causing incorrect state changes.
Final Answer:
Using assignment '=' instead of comparison '==' in if condition -> Option D
Quick Check:
Use '==' for comparison, not '=' [OK]
Hint: Check if conditions use '==' not '=' [OK]
Common Mistakes:
Confusing '=' and '==' in conditions
Ignoring missing default case (not critical here)
Assuming all states must be defined
5. You want to add a new state STATE_PAUSE and event EVENT_PAUSE to the existing state machine. Which code snippet correctly updates the handle_event function to handle pausing from STATE_RUN and resuming back to STATE_RUN from STATE_PAUSE?
hard
A. case STATE_RUN:
if (e == EVENT_PAUSE) current_state = STATE_PAUSE;
else if (e == EVENT_STOP) current_state = STATE_IDLE;
break;
case STATE_PAUSE:
if (e == EVENT_PAUSE) current_state = STATE_RUN;
break;
B. case STATE_RUN:
if (e == EVENT_PAUSE) current_state = STATE_IDLE;
break;
case STATE_PAUSE:
if (e == EVENT_PAUSE) current_state = STATE_STOP;
break;
C. case STATE_RUN:
if (e == EVENT_STOP) current_state = STATE_PAUSE;
break;
case STATE_PAUSE:
if (e == EVENT_PAUSE) current_state = STATE_IDLE;
break;
D. case STATE_RUN:
if (e == EVENT_PAUSE) current_state = STATE_STOP;
break;
case STATE_PAUSE:
if (e == EVENT_STOP) current_state = STATE_RUN;
break;
Solution
Step 1: Understand desired transitions
From STATE_RUN, EVENT_PAUSE should move to STATE_PAUSE. From STATE_PAUSE, EVENT_PAUSE should resume to STATE_RUN.
Step 2: Check each option for correct transitions
case STATE_RUN:
if (e == EVENT_PAUSE) current_state = STATE_PAUSE;
else if (e == EVENT_STOP) current_state = STATE_IDLE;
break;
case STATE_PAUSE:
if (e == EVENT_PAUSE) current_state = STATE_RUN;
break; matches these transitions exactly. Other options assign wrong states or events.
Final Answer:
case STATE_RUN:
if (e == EVENT_PAUSE) current_state = STATE_PAUSE;
else if (e == EVENT_STOP) current_state = STATE_IDLE;
break;
case STATE_PAUSE:
if (e == EVENT_PAUSE) current_state = STATE_RUN;
break; -> Option A
Quick Check:
Pause toggles between RUN and PAUSE states [OK]
Hint: Match events to correct state transitions carefully [OK]
Common Mistakes:
Assigning wrong states on pause/resume events
Confusing EVENT_PAUSE with EVENT_STOP
Missing else if for multiple events
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.