Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Arduino & Microcontrollers

Arduino Finite State Machine: Writing Cleaner Code for Complex Projects

Arduino Finite State Machine: Writing Cleaner Code for Complex Projects

March 11, 2026 /Posted byJayesh Jain / 0

As your Arduino projects grow beyond a few if statements, keeping your code maintainable becomes a real challenge. The Arduino finite state machine (FSM) design pattern is the single most effective technique for organising complex, event-driven embedded code. Whether you’re building a vending machine controller, a traffic light system, or a multi-mode robot, FSMs make your code predictable, testable, and easy to extend.

Table of Contents

  • What Is a Finite State Machine?
  • Why Use FSM on Arduino?
  • Implementing a Basic FSM with switch-case
  • FSM with Function Pointers
  • Entry and Exit Actions
  • Real-World Example: Vending Machine Controller
  • Arduino FSM Libraries
  • Frequently Asked Questions

What Is a Finite State Machine?

A Finite State Machine is a mathematical model of computation with four key components:

  1. States — A finite set of distinct conditions the system can be in. At any moment, the system is in exactly one state.
  2. Events (Inputs) — Triggers that can cause a state transition (button press, timer expiry, sensor threshold crossed).
  3. Transitions — Rules that define which state to move to when a specific event occurs in a specific state.
  4. Actions — Code that runs on entry to a state, during a state, or on exit from a state.

A classic example: a traffic light. It has three states (RED, YELLOW, GREEN), one event (timer expired), and transitions between them in a fixed sequence. The FSM ensures the light never jumps from RED directly to GREEN — the rules enforce valid sequences.

Why Use FSM on Arduino?

Before FSMs, most beginners write code that looks like this — nested if conditions that try to handle every combination of inputs and current state simultaneously:

// The "spaghetti code" approach (avoid this!)
void loop() {
  if (buttonPressed && !motorRunning && !alarmActive) {
    startMotor();
  } else if (buttonPressed && motorRunning) {
    stopMotor();
  } else if (alarmActive && motorRunning) {
    stopMotor();
    soundAlarm();
  } else if (alarmActive && !motorRunning) {
    soundAlarm();
  }
  // ... 50 more conditions ...
}

This approach breaks down quickly because:

  • Adding a new state requires touching every existing condition
  • Testing all possible condition combinations is exponentially hard
  • Timing bugs appear when the system briefly passes through invalid states
  • Understanding the code’s intent becomes impossible

An FSM replaces this with a clear diagram and structured code where each state handles only its own concerns.

Recommended: Arduino Uno R3 Beginners Kit — Includes a breadboard and components for building the FSM examples in this guide, including buttons, LEDs, and a buzzer for interactive state machine demos.

Implementing a Basic FSM with switch-case

The simplest Arduino FSM uses an enum for states and a switch statement in the loop to dispatch logic per state. Let’s model a simple door lock with a keypad:

// States
enum State {
  STATE_LOCKED,
  STATE_ENTERING_CODE,
  STATE_UNLOCKED,
  STATE_ALARM
};

// Events
enum Event {
  EVT_NONE,
  EVT_KEYPRESS,
  EVT_CORRECT_CODE,
  EVT_WRONG_CODE,
  EVT_TIMEOUT,
  EVT_LOCK_BUTTON
};

State currentState = STATE_LOCKED;
Event currentEvent = EVT_NONE;
unsigned long stateEnteredAt = 0;

void setState(State newState) {
  currentState = newState;
  stateEnteredAt = millis();
}

void loop() {
  currentEvent = getEvent();  // Poll buttons/sensors for events

  switch (currentState) {

    case STATE_LOCKED:
      // Display "Locked" on LCD
      if (currentEvent == EVT_KEYPRESS) {
        setState(STATE_ENTERING_CODE);
      }
      break;

    case STATE_ENTERING_CODE:
      // Collect keypad input
      if (currentEvent == EVT_CORRECT_CODE) {
        setState(STATE_UNLOCKED);
      } else if (currentEvent == EVT_WRONG_CODE) {
        setState(STATE_ALARM);
      } else if (millis() - stateEnteredAt > 10000) {
        // 10-second entry timeout
        setState(STATE_LOCKED);
      }
      break;

    case STATE_UNLOCKED:
      // Activate solenoid, display "Open"
      if (currentEvent == EVT_LOCK_BUTTON ||
          millis() - stateEnteredAt > 5000) {
        setState(STATE_LOCKED);
      }
      break;

    case STATE_ALARM:
      // Sound buzzer, flash LED
      if (millis() - stateEnteredAt > 30000) {
        setState(STATE_LOCKED);  // Auto-reset after 30s
      }
      break;
  }
}

