In this MicroPython tutorial, we will continue learning how to interact with basic hardware, seeing how to perform reading a button as a digital input.
A button is an electronic component that allows or prevents the flow of electric current when pressed.
In its normal state (not pressed), the button can be open (does not conduct current) or closed (conducts current).
In a microcontroller, we can use a digital input to detect whether the button is pressed or not. Which, in principle, is very common and quite usual, but has a couple of “little things” we need to know.
So let’s see how to read a button or a switch with a digital pin in MicroPython.
Configuring a GPIO Pin as Input
As we saw in the previous post, in MicroPython GPIO pins are configured using the Pin class from the machine module.
Let’s remember, in summary, that to configure a pin as input, we use the Pin.IN mode. Then we can read its state using the value() method (without parameters).
from machine import Pin
# Configure pin 5 as input
button = Pin(5, Pin.IN)
state = button.value()
The value() method
- Returns
1if the pin is in HIGH state (button pressed) 0if it is in LOW state (button not pressed).
Pull-Up and Pull-Down Resistors
When working with digital inputs, it is necessary to ensure that the pin has a defined state when the button is not pressed.
For this, we use pull-up or pull-down resistors.
- Pull-Up Resistor: Connects the pin to a high voltage (VCC) through a resistor. When the button is not pressed, the pin reads HIGH. When pressed, the pin is connected to ground (GND) and reads LOW.
- Pull-Down Resistor: Connects the pin to ground (GND) through a resistor. When the button is not pressed, the pin reads LOW. When pressed, the pin is connected to VCC and reads HIGH.
Many devices include internal pull-up or pull-down resistors. We can activate them from MicroPython, using the Pin.PULL_UP or Pin.PULL_DOWN modes.
# Configure pin 5 as input with internal pull-up resistor
button = Pin(5, Pin.IN, Pin.PULL_UP)
In this case, when the button is not pressed, the pin will read HIGH. When pressed, it will read LOW.
Handling Button Bounce
A common headache when working with buttons is bounce. When a button is pressed or released, the contacts often generate multiple rapid transitions between HIGH and LOW before stabilizing (which will ruin your measurement).
To handle bounce, we can implement a simple software debounce. A simple way to do this is to introduce a small delay after detecting a press.
from machine import Pin
import time
# Configure pin 5 as input with internal pull-up resistor
button = Pin(5, Pin.IN, Pin.PULL_UP)
# Variable to store the last state of the button
last_state = button.value()
while True:
current_state = button.value()
if current_state != last_state:
time.sleep(0.05) # Small delay to avoid bounce
current_state = button.value() # Read state again
if current_state == 0: # Button pressed (LOW due to pull-up)
print("Button pressed")
else:
print("Button not pressed")
last_state = current_state
time.sleep(0.01) # Small pause to avoid repeated readings
In this code, after detecting a change in the button state, we wait 50 ms before reading the state again. This helps avoid false detections due to bounce.
There are other ways to manage bounce. This one is simple, and therefore very used, but for complex applications better methods may be necessary.
Practical Examples
Turn on an LED when the button is pressed
Let’s combine what we’ve learned to create a practical example: turn on an LED when a button is pressed.
from machine import Pin
import time
# Configure pin 5 as input with internal pull-up resistor
button = Pin(5, Pin.IN, Pin.PULL_UP)
# Configure pin 2 as output for the LED
led = Pin(2, Pin.OUT)
while True:
state = button.value()
if state == 0: # Button pressed (LOW due to pull-up)
led.value(1) # Turn on the LED
else:
led.value(0) # Turn off the LED
time.sleep(0.1) # Small pause to avoid repeated readings
In this example, the LED connected to pin 2 turns on when the button is pressed and turns off when released.
Read the button in a continuous loop
Once the pin is configured as input, we can read its state in a loop to detect when the button is pressed.
from machine import Pin
import time
# Configure pin 5 as input with internal pull-up resistor
button = Pin(5, Pin.IN, Pin.PULL_UP)
while True:
state = button.value()
if state == 0: # Button pressed (LOW due to pull-up)
print("Button pressed")
else:
print("Button not pressed")
time.sleep(0.1) # Small pause to avoid repeated readings
In this example, the program prints “Button pressed” when it detects the button is pressed (LOW state) and “Button not pressed” when it is not (HIGH state).
Press Counter
This example counts how many times a button is pressed and displays the result on the console.
from machine import Pin
import time
# Button configuration
button = Pin(25, Pin.IN, Pin.PULL_UP)
counter = 0
while True:
if button.value() == 0: # Detect button press
time.sleep(0.02) # Anti-bounce
if button.value() == 0:
counter += 1
print(f"Presses: {counter}")
while button.value() == 0: # Wait for it to be released
pass
State Change Between Multiple Modes
This example alternates between different operation modes when the button is pressed.
from machine import Pin
import time
# Configuration
button = Pin(25, Pin.IN, Pin.PULL_UP)
modes = ["Mode 1", "Mode 2", "Mode 3"]
mode_index = 0
while True:
if button.value() == 0: # Detect press
time.sleep(0.02) # Anti-bounce
if button.value() == 0:
mode_index = (mode_index + 1) % len(modes) # Change mode
print(f"Current mode: {modes[mode_index]}")
while button.value() == 0: # Wait for it to be released
pass
