用中断统计按键次数
本课属于 Coddy Arduino 学习旅程的“无需 delay 的计时”单元。第 15 课,共 18 课。
正如你在“输入”单元中看到的,按钮会抖动:按下和松开时,触点会接触、分开,然后再次接触,持续约 1 毫秒。中断会检测到每一次接触,因此使用 FALLING 的 ISR 每检测到一次就加 1,会把一次点击计数好几次。
ISR 不能用 delay() 来消抖:delay() 需要时钟自己的中断,而 ISR 运行时中断会暂停。改用时钟来处理。记住上次计数的按下操作发生的时间,并忽略紧接着发生的下落沿:
unsigned long lastPress = 0;
void onPress() {
unsigned long now = millis();
if (now - lastPress >= 200) {
presses = presses + 1;
lastPress = now;
}
}在 ISR 中读取 millis() 没问题:它会给出 ISR 开始运行的时间。选择一个比一次点击持续时间长的时间窗口,这样松开时的抖动就会落在窗口内;同时,窗口要短于两次快速点击之间的间隔。对人来说,200 毫秒合适。
挑战
中等这个计数器会把每次点击计数好几次。在 onPress() 中对它进行消抖:
- 添加一个
unsigned long lastPress变量 - 只有自
lastPress起至少经过 200 ms 后,才对一次下降沿计数,然后将时间存入lastPress
按下 运行,点击几次按钮并观察计数,然后点击 检查。
亲手试试
const int buttonPin = 2;
volatile int presses = 0;
int shown = 0;
void onPress() {
// 引脚每次从高电平变为低电平都会计数,抖动也算:在这里消除抖动。
presses = presses + 1;
}
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(buttonPin), onPress, FALLING);
}
void loop() {
// 每当计数发生变化时,就打印出来。
if (presses != shown) {
shown = presses;
Serial.println(shown);
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
无需 delay 的计时中的所有课
自己练习: Arduino 在线编辑器