Maker Advent Calendar Day #3: Bashing Buttons!

Maker Advent Calendar Day #3: Bashing Buttons!

Welcome to day three of your 12 Projects of Codemas Advent Calendar. Today we’ll be adding physical inputs to your program using buttons!

So far we’ve relied purely on code to tell our components and program what to do and when. Now we’re going to use physical buttons to do that, which will act as triggers in our program to determine what happens.

Let's go!

Box #3 Contents

In this box you will find:

  • 1x Mini Breadboard
  • 3x Tall Tactile Buttons
  • 3x Button caps
  • 7x Male to male jumper wires

Day 3 parts

Today’s Project

Today we’ll be programming the buttons in your box as inputs for our code. Whilst we can easily use code to trigger our program to 'do things' (such as counting), components like buttons and switches allow us to physically interact with our project.

Most buttons are very simple, just connecting a circuit together which then sends a signal to our Raspberry Pi Pico via our chosen GPIO pin. You could do the same by simply touching two wires together, but of course buttons make this far more convenient and user friendly.

We're also going to be using the mini breadboard as a little control panel for our project as we’re going to make use of our LED circuit from yesterday. It's a handy part to have in your growing stash of bits, and it'll come in handy for some of our other boxes too.

Oh and the button caps? They're just a nice little extra that make each click that little bit more satisfying! Clickety click click clickety click!

Construct the Circuit

As always, first make sure your Pico is disconnected from your computer.

Now grab the mini breadboard and pop each button into it a few holes apart, making sure the legs sit either side of the little channel in the middle.

