Thursday 5 January 2023

Interrupt driven buttons on the Raspberry Pi Pico

There are two ways to detect the operation of buttons - polling and interrupt.

Polling involves checking the status of the button, which has to occur each time and can be missed if the program is busy elsewhere. It does have the benefit of conceptual simplicity.

Interrupts requires the program to be literally interrupted when the button is pressed, and code to be executed and then the program resumes its normal course. There are a number of complexities created by this method, especially if the task is complicated (things can be in the process of being changed when the interrupt occurs and so the results may not be predicted). There are additional complexities involved in the Micropython implementation (see the documentation here)

The PIMORONI Inky Pack (described here) is fitted with three buttons.


The objective is the display details of which button has been pressed.

Each button is attached to a GPIO pin (pins 12-14 on the Inky Pack) and can be created as a simple Pin object using the following code (this is for the button A on the Inky Pack).

pin1 = Pin(12,Pin.IN,Pin.PULL_UP)

To use interrupts, set the trigger and the callback handler function.

pin1.irq(trigger=Pin.IRQ_FALLING, handler=callback)

The callback function 
def callback(pin):

Supplies the Pin object to the code in the function.

Though the Pin object requires the pin id (in this case 12), it is not (currently 05/01/2023) possible to obtain the pin id from the Pin object directly.

However it is possible to check the equivalence of the supplied Pin against known pins:

def callback(pin):
    if(pin == pin1):
        print("Pin 1")

This means the same callback function can be used for all three pins, the equivalence check defines which pin is calling the callback function.

By using the code below, the following text is printed to the REPL console after the three buttons are pressed within the ten second cycle time of the loop and button B is pressed in the next loop.

cycle
Pin 1
Pin 2
Pin 3
cycle
Pin 2

Code

from machine import Pin
import time

# Set pins to the three buttons on the Inky Pack
pin1 = Pin(12,Pin.IN,Pin.PULL_UP)
pin2 = Pin(13,Pin.IN,Pin.PULL_UP)
pin3 = Pin(14,Pin.IN,Pin.PULL_UP)

# Define callback function for the interrupt
def callback(pin):
    if(pin == pin1):
        print("Pin 1")
    if(pin == pin2):
        print("Pin 2")
    if(pin == pin3):
        print("Pin 3")

# Set interrupt trigger and callback handler
pin1.irq(trigger=Pin.IRQ_FALLING, handler=callback)
pin2.irq(trigger=Pin.IRQ_FALLING, handler=callback)
pin3.irq(trigger=Pin.IRQ_FALLING, handler=callback)

# Infinite loop, every ten seconds it prints cycle.
while True:
    time.sleep(10)
    print("cycle")

References