0
0
AutocadHow-ToBeginner · 4 min read

How to Create a State Machine in Arduino: Simple Guide

To create a state machine in Arduino, define states using an enum and use a switch statement inside loop() to handle each state. Change states by updating the state variable based on conditions or events.
📐

Syntax

Use an enum to list all possible states. Declare a variable to hold the current state. Inside the loop(), use a switch statement to run code for each state. Change the state variable to move between states.

  • enum State: Defines all states.
  • State currentState: Holds current state.
  • switch(currentState): Runs code for each state.
  • currentState = NEW_STATE; Changes state.
arduino
enum State {
  STATE_ONE,
  STATE_TWO,
  STATE_THREE
};

State currentState = STATE_ONE;

void setup() {
  // Initialize things here
}

void loop() {
  switch (currentState) {
    case STATE_ONE:
      // Code for state one
      // Change state when needed
      // currentState = STATE_TWO;
      break;
    case STATE_TWO:
      // Code for state two
      // currentState = STATE_THREE;
      break;
    case STATE_THREE:
      // Code for state three
      // currentState = STATE_ONE;
      break;
  }
}
💻

Example

This example shows a simple state machine that turns an LED on and off every second using three states: LED_OFF, LED_ON, and WAIT.

arduino
enum State {
  LED_OFF,
  LED_ON,
  WAIT
};

State currentState = LED_OFF;
const int ledPin = 13;
unsigned long previousMillis = 0;
const unsigned long interval = 1000; // 1 second

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();
  switch (currentState) {
    case LED_OFF:
      digitalWrite(ledPin, LOW);
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;
        currentState = LED_ON;
      }
      break;

    case LED_ON:
      digitalWrite(ledPin, HIGH);
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;
        currentState = LED_OFF;
      }
      break;

    case WAIT:
      // Not used in this example
      break;
  }
}
Output
The LED on pin 13 turns ON for 1 second, then OFF for 1 second, repeating continuously.
⚠️

Common Pitfalls

Common mistakes when creating state machines in Arduino include:

  • Not updating the state variable, causing the machine to get stuck in one state.
  • Using delay() inside states, which blocks the program and stops state changes.
  • Not handling all states in the switch, leading to unexpected behavior.
  • Forgetting to initialize variables like timers, causing timing errors.

Always use non-blocking code like millis() for timing and ensure every state can transition properly.

arduino
/* Wrong: Using delay() blocks state changes */
void loop() {
  switch (currentState) {
    case LED_OFF:
      digitalWrite(ledPin, LOW);
      delay(1000); // Blocks everything
      currentState = LED_ON;
      break;
    case LED_ON:
      digitalWrite(ledPin, HIGH);
      delay(1000); // Blocks everything
      currentState = LED_OFF;
      break;
  }
}

/* Right: Use millis() for non-blocking timing */
unsigned long previousMillis = 0;
const unsigned long interval = 1000;
void loop() {
  unsigned long currentMillis = millis();
  switch (currentState) {
    case LED_OFF:
      digitalWrite(ledPin, LOW);
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;
        currentState = LED_ON;
      }
      break;
    case LED_ON:
      digitalWrite(ledPin, HIGH);
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;
        currentState = LED_OFF;
      }
      break;
  }
}
📊

Quick Reference

Tips for creating state machines in Arduino:

  • Use enum for clear state names.
  • Use a switch statement to handle states.
  • Use millis() for timing, avoid delay().
  • Always update the state variable to move between states.
  • Keep state code short and focused on one task.

Key Takeaways

Define states with an enum and track the current state with a variable.
Use a switch statement inside loop() to run code for each state.
Avoid delay(); use millis() for non-blocking timing in state transitions.
Always update the state variable to move between states.
Keep state code simple and handle all possible states.