- This information only applies to limited resource environments like an Arduino, LaunchPad or PIC.
- Use flag variables very carefully when you do use them.
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.What’s an embedded programming problem you could only solve using flag variables?
9 Comments
I think it would be a good idea to extract the array length, maybe to a `const int VAL_COUNT = 6`
is there a video on explaining how to use flags on microcontrollers?
Last year I wrote about global variables in a similar vein.
http://nerdralph.blogspot.ca/2014/08/global-variables-are-good.html
Excellent write-up. This is definitely another “evil” new embedded programmers need to understand.
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
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).
Huh! News to me—I stand corrected. Another very useful tidbit to pick up from your examples. Thanks!
Another trick (and what I should have done) was to simply do:
[arduino]
for (int x=A0; x<A6; x++)
int reading = analogRead(x);
[/arduino]
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.