Microcontroller state machine with enum tutorial

state-machine-with-enum-tutorial

Flag variables are great, and totally not evil, when you just have two states: ON or OFF. What about when you have multiple states? Is there an option better than creating multiple flag variables?

The C-language has a declaration type just for this purpose. It is called an enumeration, or enum.

Setting up a state machine with enum is a surprisingly simple. Arduino and embedded programmers should use them!

All you need to do is create descriptive tag names, and let the compiler assign them an integer value. Unlike a #define which is just a macro replacement, the compiler treats an enum as your personal variable type.

This behavior comes in handy when you’re creating states for a state machine. I show how to create a simple state machine with enum, to blink an LED with millis(), in this post.

Creating States

Start by thinking about the “states” that this LED will go through. We want it to blink. So that means either it’ll be blinking or not blinking. How many states can you count? You might think, “that’s easy, it’s 2! BLINK and NOT_BLINK.” That is true, but only half of them.

What about the actual blinking? When the LED should be “blinking”, in code that means the LED itself will be ON and OFF. So that’s two more states for our LED.

Creating an enum

Here are the four states the LED can exist in: Blinking_enabled, Blinking_disabled, LED_on, and LED_off. Here is how to create the enum, named “blinkStates”, with those 4 states.

enum blinkStates {
  BLINK_DIS, // blink disable
  BLINK_EN, // blink enable
  LED_ON, // we want the led to be on for interval
  LED_OFF // we want the led to be off for interval
};

Just like the compiler knows what an “int” or “float” is, now it knows what a “blinkStates” variable type is. This new variable type isn’t very useful yet, because we need to create a variable of this type.

enum blinkStates ledState;

Example State Machine with enum Code

Now that we’ve defined our state machine and enum, we need some code to go with it. Here’s a relatively simple example. One character Serial commands will control whether or not to blink the LED. Using millis() to control the rate of blinking, mean we will never miss a command. You could easily swap out the serial code for push buttons. (This is why millis() makes it appear like you can multitask on an Arduino.)

enum blinkStates {
  BLINK_DIS, // blink disable
  BLINK_EN, // blink enable
  LED_ON, // we want the led to be on for interval
  LED_OFF // we want the led to be off for interval
};

enum blinkStates ledState;
const int ledPin = 13;
long interval = 1000;
unsigned long previousMillis = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  unsigned long currentMillis = millis();

  // use ! and + characters to control the blinking.
  if (Serial.available() > 0) {
    char incomingByte = Serial.read();
    // turn off LED
    if (incomingByte == '!')
      ledState = BLINK_DIS;

    // turn on LED
    if (incomingByte == '+')
      ledState = BLINK_EN;
  }

  // enums are just integers, so let's see if
  // it has been enabled.
  if (ledState > BLINK_DIS) {
    if ((unsigned long)(currentMillis - previousMillis >= interval)) {
      // enough time has passed, let's change the state of the LED.
      if (ledState == LED_ON) {
        // time to turn off the LED
        ledState = LED_OFF;
        digitalWrite(ledPin, LOW);
      } else {
        // time to turn on the LED
        ledState = LED_ON;
        digitalWrite(ledPin, HIGH);
      }
      // reset our timer
      previousMillis = currentMillis;
    }
  } else if (ledState == BLINK_DIS) {
    // blinking is disabled, so turn off LED
    digitalWrite(ledPin, LOW);
  }
}
// Code by [email protected]
// More at: https://www.baldengineer.com/state-machine-with-enum-tutorial.html

Looking deeper at our enum

One line of code in this program is critical to understand, and it is this if-statement:

if (ledState > BLINK_DIS) {

Remember that enums are just integers. So we can use them as if we assigned each of our “states” an integer number. Since BLINK_DIS appears first in the enum’s list, it is assigned the lowest integer.

The simple if-statement just checks if the LED is active. The code’s logic assumes that if the state is not BLINK_DIS, something should be happening.

What is inside of an enum

This code example illustrates the simplicity of an enum. We will print out the values for each of our states.

enum blinkStates {
  BLINK_DIS, // blink disable
  BLINK_EN, // blink enable
  LED_ON, // we want the led to be on for interval
  LED_OFF // we want the led to be off for interval
};

enum blinkStates ledState;

void setup() {
  delay(1000);
  Serial.begin(9600);
  Serial.println(F("---------"));
  Serial.print(F("BLINK_DIS = "));
  Serial.println(BLINK_DIS);

  Serial.print(F("BLINK_EN = "));
  Serial.println(BLINK_EN);

  Serial.print(F("LED_ON = "));
  Serial.println(LED_ON);

  Serial.print(F("LED_OFF = "));
  Serial.println(LED_OFF);
}

void loop() { }
// Code by [email protected]
// More at: https://www.baldengineer.com/state-machine-with-enum-tutorial.html

When I run it on my Arduino Uno and my MSP430 based Launchpad, I get the following results.

---------
BLINK_DIS = 0
BLINK_EN = 1
LED_ON = 2
LED_OFF = 3

So what you can see with this example is that C is using integers to represent our simple to use names.

Question: What is a coding situation you could have used an enum to simply your logic? You can leave a comment by clicking here.

Long comments, URLs, and code tend to get flagged for spam moderation. No need to resubmit.

Leave a comment

7 thoughts on “Microcontroller state machine with enum tutorial

  1. Another tip.

    You can also set the values of the enum items to specific values if you wish, i.e.

    enum blinkStates {
      BLINK_DIS = 1,
      BLINK_EN = 10,
      LED_ON, 
      LED_OFF
    };
    

    This is handy if you have a group of specific values you need to use. Probably more related to enums in general than states.

    The other good thing about using enums/states is that it makes you consider all states and transitions which are easily missed if done otherwise.

  2. I’ve used enum to represent a state machine and that made the flow logic simpler and clearer to read. I also seen it used for representing different colours.
    When you say “Remember that enums are just integers” does the complier find the smallest integer type that the enum will fit into? Would I be correct in thinking that there’s no bounds checking so I could assign an invalid value?

    • Good questions. I don’t know the C-standards well enough to know if the compiler will change variable types on an out of bounds condition. Would be interesting to do some experiments.

      • The Arduino compiler lets you put whatever value you like into the variable – not just the listed Enum values – as long as it’s integer.

        This kind of defeats some of the value of using it over just defining a list of “states” in “#Define” or “const” statements.