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.
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 - 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.
The same toggle in MicroPython: the debounce from the last article, and a variable flipped on each debounced press and written to a second pin.
"""
Push Button - a toggle, MicroPython TK04 / /p/tk04
Wiring. Count from the square pad on the TinkerBlock board, button
up, header at the bottom:
GND -> GND
VCC -> 3V3 (never 5V: pressed, SIGNAL gives your pin VCC)
NC -> nothing (unconnected on the board)
SIGNAL -> 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 -> GPIO 4 on an ESP32, GPIO 5 on an ESP32-S3, GP14 on a Pico
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
Save it to the board as main.py to run it on every power-up.
Nothing to install: machine and time are built in.
"""
from machine import Pin
import time
# The GPIO number the button's SIGNAL is wired to.
# ESP32: 25. ESP32-S3: 4. Pico: 15.
BUTTON_PIN = 4
# The GPIO number the TK01's SIGNAL is wired to.
# ESP32: 4. ESP32-S3: 5. Pico: 14.
LED_PIN = 5
DEBOUNCE_MS = 20
button = Pin(BUTTON_PIN, Pin.IN) # no pull: the block has its own
led = Pin(LED_PIN, Pin.OUT, value=0)
last_reading = 0
state = 0
last_change = time.ticks_ms()
led_on = False # the toggle's memory
while True:
reading = button.value()
now = time.ticks_ms()
if reading != last_reading: # the contacts moved: restart
last_reading = reading
last_change = now
if (time.ticks_diff(now, last_change) >= DEBOUNCE_MS
and reading != state):
state = reading
if state == 1: # one real press: flip
led_on = not led_on
led.value(led_on)
print("on" if led_on else "off")led_on is the toggle's only memory, and it starts off at every reset. Stop the program with Ctrl-C in Thonny's shell and the TK01 stays in whatever state it was in.
When it does not work
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.
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 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.
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.
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
Questions about this product
See what other owners have asked, and read their solutions.
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.