Notice how each case in the switch statement only has to worry about what happens in that state. The code for STATE_UNLOCKED doesn’t need to know anything about STATE_ALARM. This separation is the core benefit of the FSM pattern.

FSM with Function Pointers

For more complex FSMs, the switch-case approach grows unwieldy. A table-driven FSM uses a 2D array of function pointers — one dimension for states, one for events — to look up and call the appropriate transition function directly:

#define NUM_STATES 4
#define NUM_EVENTS 6

// Forward declarations
void doNothing();
void startCodeEntry();
void unlockDoor();
void triggerAlarm();
void lockDoor();
void timeoutToLocked();

// Transition table: transitionTable[state][event] = function to call
typedef void (*TransitionFn)();
TransitionFn transitionTable[NUM_STATES][NUM_EVENTS] = {
//             NONE         KEYPRESS          CORRECT          WRONG           TIMEOUT          LOCK
/* LOCKED */   {doNothing,  startCodeEntry,   doNothing,       doNothing,      doNothing,       doNothing},
/* ENTERING */ {doNothing,  doNothing,        unlockDoor,      triggerAlarm,   timeoutToLocked, doNothing},
/* UNLOCKED */ {doNothing,  doNothing,        doNothing,       doNothing,      lockDoor,        lockDoor},
/* ALARM */    {doNothing,  doNothing,        doNothing,       doNothing,      lockDoor,        doNothing},
};

void loop() {
  Event event = getEvent();
  // Call the transition function for the current state and event
  transitionTable[currentState][event]();
}

This approach scales cleanly to dozens of states and events. Adding a new event means adding one column; adding a new state means adding one row. The logic remains contained in small, individually testable functions.

Entry and Exit Actions

Professional FSM implementations distinguish between three types of actions:

  • Entry action: Runs once when entering a state (initialise a timer, turn on an LED, play a tone)
  • Do/During action: Runs repeatedly while in the state (read sensors, update display)
  • Exit action: Runs once when leaving a state (turn off LED, save data)
void enterUnlocked() {
  digitalWrite(SOLENOID_PIN, HIGH);  // Entry: open lock
  lcd.print("OPEN");
  stateEnteredAt = millis();
}

void duringUnlocked() {
  // During: auto-lock after 5 seconds
  if (millis() - stateEnteredAt > 5000) {
    exitUnlocked();
    enterLocked();
    currentState = STATE_LOCKED;
  }
}

void exitUnlocked() {
  digitalWrite(SOLENOID_PIN, LOW);  // Exit: close lock
}
Recommended: Arduino Mega 2560 R3 Board — Complex FSMs with many states benefit from the Mega’s additional memory (8 KB RAM vs 2 KB on Uno) and multiple serial ports for debugging state transitions.

Real-World Example: Vending Machine Controller

Here’s a simplified vending machine FSM that demonstrates a complete, practical implementation:

enum VendState {
  VEND_IDLE,
  VEND_COIN_INSERTED,
  VEND_SELECTION_MADE,
  VEND_DISPENSING,
  VEND_RETURNING_CHANGE
};

VendState vendState = VEND_IDLE;
int balance = 0;
int itemCost = 0;
unsigned long dispenseStarted = 0;

void loop() {
  switch (vendState) {

    case VEND_IDLE:
      showIdleScreen();
      if (coinDetected()) {
        balance += readCoinValue();
        vendState = VEND_COIN_INSERTED;
      }
      break;

    case VEND_COIN_INSERTED:
      displayBalance(balance);
      if (itemSelected()) {
        itemCost = getItemCost(selectedItem());
        if (balance >= itemCost) {
          vendState = VEND_SELECTION_MADE;
        } else {
          displayInsufficient();
        }
      }
      if (refundPressed()) {
        vendState = VEND_RETURNING_CHANGE;
      }
      break;

    case VEND_SELECTION_MADE:
      balance -= itemCost;
      activateMotor();
      dispenseStarted = millis();
      vendState = VEND_DISPENSING;
      break;

    case VEND_DISPENSING:
      if (millis() - dispenseStarted > 2000) {
        stopMotor();
        if (balance > 0) {
          vendState = VEND_RETURNING_CHANGE;
        } else {
          vendState = VEND_IDLE;
        }
      }
      break;

    case VEND_RETURNING_CHANGE:
      returnCoins(balance);
      balance = 0;
      vendState = VEND_IDLE;
      break;
  }
}

