Building a Simple State Machine for Embedded Systems


Published March 3, 2025, 6 a.m. by Job Daniels

Introduction

In embedded systems, managing different states of operation efficiently is critical. A state machine is a fundamental tool that helps in designing structured, predictable, and maintainable code. Whether you are working on motor control, user interfaces, or communication protocols, a well-implemented state machine ensures robustness and clarity in your software.

This blog will cover everything you need to know about state machines in embedded systems, including:

  - What is a state machine?

  - Types of state machines

  - Designing a simple state machine

  - Implementing a state machine in C

  - Best practices and optimizations

What is a State Machine?

A state machine, also called a finite state machine (FSM), is a computational model that transitions between a finite number of states based on inputs or events. It consists of:

  • States: Represent different conditions of the system.
  • Transitions: Define movement from one state to another.
  • Events/Inputs: Triggers that cause transitions.
  • Actions: Operations performed in each state.

Example: State Machine for a Traffic Light System

A simple example of an FSM is a traffic light system, which has three states:

  1. Red → Wait
  2. Green → Go
  3. Yellow → Slow down

Each state transitions to another after a predefined time or based on an external trigger, such as a pedestrian button press.

Types of State Machines

There are two primary types of state machines:

1. Moore State Machine

  • The output depends only on the current state.
  • Transitions are triggered by inputs, but outputs remain the same until the state changes.
  • Example: A vending machine that dispenses a product only when a specific state is reached.

2. Mealy State Machine

  • The output depends on both the current state and inputs.
  • More flexible but can be harder to debug.
  • Example: A keypad lock system where the output (unlocking the door) depends on the current input sequence.

Designing a Simple State Machine

Let’s design a state machine for a push-button controlled LED:

  • State 1: LED is OFF.
  • State 2: LED is ON.
  • Transition: Pressing the button toggles the LED state.

State Transition Table

Current State Input (Button Pressed) Next State Output
LED OFF Yes LED ON Turn LED ON
LED ON Yes LED OFF Turn LED OFF

State Diagram

Thumbnail Image

Implementing a Simple State Machine in C

#include <stdio.h>
#include <stdbool.h>

// Define states
typedef enum {
    LED_OFF,
    LED_ON
} State;

// Function to simulate button press
bool button_pressed() {
    static int press_count = 0;
    press_count++;
    return (press_count % 2 == 1); // Simulates alternating button presses
}

int main() {
    State currentState = LED_OFF;

    while (1) {
        switch (currentState) {
            case LED_OFF:
                printf("LED is OFF\\n");
                if (button_pressed()) {
                    currentState = LED_ON;
                }
                break;

            case LED_ON:
                printf("LED is ON\\n");
                if (button_pressed()) {
                    currentState = LED_OFF;
                }
                break;
        }
    }
    return 0;
}
        

Explanation:

  • We define the possible states using an enum.
  • The switch-case statement ensures that only one state is active at a time.
  • A function button_pressed() simulates the button press input.
  • The loop checks the current state and transitions accordingly.

Best Practices for Implementing State Machines

  1. Use Enums for Readability
  2. Using enum for state representation makes the code easier to understand and maintain.

  3. Avoid Too Many Nested If-Else Conditions

  4. A switch-case or function pointers are better alternatives for clear state transitions.

  5. Separate Logic from State Handling

  6. Keep state transition logic separate from actions to maintain modularity.

  7. Use a Timer for Time-Based Transitions

  8. When dealing with real-world applications, consider using a hardware timer or software delay for automatic state transitions.

  9. Implement Debugging Mechanisms

  10. Adding logs or debugging LEDs can help track state transitions in real-time.

Optimizing State Machines in Embedded Systems

  1. Use Function Pointers for State Execution
  2. Instead of switch-case, function pointers allow calling the function corresponding to the current state dynamically.

  3. Use Lookup Tables

  4. Reduces the complexity of state transitions by predefining state changes in a table.

  5. Finite State Machine (FSM) Libraries

  6. There are FSM libraries like QP Framework that help implement hierarchical state machines with ease.

Applications of State Machines in Embedded Systems

State machines are widely used in various embedded applications:

    - Communication Protocols: UART, SPI, and I2C controllers.

    - User Interfaces: Menu navigation in embedded GUIs.

    - Motor Control: BLDC and stepper motor speed control.

    - Power Management: Battery charging and sleep modes in low-power devices.

    - Robotics: Robot motion control and autonomous navigation.

Conclusion

State machines provide a structured approach to managing system behavior in embedded applications. By understanding different types of state machines, implementing them effectively in C, and following best practices, you can build efficient and maintainable embedded systems.

Whether you are designing an IoT device, a robotic controller, or a power management system, mastering state machines will significantly improve your coding efficiency and system reliability.

You can leave a comment below

Happy coding!

Similar posts


Comment on this post


?