Count Presses by Interrupt
Part of the Timing Without Delay section of Coddy's Arduino journey. Lesson 15 of 18.
As you saw in the Inputs section, buttons bounce: for about a millisecond the contacts touch, part and touch again, on the press and on the release. An interrupt sees every touch, so a FALLING ISR that adds 1 counts one click several times.
An ISR cannot debounce with delay(): delay() needs the clock's own interrupt, and interrupts are paused while an ISR runs. Use the clock instead. Remember when the last counted press happened, and ignore any fall that comes too soon after it:
unsigned long lastPress = 0;
void onPress() {
unsigned long now = millis();
if (now - lastPress >= 200) {
presses = presses + 1;
lastPress = now;
}
}Reading millis() in an ISR is fine: it gives the time the ISR started. Pick a window longer than a click, so the release's bounces fall inside it, and shorter than the gap between two quick clicks. 200 ms works for people.
Challenge
MediumThis counter counts each click several times. Debounce it inside onPress():
- add an
unsigned long lastPressvariable - count a fall only if at least 200 ms have passed since
lastPress, and then store the time inlastPress
Press Run, click the button a few times and watch the count, then Check.
Try it yourself
const int buttonPin = 2;
volatile int presses = 0;
int shown = 0;
void onPress() {
// every fall of the pin counts, bounces too: debounce it here
presses = presses + 1;
}
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(buttonPin), onPress, FALLING);
}
void loop() {
// print the count whenever it changes
if (presses != shown) {
shown = presses;
Serial.println(shown);
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Timing Without Delay
Practice on your own: Arduino playground