Embedded Systems
How to count button presses on an Arduino
To count button presses on an Arduino, keep the count in a variable above setup(), so it survives every pass of loop(), and add one only when the pin changes from HIGH to LOW, the moment of the press. Never count every pass that reads LOW: one press lasts thousands of passes.
The counter must survive the pass
A variable declared inside loop() is made fresh on every pass and starts again each time. Declared above setup(), it lives as long as the board runs:
int presses = 0; // the tally, kept between passes
presses = presses + 1 works out the old value plus one, then stores it back. presses++ is the short way to write the same thing.
Count the change, not the hold
With the button from pin 2 to GND and INPUT_PULLUP, released reads HIGH and pressed reads LOW. Remember what the pin read last pass, and count only when it was HIGH and is LOW now. Real buttons also bounce for a few milliseconds when they close and open, so ignore the pin for 50 ms after each change:
int presses = 0;
bool last = HIGH;
unsigned long changedAt = 0;
void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(9, OUTPUT);
Serial.begin(9600);
}
void loop() {
bool now = digitalRead(2);
if (now != last && millis() - changedAt > 50) {
changedAt = millis();
last = now;
if (now == LOW) { // a new press
presses = presses + 1;
Serial.println(presses);
}
}
digitalWrite(9, presses > 0 && presses % 3 == 0);
}
Live experiment
Every third press
Pip, an LED on pin 9, lights on every third press: when presses % 3 is 0, but not before the first press. The remainder dial goes 0, 1, 2 and round again. Then switch the count to every LOW pass and press just once.
“Count and remember” is lesson 3 of 6 in Clockwork Cove, Embedded Systems World 2. Free with an account. Lessons unlock in order, so you’ll do the 9 before it first.
Every third press, with %
% gives the remainder after dividing. Divide the count by 3 and the remainder goes round like a clock: 1, 2, 0, 1, 2, 0. It's 0 exactly on the 3rd, 6th and 9th press:
| presses | presses % 3 |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 0 |
| 4 | 1 |
| 6 | 0 |
So the LED lights at the third press, goes off at the fourth, and lights again at the sixth. Change the 3 to any N for every Nth press.
Where you'll use it
Counting edges and taking remainders turns up everywhere: a turnstile's tally, a menu that cycles through options, a lamp with modes, or a 13 o'clock that's really 1 o'clock, because 13 % 12 is 1.
Free lesson
Now build it yourself
Each lesson comes in three short parts: see the idea, try it on a live board, then build it yourself, with quick checks as you go.
“Count and remember” is lesson 3 of 6 in Clockwork Cove, Embedded Systems World 2. Free with an account. Lessons unlock in order, so you’ll do the 9 before it first.
Or start from the very first lesson, no account neededPractice questions
Three quick questions from the lessons. Pick an answer to check it.
Show the answer
Answer: Add one to presses and keep the new value. The right side works out the old value plus one, and the = stores it back in presses. That's how a tally grows.
- Why not “Check whether presses is one more”? A single = stores a value; it doesn't ask a question. Checking for equality would be ==.
- Why not “Set presses back to one”? presses + 1 is worked out from the old value first, so the count grows. Setting it to one would be presses = 1.
- Why not “Print presses plus one”? Nothing is printed. The line only works out the new value and stores it in presses.
Show the answer
Answer: 0, 3, 6, 9, 12…. The remainder is zero exactly when three divides the count with nothing left over: every third count, and 0 too, before any press.
- Why not “1, 2, 3…”? % 3 == 0 is true only when 3 divides the count exactly, so 1 and 2 don't pass.
- Why not “only 3”? 6, 9, 12 and every other multiple of 3 leave nothing over too, and so does 0.
- Why not “any odd number”? Odd or even is % 2. Odd numbers like 5 and 7 still leave a remainder when divided by 3.
Show the answer
Answer: 1. 3 goes in twice, making 6, with 1 left over.
- Why not “0”? A remainder of 0 would mean 3 divides 7 exactly, and it doesn't: 3 × 2 = 6 and 3 × 3 = 9.
- Why not “2”? 3 goes into 7 twice, making 6, so 1 is left over, not 2.
- Why not “3”? A remainder is always smaller than the number you divide by, so % 3 can only give 0, 1 or 2.
“Count and remember” is lesson 3 of 6 in Clockwork Cove, Embedded Systems World 2. Free with an account. Lessons unlock in order, so you’ll do the 9 before it first.
Questions people ask
Why does my Arduino count one press as hundreds?
It's counting every pass of loop() that reads the button as pressed, and a press lasts thousands of passes. Count only the change from released to pressed, HIGH to LOW with a pull-up, which happens once per press.
What does % do in Arduino code?
It gives the remainder after dividing. 10 % 3 is 1, because 3 goes into 10 three times with 1 left over. Counts that should repeat, like every third press or round a list, use it.
How high can an Arduino int count?
On an Uno an int is 16 bits, so it reaches 32,767 and then wraps round to −32,768. That's plenty of button presses, but for anything that counts fast, use a long or an unsigned long.
Related topics
- How to debounce a button on ArduinoWhy one press counts as four, and the 50 ms fixes that make it count once.
- What is a pull-up resistor?Why an input pin needs a pull-up, and why a pressed button reads LOW.
- How to cycle through modes with one button on ArduinoOne button, one number, one rule per mode: how torches, fans and bike lights step through settings.
- How to do two things at once on an ArduinoNo threads, no waiting: a loop() that glances at every job thousands of times a second.