Raspberry Pi Pico Button Simulator: Wiring, Code and a Live Circuit
This is a pushbutton wired to a Raspberry Pi Pico, with a debounced press counter running live: hold the button on the drawing and the serial monitor counts each press exactly once.
- 3.3 V logic
- No library
- Input on GP15 (physical pin 20)
- Internal pull-up, 20 ms debounce
Wiring the Button to the Raspberry Pi Pico
Two wires and no resistor: GP15 (physical pin 20) to one side of the button, GND to the other, and the Raspberry Pi Pico’s internal pull-up does the rest.
Every connection in the circuit above, with the board’s own pin names.
| Button pin | Raspberry Pi Pico pin | Why |
|---|---|---|
| One side (1a) | GP15 (physical pin 20) | With INPUT_PULLUP the RP2040’s own resistor holds the pin high. |
| The other side (2a) | GND | Pressing connects the pin to ground, so it reads LOW. |
Power
No resistor and no supply wire: the Raspberry Pi Pico’s internal pull-up, about 45 k on this chip, ties the pin to 3.3 V. Never wire a button between a pin and VBUS (5 V from USB): the press would put 5 V on a 3.3 V pin.
Pins to leave alone on the Raspberry Pi Pico
The numbers in the code are GP numbers, not the physical pin numbers printed beside the header: GP15 is pin 20. GP23 to GP25 are used on the board itself, and GP25 is the LED.
On a real bench
Solder headers on the Pico and press it into the breadboard across the center channel; the Button goes in beside it. GND pins sit every fifth pin down both sides (pins 3, 8, 13, 18 and so on), so there is always one close. The first upload needs BOOTSEL held while plugging in.
The code, and what it does.
The sketch the circuit above runs. Open it in the editor, change a line and press Run: it compiles in your browser.
const int BUTTON_PIN = 15; // GP15 (physical pin 20) to the button, the button to GND
const unsigned long DEBOUNCE_MS = 20;
int lastReading = HIGH;
int state = HIGH;
unsigned long changedAt = 0;
unsigned int presses = 0;
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP); // HIGH when up, LOW when pressed
Serial.println("Press the button");
}
void loop() {
int reading = digitalRead(BUTTON_PIN);
if (reading != lastReading) changedAt = millis();
lastReading = reading;
if (millis() - changedAt > DEBOUNCE_MS && reading != state) {
state = reading;
if (state == LOW) {
presses++;
Serial.print("Pressed, count ");
Serial.println(presses);
}
}
}
pinMode(BUTTON_PIN, INPUT_PULLUP) turns on the pull-up inside the chip, so the pin reads HIGH while the button is up and LOW while it is held. That is backwards from what most people expect the first time, and it saves a resistor.
A real button bounces: for a few milliseconds after it closes, the contacts open and close many times. The sketch notes the time of every change and only accepts a new state once the reading has stayed put for 20 ms, so one press counts once. The simulated button bounces like a real one, so you can see it fail by setting DEBOUNCE_MS to 0.
Serial.begin(115200) opens the serial monitor. Serial is the USB port at 115200 baud in this sketch; on a real Pico it appears once the board has enumerated.
Common mistakes with the Button on the Raspberry Pi Pico
A floating input
With plain INPUT and no resistor, the pin reads whatever noise is nearby and the sketch sees presses nobody made. Use INPUT_PULLUP, or a 10 k resistor to the supply.
Counting the bounce
Without a debounce, one press can count as three or four. The simulated button bounces for a few milliseconds the way real contacts do, so the fix here is the fix on a desk.
Counting physical pins instead of GP numbers
The sketch says 15, which means GP15, and that is physical pin 20 on the header. Counting 15 pins down the side lands on a different GPIO, and the part never answers.
Questions and answers
Can I simulate a button with a Raspberry Pi Pico?
Yes. The circuit at the top of this page is a Raspberry Pi Pico with a pushbutton, running in your browser on a simulated RP2040. Hold the button on the drawing to press it; the contacts bounce like a real switch. Press Run it in the editor to change the wiring or the code; it is free and needs no account.
Why does the button read LOW when pressed?
Because the pull-up holds the pin HIGH and the button connects it to ground. Compare with LOW in the code, or wire the button to the supply with a pull-down resistor if you want the opposite.
Should I use attachInterrupt() for a button?
You can, but an interrupt fires on every bounce too, so it still needs a debounce. Polling every pass of loop() is simpler and fast enough for a person.
Is there a library for buttons?
Bounce2.h, OneButton.h and AceButton.h all compile here. The sketch above does the same job in a dozen lines, which is worth understanding before reaching for one.
Build your own Button project
Open this circuit in the editor, change the wiring or the code, and keep your version in a free account.