Menu
CoddyTech

无延迟闪烁

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

delay()会停止整个程序。在闪烁等待 500 ms 期间,loop()中的其他内容都不会运行:这段时间按下的按钮要等到等待结束后才会被检测到。

解决方法是永远不等待。让loop()快速地一遍又一遍运行,每次都将时钟与 LED 上次变化的时刻进行比较。在经过 500 ms 之前,什么也不做。然后改变 LED,并存储新的时刻:

const unsigned long interval = 500;
unsigned long previousMillis = 0;   // LED 上次改变状态的时间

void loop() {
  unsigned long now = millis();
  if (now - previousMillis >= interval) {
    previousMillis = now;           // 记住这一刻
    // 在这里切换 LED 的状态
  }
  // 这里的其他代码每秒会运行数千次
}

now - previousMillis表示距离上次变化所经过的时间。要切换 LED,请用变量保存它的状态:int redState = LOW;,用if/else切换状态,并用digitalWrite(redLed, redState);写入状态。

如果忘记更新previousMillis,那么经过最初的 500 ms 后,条件就会一直为真,因此 LED 会在每次循环时都变化,看起来像是亮度减半。

challenge icon

挑战

中等

黄色 LED 应该跟随按钮变化,但它反应较慢,因为红色 LED 的 delay() 调用会阻塞循环。用 millis() 重写红色 LED 的闪烁逻辑:

  • 保持按钮部分不变
  • 每隔 500 ms,切换引脚 13 上红色 LED 的状态
  • 任何地方都不能使用 delay()

按“运行”,按住按钮并观察两个 LED,然后按“检查”。

亲手试试

const int redLed = 13;
const int yellowLed = 12;
const int buttonPin = 2;

void setup() {
  pinMode(redLed, OUTPUT);
  pinMode(yellowLed, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  // 黄色 LED 随按钮状态变化。保留这部分。
  if (digitalRead(buttonPin) == LOW) {
    digitalWrite(yellowLed, HIGH);
  } else {
    digitalWrite(yellowLed, LOW);
  }

  // 红色 LED 会闪烁,但每次调用 delay() 都会让上面的代码暂停
  // 半秒。用 millis() 重写这部分。
  digitalWrite(redLed, HIGH);
  delay(500);
  digitalWrite(redLed, LOW);
  delay(500);
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

无需 delay 的计时中的所有课

自己练习: Arduino 在线编辑器