Skip to content

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.

Try it yourself: free lesson

“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:

pressespresses % 3
11
22
30
41
60

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.

Try it yourself: free lesson

“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 needed

Practice questions

Three quick questions from the lessons. Pick an answer to check it.

  1. Question 1 of 3presses = presses + 1 means…
    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.
  2. Question 2 of 3presses % 3 == 0 is true when presses is…
    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.
  3. Question 3 of 37 % 3 is…
    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.
Keep practising: free lesson

“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.

Every topic