Every state has a clear purpose, every transition is explicit, and the code reads almost like the design document itself.

Arduino FSM Libraries

Several libraries abstract the FSM boilerplate so you can focus on your state logic:

  • Arduino-fsm — Simple, event-driven FSM with on-enter/on-state/on-exit callbacks. Install from Library Manager.
  • StateMachine — Supports hierarchical state machines (a state within a state) for very complex systems.
  • Automaton — Full reactive state machine framework with built-in debouncing, timers, and event queuing.

Example using the Arduino-fsm library:

#include <Fsm.h>

State stateLocked(&onLockEnter, &onLockDuring, NULL);
State stateUnlocked(&onUnlockEnter, &onUnlockDuring, &onUnlockExit);

Fsm fsm(&stateLocked);

#define EVT_CORRECT 1
#define EVT_TIMEOUT 2

void setup() {
  fsm.add_transition(&stateLocked, &stateUnlocked, EVT_CORRECT, NULL);
  fsm.add_timed_transition(&stateUnlocked, &stateLocked, 5000, NULL);
}

void loop() {
  if (codeCorrect()) fsm.trigger(EVT_CORRECT);
  fsm.run_machine();
}
Recommended: Arduino Nano Every with Headers — The Nano Every’s ATmega4809 provides 6 KB RAM and hardware-accelerated peripherals, giving more headroom for FSMs with many states and transition tables.

Frequently Asked Questions

How many states can an Arduino FSM have?

There’s no hard limit from the FSM pattern itself — the practical limit is your Arduino’s memory. An enum state + small struct per state is just a few bytes. A 100-state machine on an Arduino Uno is feasible as long as the code for each state is kept compact. The Mega is better for large FSMs.

Can I use FSM with interrupts?

Yes. The common pattern is to have the ISR set a volatile event flag, and the main loop polls that flag and feeds it into the FSM as an event. Never trigger FSM transitions directly inside an ISR — ISRs must be short and interrupt-safe.

What’s the difference between FSM and a hierarchical state machine (HSM)?

An HSM (Hierarchical State Machine) allows states to be nested inside other states. A sub-state inherits default transitions from its parent. This avoids repeating common transitions in every state of a group. The StateSmith and QP frameworks implement HSMs for embedded systems.

Is an FSM suitable for real-time control loops?

FSMs are excellent for mode management and sequencing but aren’t typically used as the inner real-time control loop. A common architecture: outer FSM manages modes (IDLE, RUNNING, ERROR), and within the RUNNING state, a fast control loop (PID, stepper driver, etc.) executes independently.

How do I visualise my FSM during development?

Draw a state diagram before writing any code. Free tools: draw.io, Lucidchart, or even paper. Add state transition debug output: Serial.print("→ STATE_UNLOCKED") every time you change state. Some teams auto-generate state diagrams from code using PlantUML.

Build smarter Arduino projects — Browse our full selection of Arduino boards and development tools at Zbotic. From beginner kits to advanced Mega boards, we have everything for your next FSM-powered project.

Tags: Arduino, clean code, embedded programming, finite state machine, FSM, state machine
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Arduino Oscilloscope: Turn You...
blog arduino oscilloscope turn your board into a signal analyzer 594662
blog arduino eeprom save data permanently without sd card 594664
Arduino EEPROM: Save Data Perm...

Related posts

Blog Arduino Batch Programming Flash Multiple Boards Quickly 614734 Medium
Read more

Arduino Batch Programming: Flash Multiple Boards Quickly

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Blog Arduino Based Radar System With Ultrasonic Sensor 614731 Medium
Read more

Arduino Based Radar System with Ultrasonic Sensor

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Blog Arduino Automatic Plant Monitor Sunlight Moisture Temperature 614727 Medium
Read more

Arduino Automatic Plant Monitor: Sunlight, Moisture, Temperature

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Blog Arduino Lie Detector Gsr Sensor Polygraph Project 614720 Medium
Read more

Arduino Lie Detector: GSR Sensor Polygraph Project

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading
Blog Arduino Metal Detector Build A Treasure Finder 614714 Medium
Read more

Arduino Metal Detector: Build a Treasure Finder

April 1, 2026 0
Table of Contents Introduction Components and Hardware Setup Wiring Diagram and Connections Complete Code with Explanation Customization and Improvements Troubleshooting... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now