Menu
CoddyTech

循环错过的一次按键

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

草图有时会忙于执行耗时的任务,或等待较长时间的 delay()。如果循环只在任务之间读取按钮,就会漏掉在任务执行期间按下又松开的操作。

中断可以解决这个问题:引脚状态发生变化时,开发板会暂停当前操作,运行你指定的函数,然后继续执行。即使在 delay() 期间,芯片也会自行监视引脚。

void onPress() {
  digitalWrite(ledPin, HIGH);
}

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

attachInterrupt()需要三个参数:引脚对应的中断(digitalPinToInterrupt(buttonPin)会找到它)、要运行的函数,以及触发时机。FALLING表示引脚从 HIGH变为 LOW的时刻:启用上拉时,也就是按钮按下的时刻。

这个函数称为中断服务例程,简称 ISR。让它尽可能简短:不要使用 delay(),也不要使用 Serial。

challenge icon

挑战

简单

这个警报器每隔 2 秒才检查一次按钮,所以快速按下时会漏掉。让按下按钮后 LED 立即亮起:

  • 编写一个 ISR,onPress(),让 LED 亮起
  • 在 setup() 中,将它连接到按钮引脚,并使用 FALLING

将耗时的任务保留在 loop() 中。按下按钮后,LED 会像警报器一样保持亮起。按“运行”,点击按钮,然后按“检查”。

亲手试试

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

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(9600);
  // 在这里绑定中断
}

void loop() {
  // 耗时任务:保持原样
  Serial.println("working");
  delay(2000);

  // 这里只会每隔 2 秒检查一次按钮,
  // 所以短暂按下按钮可能会被漏掉
  if (digitalRead(buttonPin) == LOW) {
    digitalWrite(ledPin, HIGH);
  }
}
quiz icon自我测试

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

无需 delay 的计时中的所有课

自己练习: Arduino 在线编辑器