Table of Contents
Using a Breakout Button - Better Code
Introduction
*** Warning *** You can lock yourself out of your Pi Pico if you don't have a method to break the code. Please think about if you want/need to do this!!!
Please read the section before this titled Using a Breakout Button as I am only covering the differences here.
This is our original traffic light build, but with an additional push button on pins GP16 and GND.
The Code
Below is the full code with all of the changes, there are two blocks that have been added. We will cover these in the next section below this code block.
- | download
#Traffic light LEDs using an array from machine import Pin import time ####################### ADD BREAKOUT BUTTON ############################# # Configure the button on GPIO16 # PULL_UP means the pin reads HIGH (1) until the button connects it to GND button = Pin(16, Pin.IN, Pin.PULL_UP) ####################### ADD BREAKOUT BUTTON ############################# # Define GPIO pins for the LEDs RED = Pin(2, Pin.OUT) AMBER = Pin(6, Pin.OUT) GREEN = Pin(10, Pin.OUT) # Put them in an array lights = [RED, AMBER, GREEN] # Helper function to turn all lights off def all_off(): for light in lights: light.off() # checks to see if the button has been pressed. def check_breakout(): if button.value() == 0: # Button pressed print("Button pressed — stopping program.") all_off() return True return False # define a function wait_with_break. This function waits 1 second in 0.1s slices. If you pass # it the value 3, it will wait 3 seconds in 30 x .1s slices. This is so it can check the # button state every 0.1s rather than waiting 8 whole seconds. def wait_with_break(seconds): for _ in range(int(seconds * 10)): # 0.1s slices in a loop if check_breakout(): return True time.sleep(0.1) return False while True: # Red all_off() RED.on() # passes the value 3 to the function above causing a 3s second delay in 0.1s steps if wait_with_break(3): break # Red + Amber AMBER.on() # passes the value 1 to the function above causing a 1s second delay in 0.1s steps if wait_with_break(1): break # Green all_off() GREEN.on() # passes the value 3 to the function above causing a 3s second delay in 0.1s steps if wait_with_break(3): break # Amber all_off() AMBER.on() # passes the value 1 to the function above causing a 1s second delay in 0.1s steps if wait_with_break(1): break # Code End
What Has Changed?
We have actually removed the long delay required when pressing the button. See below for how this was achieved.
Firstly, we have defined a function for the button press detection.
- | download
# checks to see if the button has been pressed. def check_breakout(): # Define a function named 'check_breakout' if button.value() == 0: # Read the button pin; 0 means the button is pressed print("Button pressed — stopping program.") # Inform the user via the console all_off() # Turn off all LEDs (your own helper function) return True # Signal to the caller that the program should stop return False # Button not pressed → tell the caller to continue running
The code block above is a function.
In Python, a function is created using the def keyword, followed by:
- a name
- parentheses
- a colon
- an indented block of code
Next, we have a function that waits an amount of time depending on a value that is passed to it. It loops in 0.1s intervals, and in each loop it checks the button status. This makes button detection only 0.1s long.
- | download
# define a function wait_with_break. This function waits 1 second in 0.1s slices. If you pass # it the value 3, it will wait 3 seconds in 30 x .1s slices. This is so it can check the # button state every 0.1s rather than waiting 8 whole seconds. def wait_with_break(seconds): # Define a function named 'wait_with_break' that takes 'seconds' as an argument for _ in range(int(seconds * 10)): # Loop 'seconds * 10' times → e.g. 1s = 10 loops, 3s = 30 loops (each loop = 0.1s) if check_breakout(): # Call 'check_breakout()' to see if the button has been pressed return True # If the button is pressed, immediately return True to signal "stop" time.sleep(0.1) # Wait for 0.1 seconds before the next loop iteration return False # If the loop finishes with no button press, return False (no stop requested)
So if it is passed the value 3, it will loop 30×0.1s, and in that time check the button status 30 times. So when you press the breakout button, it will seem instant.
Lastly, in the section that sets the traffic light LED status, we call the wait_with_break function at each section, and we pass the delay to this function.
- | download
# Red all_off() RED.on() # passes the value 3 to the function above causing a 3s second delay in 0.1s steps if wait_with_break(3): break # Red + Amber AMBER.on() # passes the value 1 to the function above causing a 1s second delay in 0.1s steps if wait_with_break(1): break # Green all_off() GREEN.on() # passes the value 3 to the function above causing a 3s second delay in 0.1s steps if wait_with_break(3): break # Amber all_off() AMBER.on() # passes the value 1 to the function above causing a 1s second delay in 0.1s steps if wait_with_break(1): break
So this line: if wait_with_break(3): break calls the function wait_with_break and asks for a delay of 3 seconds (in a 0.1s loop).
If the button is detected to have been pressed, we breakout of the code immediately.
Example
*Remember* - We must save this code to our Raspberry Pi Pico as a file called main.py.
This will enable to code to run on the Pico boot up.
Here is the button in action using the better code we just explored.
Using a button like this means you can never get you Pico stuck in a software loop with little to no way of recovery (without wiping it completely).

