One press, one action · 08 of 9

A toggle

Press once and a light comes on, press again and it goes off. The button only says HIGH while it is held, so the on-or-off has to live in the sketch: one variable, flipped once per debounced press.

The button forgets

This block's switch is momentary. SIGNAL is HIGH while your finger is on it and LOW the moment you let go, which is what WORKS ONLY WHILE PRESSED on the back of the board means. A light that should stay on after the press has to be remembered by something else, and here that something is the sketch.

A toggle
Presses
0
Button held for
0.00 s
TK01 LED
off
The top lane is what the button says: HIGH only while you hold it. The bottom lane is a variable in the sketch. Watch which one lasts.

Four presses, and the button is down for well under half of the three seconds. The ledOn lane stays where each press left it. The switch said nothing between presses; the variable is the memory.

One variable, flipped on the edge

The sketch is the debounce sketch with the counter taken out. Where it used to add one to presses, it now does ledOn = !ledOn and writes the result to LED_PIN. Everything else is the same, and it has to be:

  • Flip on the change, not on the level. Flipping on every pass of loop() while the pin is HIGH would flip thousands of times per press and land at random.
  • Flip on the debounced change. A bouncing contact flips it two or three times per press, and the light ends up on or off by chance.

The second pin drives a TK01 XL LED: D9 on an Uno, GPIO 4 on an ESP32, GPIO 5 on an ESP32-S3, GP14 on a Pico. Its first blink shows the two wires. Without one, watch the serial monitor print on and off.

Or let the switch remember

A toggle in software costs a debounce and a variable, and it forgets at every reset. The other way to get push-on, push-off is a switch that holds its own position mechanically: a latching switch. The TK05 latching button is that, on the same four-pin header. With it, the sketch reads a level that lasts, rather than catching a moment.

Neither is better. A software toggle can do more than on and off: count presses, time them, or cycle through modes. A latching switch keeps its position through a reset or a power cut, because nothing in it is memory.

The code

The debounce sketch with one change: instead of counting, each debounced press flips ledOn and writes it to a second pin. A TK01 XL LED on that pin shows it. No library.

push_button_toggle.ino
/*
  Push Button - a toggle                                 TK04 / /p/tk04

  Wiring. Count from the square pad on the TinkerBlock board, button
  up, header at the bottom:

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
              (pressed, SIGNAL gives your pin whatever VCC is)
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> D2 on an Uno, GPIO 25 on an ESP32, GPIO 4 on an
              ESP32-S3, GP15 on a Raspberry Pi Pico

  A TK01 XL LED on a second pin shows the state (optional):
    GND    -> GND
    SIGNAL -> D9 on an Uno, GPIO 4 on an ESP32, GPIO 5 on an
              ESP32-S3, GP14 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The GPIO number the button's SIGNAL is wired to.
// Uno: 2. ESP32: 25. ESP32-S3: 4. Pico: 15.
const int BUTTON_PIN = 4;
// The GPIO number the TK01's SIGNAL is wired to.
// Uno: 9. ESP32: 4. ESP32-S3: 5. Pico: 14.
const int LED_PIN = 5;
const unsigned long DEBOUNCE_MS = 20;

int lastReading = LOW;
int state = LOW;
unsigned long lastChange = 0;
bool ledOn = false;             // the toggle's memory

void setup() {
  Serial.begin(115200);
  pinMode(BUTTON_PIN, INPUT);   // the block has its own pull-down
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  int reading = digitalRead(BUTTON_PIN);
  unsigned long now = millis();

  if (reading != lastReading) { // the contacts moved: restart the clock
    lastReading = reading;
    lastChange = now;
  }

  if (now - lastChange >= DEBOUNCE_MS && reading != state) {
    state = reading;
    if (state == HIGH) {        // one real press: flip
      ledOn = !ledOn;
      digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
      Serial.println(ledOn ? "on" : "off");
    }
  }
}

ledOn is the whole memory of the toggle: the button forgets the moment you let go, and the red LED on the TK04 goes out with it, but the TK01 stays as you left it. Every reset starts it off.

When it does not work

The light flickers or ends up in the wrong state.

The press is not debounced, so a bouncing contact flips the variable two or three times and it lands wherever the last flip left it. Flip only when the debounced state changes to HIGH, as the sketch does, and it flips exactly once per press.

It toggles on release instead of on press.

The sketch is testing for the change to LOW. On this block HIGH is pressed, so the change to HIGH is the moment the finger goes down. Toggling on release is a valid choice, but it feels late.

The light is off again after a reset.

The variable lives in the microcontroller's memory, which starts empty at every power-up and reset. To remember across a power cut, save it: EEPROM on an Uno, Preferences on an ESP32. Or use a latching switch, which holds its own position.

Can I do this without a TK01?

Yes. Leave the LED lines as they are and watch the serial monitor, which prints on or off at every press. Any LED with a resistor on the LED_PIN pin works the same way as the TK01.

Where this goes next

The short list of reasons, split in two by the red LED.

When a press does nothing

Edit this page — content/books/push-button/a-toggle.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Push Button

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum