Menu
CoddyTech

用 volatile 共享数据

本课属于 Coddy Arduino 学习旅程的“无需 delay 的计时”单元。第 14 课,共 18 课。

ISR 应该只做一件快速的事,所以它通常会设置一个变量,供草图的其余部分读取。两者都会使用的变量必须声明为 volatile:

volatile bool started = false;

void onPress() {
  started = true;
}

为了节省时间,编译器(将你的 C++ 转换成芯片指令的程序)可能会在处理器中保存一份变量副本,而不是读取内存。它不知道中断可以更改这个变量,因此草图可能会永远使用旧副本。volatile 会让程序每次都重新读取变量。

这个草图在 setup() 中使用 while 循环等待:只要条件为真,while (condition) { } 就会重复执行花括号中的内容,这里的条件是 !started。和“输入”单元中一样,! 表示非:当 started 为 false 时,循环会重复执行。没有 volatile,即使按下按钮后,它也可能永远等待。

challenge icon

挑战

简单

这段程序应该等待按钮被按下,然后让 LED 闪烁。目前它会一直等待。请修复它:

  • 在 onPress() 中,将 started 设为 true
  • 将 started 声明为 volatile

按“运行”,再按下按钮,然后按“检查”。试一次不使用 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 在线编辑器