Flag variables are not evil (for Microcontrollers)

Non-embedded programs shield your ears: flag variables are good

Fun With Flag Variables

Getting programming questions answered on the internet can be problematic. Programmers love to have opinions, stick to those ideas, and express them to you even when their opinion has nothing to do with your question(s).

Not only am I going to explain how to use flag variables in your code, I am going to encourage their use—which most programmers avoid.

However, this advice comes with two caveats.

  1. This information only applies to limited resource environments like an Arduino, LaunchPad or PIC.
  2. Use flag variables very carefully when you do use them.

The following flag variable usage examples are Arduino-centric but apply to any microcontroller platform, including the Energia project for TI Launchpads.

What are Flag Variables?

Flag variables are used to indicate a single state. Like an LED that needs to be “ON” or “OFF.” In fact, you’ll see in many of my mlllis() cookbook examples, I use a flag variable to indicate the state of an LED.

Here are a few places where you can use flag variables.

Flag Variables Case #1: Interrupts

When using interrupts you want to get in and out of the interrupt service routine (ISR) as fast as possible. An ISR is an excellent example of where you should use flag variables. When an ISR occurs, set a flag and exit. In the main loop() of your program, you check for the flag and do what needs to be done when you see it.

Example

// Flag variable
// ISRs require them to be "volatile"
volatile bool needToSend = false;

void setup() {
 Serial.begin(9600);
 // Interrupt 0 on Uno is Pin 2!
 attachInterrupt(0, printText, CHANGE);
}

void loop() {
 if (needToSend) {
 // send our very long message
 Serial.println("Pin 2 changed states, thought you should know... kthxbye");
 // clear the flag
 needToSend = false;
 }
}

// ISR for Interrupt 0
void printText() {
 // Set the flag and get out
 needToSend = true;
}

In this (contrived) example, when an interrupt occurs on Pin 2, we send a very long message over serial. You would not want to sit in the ISR waiting for this transmit to finish.

Note, Arduino’s library already uses an interrupt based transmit buffer. However, issues can occur trying to start a serial from the interrupt.

Flag Variables Case #2: Simplify Yes / No Operations

Often when reading multiple sensors, you may have one function or loop that speeds through all of the available inputs. If your code only needs to act if one of the inputs change, you could use a flag variable to indicate a the change. The flag would prevent you from having to run through another loop checking all the results.

Good practices when using flags:

  • Make name yes/no question.
  • When you read the code, its meaning should be obvious.
  • Don’t use a flag when something else could have worked, like an enum.

Example

// Flag Variable
bool inputChanged = false;

int currentValues[6];
int previousValues[6];

void setup() {
 // Just want to toggle something
 pinMode(13, OUTPUT);

 // load variables with known values
 for (int i = 0; i < 6; i++) {
 currentValues[i] = 0;
 previousValues[i] = 0;
 }
}

void loop() {
 // Read A0..A5, compare to last read
 for (int x = 0; x < 6; x++) {
 currentValues[x] = analogRead(x);
 if (currentValues[x] != previousValues[x])
 inputChanged = true;
 // Store previous for next check
 previousValues[x] = currentValues[x];
 }
 if (inputChanged) {
 // Just toggle LED, kinda lame, I know
 digitalWrite(13, !digitalRead(13));
 // Don't forget to clear
 inputChanged = false;
 }
}

Flag Variables Case #3: Don’t use flags, use states

A close cousin to a flag variable is the state. While a flag is a single state event, which is probably fine for something like an “ON” or “OFF”. However, think about blinking an LED. You might say “either I want it to blink or not blink.” However, there are four states: “Blinking,” “ON,” “OFF,” and “Not Blinking.”

One option is, of course, to have two flag variables. One called shouldBlink and blinkState. Another option is to use an enumerated type, also known as, enum. It’s probably better to save enums and state machines for another post.

Question: What’s an embedded programming problem you could only solve using flag variables? You can leave a comment by clicking here.

Your questions, comments, and even corrections are encouraged and very much appreciated! However. I have zero-tolerance for inappropriate or harassing comments. I try to reply to everyone... -James

Leave a comment

7 thoughts on “Flag variables are not evil (for Microcontrollers)

  1. Thanks – another topic that I feel you’ve hit perfectly on the head.

    Another scenario that I’ve use flags for, is where a number of events can trigger a single action – for example (to contrive an example) if a button press, or a specific character over the UART, or a time-based event could all cause a warning LED to light up. To make the code easier to read, I would set a flag (warningLED) that then gets processed later in the routine to turn the LED on. This can make it clearer that all these events result in the same outcome.

    Cheers
    @crashbang_proto

  2. Thanks for this review of flag variables! I’ve used them before but wasn’t aware that people disparaged them. In any case, I appreciate the examples.

    It looks like there are couple typos in your code:

    First code block:
    * line 1: starts with , which I’m guessing leaked over from the HTML.

    Second code block:
    * line 12: did you mean to leave the final values in the two arrays unassigned?
    * line 21: I assume you’re modeling this to run on an Uno, in which case you can’t do analogRead on pins 0 through 5, which are not the same as A0–A5. One quick fix would be to analogRead(x+14) since A0 is pin 14 on the Uno.

    Also in line 29 of the second block, I’ve never seen that way of compacting a state change into a single digitalWrite command—very clever! I’ll hope to use that in the future.

    • * line 12: did you mean to leave the final values in the two arrays unassigned?
      Nope, fixed. Thanks!

      you can’t do analogRead on pins 0 through 5
      Yes, you can. analogRead() is smart enough to know that if you pass it anything less than 14, to use the analog pins. So 0 through 5 automatically translate to A0 (14) to A5 (19).

        • Another trick (and what I should have done) was to simply do:

          for (int x=A0; x<A6; x++)
           int reading = analogRead(x);
          

          This works because A6 is defined (SMT versions of the ATmega328 have 6 analog pins) and A0..A6 are defined as ints anyway. But I think that might actually be a bit more confusing than just saying 0..6.