How to Use Volatile Variables in Arduino?

ArduinoHardwareSoftware & Coding

Just like in C and C++, you need to qualify a variable with the volatile keyword if it can be modified within an interrupt routine.

When you qualify a variable as volatile, this is what happens behind the scenes −

  • The compiler gets instructed that the variable should be loaded into the RAM and not the storage register (where program variables are generally stored/manipulated)

  • This ensures that any changes to the variable outside of the loop() (for example in the interrupt service routine), get immediately reflected in the loop()

If you have a variable larger than a byte in size (int or long), then an 8-bit microcontroller, like in Arduino Uno, will read the variable in steps of 8 bytes each. This can cause a problem (the next 8 bytes of the variable may have changed while the microcontroller was reading the first 8 bytes). This can cause some random errors. To avoid that, you can use one of the following approaches −

  • Use the ATOMIC_BLOCK macro (this converts the read operation to an atomic operation, wherein the contents cannot be altered while being read). You will need to include <util/atomic.h> for this, and the syntax is given here.

  • Disable interrupts using noInterrupts() while the variable is being read.

Example

An example with volatile variables is given below −

#include <util/atomic.h>
volatile int flag = 0;
int flagValue = 0;
void setup() {
   Serial.begin(9600);
   pinMode(LED_BUILTIN, OUTPUT);
   attachInterrupt(digitalPinToInterrupt(2), interruptFunction, CHANGE);
}
void loop() {
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
      // code with interrupts blocked (consecutive atomic operations will
not get interrupted)
      flagValue = flag;
   }
   if (flagValue == 1) {6305298009
      flag = 0;
      flagValue = 0;
      Serial.println("Interrupt encountered!");
   }
}
void interruptFunction() {
   flag = 1;
}

Note that only flag has been defined as volatile, because it is the only variable whose value changes within the interrupt. The same code as above, using noInterrupts() would look like −

volatile int flag = 0;
int flagValue = 0;
void setup() {
   Serial.begin(9600);
   pinMode(LED_BUILTIN, OUTPUT);
   attachInterrupt(digitalPinToInterrupt(2), interruptFunction, CHANGE);
}
void loop() {
   noInterrupts();
   flagValue = flag;
   interrupts();
   if (flagValue == 1) {
      flag = 0;
      flagValue = 0;
      Serial.println("Interrupt encountered!");
   }
}
void interruptFunction() {
   flag = 1;
}
raja
Published on 24-Jul-2021 14:25:16
Advertisements