Like our larger breadboard, that central channel disconnects one side from the other, which is handy when wiring projects otherwise all of our button legs would be connected together (and we really don't want any magic blue smoke!).

Buttons in breadboard

Now we need to connect a 3.3V pin from the Pico to the top red lane on our main breadboard. Pop a jumper wire into the 3V3 (OUT) pin on the Pico (physical pin 36), then connect the other side to the top red lane.

You then need to connect the red 3.3V lane to one side of each of the buttons, go for the right side like we have below:

Buttons wired to 3v3

Lastly we need to connect the other side of the buttons to GPIO pins. Add a jumper wire into GPIO 13, 8 and 3 (that's physical pins 17, 11 and 5). Check the Pico pin map if you're not sure, or use our diagram below.

Buttons wired to GPIO

Important: the GPIO pin must be on the opposite side of the button, as the left and right side are disconnected until you click the button. If you had the GPIO and 3.3V wires on one side, the button would act as if it's constantly clicked!

Activity 1: Button Test Program

We'll first run a simple test program on one of the buttons. Each button has been wired to a GPIO pin (13, 8 and 3) so we can set these as inputs to trigger some text to print when they're pressed.

We'll use a while loop (which we learnt about yesterday) so that the program keeps watching for the button press forever, with a new function, an if statement, to determine what happens when the button is pressed.

If Statements

If you've used Microsoft Excel or similar software previously, you'll have already guessed what if statements do.

If statements allow us to give our code different outcomes depending on values, inputs and many other things, such as "if the first button is pressed, light the red LED" . If the condition for the statement is met, our program will run the code inside that code block which is indented underneath.

Indentation is important again here - the while loop block is indented, but as the while loop contains an if statement, we indent yet again for the if statement block of code. Look at the example below to see this in action.

If statements can be very powerful and there are lots of different and advanced ways to use them. You'll use them lots when making your own code. We'll start with a nice simple example, but first let's explain something else new in our code - pull downs.

Pull downs

Our code below also uses pull downs - you can see this at the end of each of the button set up sections as Pin.PULL_DOWN.

So why do we add this? When we use a button, we're sending 3.3V to the GPIO pin to set it HIGH, however we need to make sure the pin is LOW in the first place or our code might not be able to detect the change and/or it might trigger itself randomly.

This is because GPIO pins with no pull down (or pull up) can be 'floating' between 0V and 3.3V - 'pulling down' the pin to 0V ensures it's always LOW to start with.

Sometimes this is achieved by using physical resistors in a circuit, however some microcontrollers (such as our Pico) have this functionality built-in and we can simply enable them in our code. Handy!

The Code

This initial simple code uses just the first button. The code includes our usual imports and pin setup, then starts a while loop. The while loop contains an if statement that looks for a HIGH signal (1) on GPIO 13.

If the button is pressed and a signal is sent to that pin, our code will print "button 1 pressed".

We include a short delay in this loop to give your finger a chance to release the button, to avoid the code triggering many times from a single press (known as 'debouncing'). Values of 0.1 or 0.2 seconds usually work well.

Copy the example over to Thonny and give it a go:

# Imports
from machine import Pin
import time

# Set up our button name and GPIO pin number
# Also set the pin as an input and use a pull down
button1 = Pin(13, Pin.IN, Pin.PULL_DOWN)

while True: # Loop forever

    time.sleep(0.2) # Short delay
    
    if button1.value() == 1: #If button 1 is pressed
        print("Button 1 pressed")

Activity 2: Multiple Button Inputs

Let's add our other buttons into the code and change our if statement to make it watch for any of them being pressed.

To do this, we add setup lines for the other buttons, then add additional if statements below the original one - our code will simply check each condition, in order.

If one of the conditions is met (if a button is pressed) it will run the code for that button and then continue to check the remaining statements (and it will do this forever, because we have this in a while True loop):

# Imports
from machine import Pin
import time

# Set up our button names and GPIO pin numbers
# Also set pins as inputs and use pull downs
button1 = Pin(13, Pin.IN, Pin.PULL_DOWN)
button2 = Pin(8, Pin.IN, Pin.PULL_DOWN)
button3 = Pin(3, Pin.IN, Pin.PULL_DOWN)

while True: # Loop forever
    
    time.sleep(0.2) # Short Delay
        
    if button1.value() == 1: # If button 1 is pressed
        
        print("Button 1 pressed")
        
    if button2.value() == 1: # If button 2 is pressed
        
        print("Button 2 pressed")
        
    if button3.value() == 1: # If button 3 is pressed
        
        print("Button 3 pressed")

Activity 3: Multiple Button Inputs with elif and else

What if we wanted to do something more advanced with our buttons?

Maybe we want to ignore buttons 2 and 3 if button 1 is pressed? Do we want something else to happen if none of the buttons are pressed? Perhaps we want something to happen if we hold two buttons down at the same time?

We can do many of these things, and more, by using our if statement with additional statements elif and else. Let's explain how they work before we try them:

The elif statement

The elif statement is short for 'else if'. If your first if statement isn't true, your code will then check each elif statement in order to see if any of those are true.

If one of the elif statements triggers, it will run the code block for that statement only and then stop checking the others in the loop (unlike regular if statements which keep checking each one after the other regardless of what happens).

In the example below, we use if then elif to tell our code to check if button 1 is being pressed, and if not, check button 2, and if button 2 isn't being pressed, check button 3.

Tip: There should always be an initial 'if' statement first

# Imports
from machine import Pin
import time

# Set up our button names and GPIO pin numbers
# Also set pins as inputs and use pull downs
button1 = Pin(13, Pin.IN, Pin.PULL_DOWN)
button2 = Pin(8, Pin.IN, Pin.PULL_DOWN)
button3 = Pin(3, Pin.IN, Pin.PULL_DOWN)

while True: # Loop forever
    
    time.sleep(0.2) # Short Delay
        
    if button1.value() == 1: # If button 1 is pressed
        
        print("Button 1 pressed")
        
    elif button2.value() == 1: # If button 2 is pressed
        
        print("Button 2 pressed")
        
    elif button3.value() == 1: # If button 3 is pressed
        
        print("Button 3 pressed")

The else statement

The else statement says "if none of the statements above have their conditions met, do this instead". It can be useful if you want something to always happen when none of the above if/elif statements are being met.

Here's a short example (using just two buttons) you can try where we always print "No button presses" if none of the buttons are being pressed. The commentary shows you where the else statement is being used:

# Imports
from machine import Pin
import time

# Set up our button names and GPIO pin numbers
# Also set pins as inputs and use pull downs
button1 = Pin(13, Pin.IN, Pin.PULL_DOWN)
button2 = Pin(8, Pin.IN, Pin.PULL_DOWN)

while True: # Loop forever
    
    time.sleep(0.2) # Short Delay
        
    if button1.value() == 1: # If button 1 is pressed
        
        print("Button 1 pressed")
        
    elif button2.value() == 1: # If button 2 is pressed
        
        print("Button 2 pressed")
        
    else: # If no buttons are being pressed
        
        print("No button presses")

The Code

Now that we know what elif and else do, let's put them to work whilst adding our LEDs back into our program.

The code below first checks if we've held buttons 1 and 2 together. It does this by using an if statement with 'and' between two conditions, asking for both of these to be met at the same time. If the buttons are both held down, the green LED will light.

We then use an elif statement to check if button 1 is being pressed on its own, if so, the amber LED will light.

Then we use an else statement to light the red LED (and turn all others off) if nothing is being pressed. Button 3 isn't being used for this example. All of this is in a while True loop to make it run forever:

# Imports
from machine import Pin
import time

# Set up our button names and GPIO pin numbers
# Also set pins as inputs and use pull downs
button1 = Pin(13, Pin.IN, Pin.PULL_DOWN)
button2 = Pin(8, Pin.IN, Pin.PULL_DOWN)
button3 = Pin(3, Pin.IN, Pin.PULL_DOWN)

# Set up our LED names and GPIO pin numbers
red = Pin(18, Pin.OUT)
amber = Pin(19, Pin.OUT)
green = Pin(20, Pin.OUT)

while True: # Loop forever
    
    time.sleep(0.2) # Short Delay
        
    if button1.value() == 1 and button2.value() == 1: # If button 1 and 2 are pressed at the same
        
        print("Buttons 1 and 2 pressed")
        green.value(1) # green LED on
        red.value(0) # red LED off

    elif button1.value() == 1: # If button 1 is pressed
        
        print("Button 1 pressed")
        amber.value(1) # amber LED on
        red.value(0) # red LED off

    else: # If no buttons are being pressed
        
        red.value(1) # red LED on
        amber.value(0) # amber LED off
        green.value(0) # green LED off

Activity 4: This button or that button?

Another trick we can use with buttons and if statements is to use 'or' between conditions to check if one of our buttons is being pressed - but make them all trigger the same result.

We've added an example below which looks for either button 1 or 2 being pressed.

Once you've tried it, why not have a go at adding button 3 back into the code, and then make all three buttons trigger the LED (hint: just add another 'or' to the same line in the same way):

# Imports
from machine import Pin
import time

# Set up our button names and GPIO pin numbers
# Also set pins as inputs and use pull downs
button1 = Pin(13, Pin.IN, Pin.PULL_DOWN)
button2 = Pin(8, Pin.IN, Pin.PULL_DOWN)

# Set up our LED names and GPIO pin numbers
green = Pin(20, Pin.OUT)

while True: # Loop forever
    
    time.sleep(0.2) # Short Delay
        
    if button1.value() == 1 or button2.value() == 1: # If button 1 OR button 2 is pressed
        
        print("Button 1 or 2 pressed")
        
        green.value(1) # green LED on
        time.sleep(2)
        green.value(0) # green LED off

Activity 5: Toggling with buttons

Another handy feature we can use with GPIO pins is 'toggle'. As you might have guessed, this toggles a pin's status from HIGH to LOW to HIGH and so on.

The example below is mostly the same but uses button 1 to toggle the red LED on and off.

Once you've tried the code below, why not try adding the other buttons and LEDs back in, toggling each of them?

# Imports
from machine import Pin
import time

# Set up our button names and GPIO pin numbers
# Also set pins as inputs and use pull downs
button1 = Pin(13, Pin.IN, Pin.PULL_DOWN)

# Set up our LED names and GPIO pin numbers
red = Pin(18, Pin.OUT)

while True: # Loop forever

    time.sleep(0.5) # Short delay
            
    if button1.value() == 1: #If button 1 is pressed
        
        print("Button 1 pressed")
        
        red.toggle() # Toggle Red LED on/off

Day #3 Complete!

Great job makers, you’ve now got the skills to use physical inputs with MicroPython (which will come in handy for the rest of the calendar) and can code if statements in all sorts of interesting new ways!

Today you have learnt:

  • How to create a circuit with physical inputs
  • How to code physical inputs with MicroPython
  • What if statements are and how to use them
  • How to use elif and else within if statements
  • How to use 'and and 'or' within if statement conditions
  • Combined physical inputs with physical outputs

As always, please do not disassemble the circuit until tomorrow where we will explore the next fun component - see you then!


We used Fritzing to create the breadboard wiring diagram images for this page.

Featured Products

Maker Advent Calendar - The 12 Projects of Codemas (inc. Raspberry Pi Pico H) by The Pi Hut - The Pi HutMaker Advent Calendar - The 12 Projects of Codemas (inc. Raspberry Pi Pico H) by The Pi Hut - The Pi Hut

54 comments

M.K

M.K

nice

nice

Julie Hunt

Julie Hunt

Disaster! There are no buttons in my box! I have only got the breadboard and jumper wires. I’ve checked all the boxes and they are not in anywhere. What should I do now?

Disaster! There are no buttons in my box! I have only got the breadboard and jumper wires. I’ve checked all the boxes and they are not in anywhere. What should I do now?

jerry311

jerry311

I find it misleading (at least for me) that all the colons are in the same grey color as the comments.
Would it be possible change the colors in t code formatting a bit?
Maybe use the same blue as the ‘while’ or ‘if’ they belong together anyway.

I find it misleading (at least for me) that all the colons are in the same grey color as the comments.
Would it be possible change the colors in t code formatting a bit?
Maybe use the same blue as the ‘while’ or ‘if’ they belong together anyway.

Gavin

Gavin

While I’m enjoying this, as learning python basics has been on my to do list forever, and I dont know if it was changed in later kits, but my “1st edition” i.e. the inital batch came with white jumper wires. Coloured wires that would match the images may have made it a little easier to see you had the right wire in the right holes.

While I’m enjoying this, as learning python basics has been on my to do list forever, and I dont know if it was changed in later kits, but my “1st edition” i.e. the inital batch came with white jumper wires. Coloured wires that would match the images may have made it a little easier to see you had the right wire in the right holes.

Leave a comment

All comments are moderated before being published.

This site is protected by hCaptcha and the hCaptcha Privacy Policy and Terms of Service apply.