Ключевое слово volatile, известное как классификатор, обычно используется перед типом данными переменной, чтобы изменить способ, в котором компилятор и последующая программа рассматривают переменную.
Объявление переменной volatile является директивой для компилятора. Компилятор - это программное обеспечение, которое переводит ваш код C/C++ в машинный код, который является настоящей инструкцией для чипа Atmega в Arduino.
В частности, он указывает компилятору загружать переменную из ОЗУ, а не из регистра хранения, который является временной ячейкой памяти, где хранятся и обрабатываются программные переменные. При определенных условиях значение переменной, хранящейся в регистрах, может быть неточным.
Переменная должна объявляться volatile всякий раз, когда ее значение может быть изменено чем-то, находящимся вне контроля секции кода, в которой она появляется, например, параллельно выполняющимся потоком.
В Arduino единственное место, где это может произойти, это разделы кода, связанные с прерываниями, называемые подпрограммой обработки прерываний.
Если переменная volatile больше байта (например, 16-битное int или 32-битная длина), то микроконтроллер не может прочитать его за один такт, потому что это 8-битный микроконтроллер.
Это означает, что в то время как ваша основная часть кода (например, цикл) считывает первые 8 битов переменной, прерывание может уже изменить вторые 8 битов. Это даст случайные значения для переменной.
Пока переменная читается, прерывания должны быть отключены, чтобы они не могли связываться с битами, пока они читаются. Есть несколько способов сделать это.
// Переключает светодиод, когда вывод прерывания меняет состояние. int pin = 13; volatile byte state = LOW; void setup() { pinMode(pin, OUTPUT); attachInterrupt(digitalPinToInterrupt(2), blink, CHANGE); } void loop() { digitalWrite(pin, state); } void blink() { state = !state; }
Атомарные операции - это одиночные операции MCU - наименьшая возможная единица.
#include <util/atomic.h> // Эта библиотека включает в себя ATOMIC_BLOCK. volatile int input_from_interrupt; ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { // Код с заблокированными прерываниями // (последовательные атомарные операции не прерываются). int result = input_from_interrupt; }