In this tutorial on MicroPython, we will continue to see how to interact with basic hardware, focusing on 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. This is quite common and fairly typical, but there are a couple of “things” we need to know.
So, let’s see how to read a button or switch with a digital pin in MicroPython.
If you want to learn more, check out,
Configuring a GPIO Pin as Input
As we saw in the previous entry, in MicroPython, the GPIO pins are configured using the Pin
class from the machine
module.
Let’s summarize that to configure a pin as an input, we use the mode Pin.IN
. Then we can read its state using the value()
method (with no parameters).
from machine import Pin
# Configure pin 5 as input
button = Pin(5, Pin.IN)
state = button.value()
The value()
method
- Returns
1
if the pin is in HIGH state (button pressed) 0
if 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.
To do 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 connects 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 connects to VCC and reads HIGH.
Many devices include internal pull-up or pull-down resistors. We can enable them from MicroPython, using the modes Pin.PULL_UP
or Pin.PULL_DOWN
.
# 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 the bounce. When a button is pressed or released, the contacts often generate multiple rapid transitions between HIGH and LOW before stabilizing (which can ruin your measurement).
To handle bounce, we can implement a simple software debounce. A straightforward way to do this is to introduce a short 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’s state, we wait for 50 ms before reading the state again. This helps to avoid false detections due to bounce.
There are other ways to manage bounce. This is simple and hence widely used, but for complicated 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: turning 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 lights up 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 that the button is pressed (LOW state) and “Button not pressed” when it is not (HIGH state).
Button Press Counter
This example counts how many times a button is pressed and displays the result in 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 toggles between different operating 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