Skip to content

Embedded Systems

How to cycle through modes with one button on Arduino

To cycle through modes with one button on an Arduino, keep the mode in one number, mode, and move it on with each press: mode = (mode + 1) % 3 for three modes. The % remainder brings it back to 0 after the last mode, so the presses go round and round. Then give each mode its own rule, checked on every pass of loop().

A number for the mode

Number the modes from 0: 0 is off, 1 is full, 2 is half. One variable, declared above setup(), holds the current one, and the board starts in mode 0 at every power-up.

Why not three true-or-false flags? Because flags can disagree: a bug could leave "full" and "half" both true. A single number is always exactly one mode.

Round again with %

% gives the remainder after dividing. Adding 1 to the last mode, 2, gives 3, and 3 % 3 is 0: back to the first. From any other mode, the remainder is just the next number.

modemode + 1(mode + 1) % 3
011
122
230

Live experiment

Press round the modes

Pip is the lamp on pin 9. Each press moves the mode on with (mode + 1) % 3 and the board says the new mode's name: off, full, half, and round again. Then give the lamp a fourth mode, dim, and watch the remainder become % 4.

Try it yourself: free lesson

“Modes” is lesson 6 of 6 in Clockwork Cove, Embedded Systems World 2. Free with an account. Lessons unlock in order, so you’ll do the 12 before it first.

The sketch

int mode = 0;               // 0 off, 1 full, 2 half
bool last = HIGH;
unsigned long changedAt = 0;

void setup() {
  pinMode(2, INPUT_PULLUP); // button to GND
  pinMode(9, OUTPUT);       // lamp on a PWM pin
  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
      mode = (mode + 1) % 3;
      if (mode == 0) { Serial.println("off"); }
      else if (mode == 1) { Serial.println("full"); }
      else { Serial.println("half"); }
    }
  }

  if (mode == 0) { analogWrite(9, 0); }
  else if (mode == 1) { analogWrite(9, 255); }
  else { analogWrite(9, 128); }
}

The press code only acts on the change from HIGH to LOW, ignoring 50 ms of bounce after each change, so one press moves exactly one mode. The rules at the bottom run on every pass, so the lamp always shows the current mode, however it got there. The names are printed inside the press's if, once per change.

Where you'll meet it

A bike light's steady, flashing and off, a fan's speed button, a phone's ring, vibrate and silent: each is a mode number and a rule per mode. Add rules for how modes change on their own, like a timer, and the same pattern becomes a full state machine.

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

“Modes” is lesson 6 of 6 in Clockwork Cove, Embedded Systems World 2. Free with an account. Lessons unlock in order, so you’ll do the 12 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 3After the last mode, the next press…
    Show the answer

    Answer: Goes back to the first mode. The modes go round in a circle. After the last one, a press brings the first back, like a remainder clock.

    • Why not “Turns the board off”? The board keeps running; only the mode number changes. A mode that turns the lamp off doesn't turn the board off.
    • Why not “Does nothing”? Every press moves the mode on. From the last one, the remainder brings it round to the first.
    • Why not “Adds a new mode”? The modes are written into the code. A press can only move between them, never invent a new one.
  2. Question 2 of 3In an if / else if / else chain, the else if test runs…
    Show the answer

    Answer: only when the tests before it were false. The chain tries each test in turn and runs the first block whose test is true. Later tests are skipped once one has matched.

    • Why not “only when the first test was true”? That's backwards: if the first test is true, its block runs and every else if after it is skipped.
    • Why not “never”? It runs whenever every test before it was false, which in a mode chain happens on most passes.
    • Why not “on every pass”? It runs only when the chain gets that far. Once an earlier test is true, the rest are skipped.
  3. Question 3 of 3Why keep the mode as a number instead of separate true/false flags?
    Show the answer

    Answer: One number can only be one mode at a time, so modes can't clash. With flags, two could be true at once. A single mode number is always exactly one mode.

    • Why not “No reason”? There's a good reason: with separate flags, two modes could end up on at once.
    • Why not “Numbers are faster”? Speed isn't the point; both are quick. One number simply can't hold two modes at once.
    • Why not “Flags use more pins”? Variables don't use pins at all. The difference is that flags can clash and one number can't.
Keep practising: free lesson

“Modes” is lesson 6 of 6 in Clockwork Cove, Embedded Systems World 2. Free with an account. Lessons unlock in order, so you’ll do the 12 before it first.

Questions people ask

How do I add another mode?

Raise the number in the remainder, % 3 to % 4, and add one more rule for the new mode number. The press code doesn't change, because it only ever moves the number on and wraps it round.

Should I use switch or if / else if for modes?

Either works. A switch statement with one case per mode number reads neatly when there are many modes; an if / else if chain is just as good for three. What matters is that each mode has exactly one rule.

How do I make the Arduino remember the mode after power off?

Save it in EEPROM, the chip's small non-volatile memory, whenever it changes, and read it back in setup(). EEPROM.update() only writes when the value differs, which saves wear: each byte survives about 100,000 writes.

Every topic