Menu
CoddyTech

Общий доступ с volatile

Часть раздела Отсчёт времени без delay путешествия по Arduino на Coddy. Урок 14 из 18.

ISR должна выполнять одно быстрое действие, поэтому обычно она задаёт переменную, которую затем считывает остальная часть скетча. Переменная, используемая обеими частями, должна быть объявлена как volatile:

volatile bool started = false;

void onPress() {
  started = true;
}

Чтобы сэкономить время, компилятор (программа, которая преобразует ваш код C++ в инструкции для микросхемы) может хранить копию переменной внутри процессора, а не считывать её из памяти. Он не знает, что прерывание может изменить переменную, поэтому скетч может использовать старую копию бесконечно. volatile заставляет его каждый раз считывать актуальное значение переменной.

Этот скетч ожидает в setup() с помощью цикла while: while (condition) { } повторяет инструкции в фигурных скобках, пока условие истинно; здесь это !started. Как и в разделе «Входы», ! означает «не»: цикл повторяется, пока started имеет значение false. Без volatile ожидание может продолжаться вечно, даже после нажатия.

challenge icon

Задание

Легко

Этот скетч должен ждать нажатия кнопки, а затем мигать светодиодом. Сейчас он ждёт бесконечно. Исправь это:

  • в onPress() присвой started значение true
  • объяви started как volatile

Нажми Run, нажми кнопку, а затем Check. Попробуй один раз без volatile, чтобы увидеть, как плата зависнет.

Попробуйте сами

const int ledPin = 13;
const int buttonPin = 2;

bool started = false;   // устанавливается обработчиком прерывания, считывается скетчем

unsigned long previousMillis = 0;
int ledState = LOW;

void onPress() {
  // здесь присвойте started значение true
}

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(buttonPin), onPress, FALLING);

  // ждите здесь, пока не будет нажата кнопка
  while (!started) {
  }
}

void loop() {
  // мигайте каждые 250 ms
  unsigned long now = millis();
  if (now - previousMillis >= 250) {
    previousMillis = now;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
  }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Отсчёт времени без delay

Потренируйтесь самостоятельно: Песочница Arduino