Raspberry Pi Pico
Digital IN - Pushbuttons

We want to be able to use inputs in our circuits. Pushbuttons also need us to use the built-in resistors. Here is a quick 3-button circuit with the buttons connected to GND and to pins GP18, GP19 and GP20. I like programming circuits with switches because you can be quite creative in your programming.

Pico Circuit

Here is the same circuit in a Fritzing diagram,

Pico Circuit

The first program is simply to test the button readings and to see what we get back,

import board 
from time import sleep 
from digitalio import DigitalInOut, Pull 

btnA = DigitalInOut(board.GP18) 
btnA.switch_to_input(pull = Pull.UP) 

btnB = DigitalInOut(board.GP19) 
btnB.switch_to_input(pull = Pull.UP) 

btnC = DigitalInOut(board.GP20) 
btnC.switch_to_input(pull = Pull.UP) 

while True: 
    print(btnA.value, btnB.value, btnC.value) 
    sleep(0.5) 

This program uses 'follower' variables to make it possible to track the pressing and the release of each button.

import board 
from time import sleep 
from digitalio import DigitalInOut, Pull 
 
btnA = DigitalInOut(board.GP18) 
btnA.switch_to_input(pull = Pull.UP) 

btnB = DigitalInOut(board.GP19) 
btnB.switch_to_input(pull = Pull.UP) 

btnC = DigitalInOut(board.GP20) 
btnC.switch_to_input(pull = Pull.UP) 

lastA = lastB = lastC = 1 

while True: 
    if btnA.value != lastA: 
        if btnA.value: 
            print("A released") 
        else: 
            print("A pressed") 
    if btnB.value != lastB: 
        if btnB.value: 
            print("B released") 
        else: 
            print("B pressed") 
    if btnC.value != lastC: 
        if btnC.value: 
            print("C released") 
        else: 
            print("C pressed") 
    lastA = btnA.value 
    lastB = btnB.value 
    lastC = btnC.value
    sleep(0.01) 

Since our buttons have two states, we can map these onto binary place values. Grouping those binary values together means that we can use a single integer to represent all of the button states. That also means that we can use a single comparison to determine if there was a change of state for any of the buttons.

import board 
from time import sleep 
from digitalio import DigitalInOut, Pull 

# set up pins 
btn_pins = [board.GP18, board.GP19, board.GP20] 
btns = [DigitalInOut(p) for p in btn_pins] 

# set up as buttons 
for b in btns: 
    b.switch_to_input(pull = Pull.UP) 

# function to read buttons into a binary pattern, 1 for pressed 
def read_btns(btn_list): 
    result = 0 
    for i, b in enumerate(btn_list): 
        result +=  (b.value^1)<<i 
    return result 

# function to determine if a specific button is pressed
def pressed(pattern, b): 
    return pattern>>b & 1 

previous = 0 

while True: 
    reading = read_btns(btns) 
    if reading!=previous: 
        if pressed(reading, 0): 
            print("Button 0 was pressed.") 
        if pressed(reading, 1): 
            print("Button 1 was pressed.") 
        if pressed(reading, 2): 
            print("Button 2 was pressed.") 
    previous = reading 
    sleep(0.01) 

The final program uses binary numbers to track the press, hold and release states of each button between readings. Lists of buttons are created and printed. The btn_changes function accepts the current and previous states along with the number of buttons being used. It then creates a 2 bit integer for each button. 01 (1) means that the button was previously not pressed and now is pressed, 10 (2) means that the button has been released. 11 (3) means that the button was held down since last being read. A reading of 00 (0) indicates a button not being pressed at all.

import board 
from time import sleep 
from digitalio import DigitalInOut, Pull 

# set up pins 
btn_pins = [board.GP18, board.GP19, board.GP20] 
btns = [DigitalInOut(p) for p in btn_pins] 

# set up as buttons 
for b in btns: 
    b.switch_to_input(pull = Pull.UP) 

# function to read buttons into a binary pattern, 1 for pressed 
def read_btns(btn_list): 
    result = 0 
    for i, b in enumerate(btn_list): 
        result +=  (b.value^1)<<i 
    return result 

def pressed(pattern, b): 
    return pattern>>b & 1 

def btn_changes(current, last, n): 
    return [((last >> i & 1)<<1) + (current >> i & 1) for i in range(n)] 

previous = 0 
while True: 
    reading = read_btns(btns) 
    if reading!=previous: 
        states = btn_changes(reading, previous, 3) 
        press = [i for i,e in enumerate(states) if e==1] 
        release = [i for i,e in enumerate(states) if e==2] 
        held = [i for i,e in enumerate(states) if e==3] 
        print("Pressed", press, "Released:", release, "Held:", held) 
    previous = reading 
    sleep(0.01)