Raspberry Pi Pico with Interrupts: External and Timer Interrupts (MicroPython)

In this guide, we’ll show you how to handle interrupts with the Raspberry Pi Pico using MicroPython and build some project examples with a pushbutton and a PIR motion sensor. We’ll cover external interrupts and time interrupts.

Raspberry Pi Pico with Interrupts: External and Timer Interrupts (MicroPython)

New to the Raspberry Pi Pico? Check out our eBook: Learn Raspberry Pi Pico/Pico W with MicroPython.

Table of Contents

In this guide, we’ll cover the following subjects:

Prerequisites – MicroPython Firmware

To follow this tutorial, you need MicroPython firmware installed on your Raspberry Pi Pico board. You also need an IDE to write and upload the code to your board.

The recommended MicroPython IDE for the Raspberry Pi Pico is Thonny IDE. Follow the next tutorial to learn how to install Thonny IDE, flash MicroPython firmware, and upload code to the board.

Introducing Interrupts

Interrupts are useful for making things happen automatically in microcontroller programs and can help solve timing problems. Interrupts and event handling provide mechanisms to respond to external events, enabling your Raspberry Pi Pico to react quickly to changes without continuously polling (continuously checking the current value of a pin or variable).

What are Interrupts?

Interrupts are signals that pause the normal execution flow of a program to handle a specific event. When an interrupt happens, the processor stops the execution of the main program to execute a task and then gets back to the main program. That task is also referred to as an interrupt handling routine, as shown in the figure below.

How interrupts work

Using interrupts is especially useful to trigger an action whenever motion is detected or whenever a pushbutton is pressed without the need for constantly checking its state; or to make something happen periodically without constantly checking the time.

Types of Interrupts

There are different types of interrupts: external interrupts and timed interrupts.

  1. External Interrupts: triggered by external signals such as a button press or a sensor reading—this is hardware-based and associated with a specific GPIO pin. When the state of a pin changes, it will trigger a task.
  2. Timed Interrupts (timers): initiated based on time intervals, enabling periodic actions— this uses the RP2040’s (or RP2350 depending on the Raspberry Pi Pico version) hardware timer to trigger callbacks at regular intervals.

External Interrupts in MicroPython

To set an interrupt in MicroPython, you need to follow the next steps:

1. Define an interrupt handling function

The interrupt handling function should be as simple as possible, so the processor gets back to the execution of the main program quickly. The best approach is to signal the main code that the interrupt has happened by using a global variable.

The interrupt handling function should accept a parameter of type Pin. This parameter is returned to the callback function and it refers to the GPIO that caused the interrupt. You’ll better understand these concepts when we start testing some examples.

def handle_interrupt(pin):

2. Set up the interrupt pin as an input. For example:

interrupt_pin = Pin(21, Pin.IN)

3. Attach an interrupt to that pin by calling the irq() method:

interrupt_pin.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)

The irq() method accepts the following arguments:

  • trigger: this defines the trigger mode. There are 3 different conditions:
    • Pin.IRQ_FALLING: to trigger the interrupt whenever the pin goes from HIGH to LOW;
    • Pin.IRQ_RISING: to trigger the interrupt whenever the pin goes from LOW to HIGH.
    • Pin.IRQ_LOW_LEVEL: to trigger the interrupt when the pin is LOW.
    • Pin.IRQ_HIGH_LEVEL: to trigger the interrupt when the pin is HIGH.
  • handler: this is the function that is called when an interrupt is detected, in this case, the handle_interrupt() function.

The following picture will help you better understand the different trigger modes.

Interrupt modes

External Interrupts with a Pushbutton (Examples)

To demonstrate how to handle interrupts, we’ll build some simple projects with a pushbutton and an LED. Wire a pushbutton to GPIO 21 and an LED to GPIO 20.

Here’s a list of the parts you need for these examples:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Circuit Diagram

For the examples in this section, connect an LED to GPIO20 and a pushbutton to GPIO21. You can use the following diagram as a reference.

Raspberry Pi Pico Pushbutton LED Circuit

Recommended reading: Raspberry Pi Pico and Pico W Pinout Guide: GPIOs Explained.

Example 1: Detecting a Pushbutton Press

This is one of the simplest examples to demonstrate how interrupts work. Copy the following code to Thonny IDE.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/

from machine import Pin

button = Pin(21, Pin.IN, Pin.PULL_DOWN)

def button_pressed(pin):
    print("Button Pressed!")

# Attach the interrupt to the button's rising edge
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)

View raw code

In this example, you create an input object called button. [Learn more about RPi Pico Inputs here]

button = Pin(21, Pin.IN, Pin.PULL_DOWN)

Then, you add an interrupt to that pin as follows:

button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)

This line means that when the button signal goes into RISING mode (from LOW to HIGH), the button_pressed function will be called.

The button_pressed function, simply prints on the Shell that the button was pressed.

def button_pressed(pin):
    print("Button Pressed!")

Notice that the definition of the function comes before creating the interrupt. In MicroPython, any user-defined function must be defined before being called.

Testing the Code

Run the previous code on your Raspberry Pi Pico board. You’ll get a message on the Shell every time you press the pushbutton.

Raspberry Pi Pico Detect a Pushbutton Press
Raspberry Pi Pico Detect a Pushbutton Press - Micropython Shell Thonny IDE

Example 2: Counting the Number of Button Presses

In this example, we’ll count the number of button presses with the help of a global variable. This will help you better understand how global variables work.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/

from machine import Pin

button = Pin(21, Pin.IN, Pin.PULL_DOWN)
counter = 0  # Initialize the button press count

def button_pressed(pin):
    global counter # Declare variable as global
    counter +=1
    print("Button Pressed! Count: ", counter)

# Attach the interrupt to the button's rising edge
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)

View raw code

In this example, we create a global variable called counter — it is declared and initialized outside the button_pressed function.

counter = 0  # Initialize the button press count

To use that variable inside the function, we need to use the keyword global within the function— this way, the variable counter is defined globally, making it accessible and modifiable both inside and outside the function.

When the button is pressed and the button_pressed function is called, the global counter variable is incremented, and its updated value is printed.

global counter # Declare variable as global
counter +=1
print("Button Pressed! Count: ", counter)

Note: counter +=1 is short for counter = counter +1

Testing the Code

Run the previous code on your Raspberry Pi Pico. Notice that it will print on the Shell the number of times you pressed the button.

pushbutton counter Raspberry Pi Pico Micropython Thonny IDE

Example 3: Toggling an LED on each Button Press

This is similar to the previous example, but we also toggle an LED when you press the pushbutton.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/

from machine import Pin

led = Pin(20, Pin.OUT)
button = Pin(21, Pin.IN, Pin.PULL_DOWN)
counter = 0   # Initialize the button press count

def button_pressed(pin):
    global counter # Declare variable as global
    counter +=1
    print("Button Pressed! Count: ", counter)
    
    # Toggle the LED on each button press
    led.value(not led.value())

# Attach the interrupt to the button's rising edge
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)

View raw code

In this example, we just need to declare a new Pin object for the LED, in this case on GPIO 20.

led = Pin(20, Pin.OUT)

Then, we add the instruction to toggle the LED inside the button_pressed function.

led.value(not led.value())
Raspberry Pi Pico Pushbutton LED on

Button Bouncing

You must have noticed that sometimes, the pushbutton will count more than one press when in fact, you just pressed once. This is called mechanical bouncing, and it’s very common in mechanical buttons like pushbuttons.

debounce a pushbutton

This happens because the electrical contacts inside the button connect and disconnect very quickly before reaching a steady state, which will cause the system to register multiple press events, causing an inaccurate count.

To prevent this issue, we can add some debouncing techniques using delays or timer interrupts. We’ll take a look at timer interrupts and events in the following section, where you’ll learn how to debounce a button.

Other Applications

Besides buttons, external interrupts can be used for a wide variety of applications on the Raspberry Pi Pico, including sensor inputs, rotary encoders, and other real-time event-driven scenarios.

One of the most common applications is for PIR motion sensors. These sensors go to a triggered state (HIGH) for a few seconds after motion is detected. So, using an interrupt in rising mode is a great way to detect when the sensor detects motion.

Recommended reading: Raspberry Pi Pico: Detect Motion using a PIR Sensor (MicroPython).

Raspberry Pi Pico with a PIR motion sensor

There are also other sensors like smoke sensors, rain sensors, water level sensors, and sound sensors, among others, that send a digital signal when the readings cross a certain threshold. Detecting when the sensor sends such a signal can also be achieved with interrupts because we can detect that state without having to constantly poll the value on a certain GPIO.


Timer Interrupts

Using timer interrupts is especially useful to make something happen periodically or after a predefined period without constantly checking the elapsed time.

Timer Interrupts

The MicroPython class Timer

The Micropython machine module comes with a class called Timer that provides methods to execute a callback function periodically within a given period or once after some predefined delay. This is useful to schedule events or to run periodic tasks without the need to constantly check the elapsed time.

Let’s take a quick look at the Timer constructors.

Creating a Timer

To create a timer, call the Timer() constructor as follows:

my_timer = Timer()

Then, you initialize a timer using the init() method on the Timer() object and you pass as argument the timer mode, period, and the callback function. Here’s an example:

my_timer.init(mode=Timer.PERIODIC, period=1000, callback=timer_callback)

This initializes a periodic timer that will run the timer_callback function every 1000 milliseconds (1 second). You can change the period parameter to any desired period.

Instead of calling the callback function periodically, you may also want to run it once after a predefined time. For that, you can use the Timer.ONE_SHOT mode as follows:

my_timer.init(mode=Timer.ONE_SHOT, period=1000, callback=timer_callback)

This line of code configures a timer (my_timer) to run in a one-shot mode, triggering the specified callback function (timer_callback) after 1000 milliseconds.

In this example, you’ll learn how to blink an LED using a Timer. This will help you understand how periodic timers work.

Circuit Diagram

We’ll blink an LED connected to GPIO 20. So, wire an LED to your Raspberry Pi Pico on that GPIO. You can use the following diagram as a reference.

RPi Pico Connected to an LED - schematic diagram

Code

The following example makes use of the Timer class to blink an LED every half a second.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/

from machine import Pin, Timer
from time import sleep

# LED pin
led_pin = 20
led = Pin(led_pin, Pin.OUT)

# Callback function for the timer
def toggle_led(timer):
    led.value(not led.value())  # Toggle the LED state (ON/OFF)

# Create a periodic timer
blink_timer = Timer()
blink_timer.init(mode=Timer.PERIODIC, period=500, callback=toggle_led)  # Timer repeats every half second

# Main loop (optional)
while True:
    print('Main Loop is running')
    sleep(2)

View raw code

In this code, we create a timer called blink_timer:

blink_timer = Timer()

Then, we initialize the timer with the following parameters:

blink_timer.init(mode=Timer.PERIODIC, period=500, callback=toggle_led)

This means this timer will call the toggle_led function every 500 milliseconds, forever (or until you stop the program).

The toggle_led function, as the name suggests, will toggle the LED state:

# Callback function for the timer
def toggle_led(timer):
    led.value(not led.value())  # Toggle the LED state (ON/OFF)

The callback functions for the timer event must take one argument (def toggle_led(timer):). The Timer object is passed automatically as an argument to that function when the event is triggered. You must have that argument even if you don’t use it.

With timers, you can also have other tasks running on the main loop without interfering with each other. For example, in our case, in the main loop, we’ll print a message every two seconds.

while True:
    print('Main Loop is running')
    sleep(2)

Testing the Code

With an LED connected to GPIO 20, run the previous code on your board.

You’ll get the message “Main Loop is running” every two seconds on the Shell, while the LED is blinking every half a second at the same time.

RPi Pico main loop running on Thonny IDE
RPi Pico Blinking LED 1
RPi Pico Blinking LED 1

After testing the previous example, it’s now easy to understand that if you create multiple timers, you can run multiple tasks at different frequencies. In this example, we’ll blink two different LEDs, one every half a second, and another every two seconds.

Circuit Diagram

Wire two LEDs to the Raspberry Pi Pico (to distinguish between the different LEDs, we’ll use different colors):

  • Blue LED: GPIO 19 > will blink every half a second.
  • Green LED: GPIO 20 > will blink every two seconds;

You can use the following diagram as a reference to wire the circuit.

Raspberry Pi Pico Wiring Two LEDs

Code

The following code uses Timers to blink two different LEDs at different frequencies.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/

from machine import Pin, Timer
from time import sleep

# LEDs
green_led_pin = 19
green_led = Pin(green_led_pin, Pin.OUT)
blue_led_pin = 20
blue_led = Pin(blue_led_pin, Pin.OUT)

# Callback function for the green timer
def toggle_green_led(timer):
    green_led.toggle()  # Toggle the LED state (ON/OFF)
    print('Green LED is: ', green_led.value())

# Callback function for the blue timer
def toggle_blue_led(timer):
    blue_led.toggle()  # Toggle the LED state (ON/OFF)
    print('Blue LED is: ', blue_led.value())

# Create periodic timers
green_timer = Timer()
blue_timer = Timer()

# Init the timers
green_timer.init(mode=Timer.PERIODIC, period=500, callback=toggle_green_led)  # Timer repeats every 0.5 second
blue_timer.init(mode=Timer.PERIODIC, period=2000, callback=toggle_blue_led)  # Timer repeats every 2 seconds

# Main loop (optional)
while True:
    print('Main Loop is running')
    sleep(2)

View raw code

In this code, we create two different timers, one for each LED:

green_timer = Timer()
blue_timer = Timer()

Then, we call the corresponding callback functions at different intervals:

# Timer repeats every 0.5 second
green_timer.init(mode=Timer.PERIODIC, period=500, callback=toggle_green_led)
# Timer repeats every 2 seconds
blue_timer.init(mode=Timer.PERIODIC, period=2000, callback=toggle_blue_led)  

The callback functions simply toggle the current LED value:

# Callback function for the green timer
def toggle_green_led(timer):
    green_led.toggle()  # Toggle the LED state (ON/OFF)
    print('Green LED is: ', green_led.value())

# Callback function for the blue timer
def toggle_blue_led(timer):
    blue_led.toggle()  # Toggle the LED state (ON/OFF)
    print('Blue LED is: ', blue_led.value())

The toggle() function: there’s a method in MicroPython called toggle() that you can use on output Pin objects like LEDs, for example. This changes the state of a digital pin from its current state to the opposite state.

Testing the Code

Run the previous code on the Raspberry Pi Pico. You’ll notice that the two LEDs will blink at different frequencies.

At the same time, you’ll get a message from the while loop every two seconds. This shows that the other tasks don’t interfere with our loop.

RPi Pico multiple timers and loop running

Example 3: Debouncing a Pushbutton with a Timer

As we’ve mentioned previously, we can use timers to help debounce a pushbutton to ensure we don’t get false button presses. There are many ways to debounce a pushbutton, the example below is just one of many possibilities.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/

from machine import Pin, Timer

led = Pin(20, Pin.OUT)
button = Pin(21, Pin.IN, Pin.PULL_DOWN)
counter = 0  # Initialize the button press count
debounce_timer = None

def button_pressed(pin):
    global counter, debounce_timer  # Declare variables as global

    if debounce_timer is None:
        counter += 1
        print("Button Pressed! Count: ", counter)
        
        # Toggle the LED on each button press
        led.toggle()

        # Start a timer for debounce period (e.g., 200 milliseconds)
        debounce_timer = Timer()
        debounce_timer.init(mode=Timer.ONE_SHOT, period=200, callback=debounce_callback)

def debounce_callback(timer):
    global debounce_timer
    debounce_timer = None

# Attach the interrupt to the button's rising edge
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)

View raw code

You should already be familiar with most of the code, so we’ll just take a look at the relevant parts for this example.

This example uses a one-shot timer (debounce_timer) initiated on each button press with a specified debounce period, in this example 200 milliseconds.

debounce_timer.init(mode=Timer.ONE_SHOT, period=200, callback=debounce_callback)

As with previous examples, we attach an interrupt to our pushbutton pin that will trigger the button_pressed function in rising mode (when the button is pressed).

button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)

When the button is pressed, the button_pressed function is called, incrementing the counter, toggling the LED, and starting the one-shot timer for debounce.

counter += 1
print("Button Pressed! Count: ", counter)
# Toggle the LED on each button press
led.toggle()
# Start a timer for debounce period (e.g., 200 milliseconds)
debounce_timer = Timer()
debounce_timer.init(mode=Timer.ONE_SHOT, period=200, callback=debounce_callback)

The debounce_callback function of the timer is called when the one-shot timer expires, resetting the debounce_timer to None.

def debounce_callback(timer):
    global debounce_timer
    debounce_timer = None

If the timer hasn’t yet expired, if another button press is detected, it will not be accounted for because the debounce_timer hasn’t been reset to None:

if debounce_timer is None:

Notice that we make use of global variables so that we can access them throughout all parts of the code, including inside the functions:

global counter, debounce_timer  # Declare variables as global

This is just one of the many ways to debounce a pushbutton.

The use of None

In Python/MicroPython, None is often used as a placeholder or default value to indicate the absence of a meaningful value. In this previous example, None helps us manage the state of the debounce_timer variable.

The debounce_timer is initially set to None to indicate that no debounce timer is currently active.

debounce_timer = None

In the button_pressed function, the following condition checks if there is no active debounce timer.

if debounce_timer is None:

If there is no active timer (None), the button press actions are performed, and a new one-shot timer, debounce_timer is initiated.

debounce_timer = Timer()
debounce_timer.init(mode=Timer.ONE_SHOT, period=200, callback=debounce_callback)

When the one-shot timer expires, the debounce_callback function is called, and it sets debounce_timer back to None, indicating that the debounce period has ended.

def debounce_callback(timer):
    global debounce_timer
    debounce_timer = None

Testing the Code

Run the code on your Raspberry Pi Pico. Press the push button multiple times. You’ll notice that you won’t get false positives anymore. If you do, you need to increase the 200 milliseconds debounce period on the debounce_timer.

debounce_timer.init(mode=Timer.ONE_SHOT, period=200, callback=debounce_callback)
Raspberry Pi Pico Pushbutton LED on
RPi Pico Pushbutton Debounce with Timer

Example 4: Interrupts and Timers with a PIR Motion Sensor

In this example, we’ll exemplify the use of single-shot timers with a PIR motion sensor. We’ll build a simple project with a PIR motion sensor. Whenever motion is detected, we’ll light up an LED for 20 seconds. After that time, the LED will turn off.

Using a PIR motion sensor for LED control

The PIR Motion Sensor

A Passive Infrared (PIR) motion sensor is designed to detect infrared radiation emitted by objects in its field of view. PIR sensors detect changes in infrared radiation, primarily emitted by living things. When there is motion in the sensor’s range, there are fluctuations in the detected infrared radiation. The following picture shows the popular HC-SR501 motion sensor.

HC-SR501 PIR Motion Sensor
HC-SR501 PIR Motion Sensor

For a more in-depth guide about the PIR motion sensor with the Raspberry Pi Pico, we recommend reading the following guide:

The sensor outputs a HIGH signal if it detects movement, or LOW if it doesn’t detect any movement. The digital output from the PIR sensor can be read by a Raspberry Pi Pico GPIO pin, allowing you to program specific actions based on the detected motion status. In this example, we’ll simply light up an LED, but it can be used for useful applications like sending an email, triggering an alarm, etc.

An important concept about PIR motion sensors is the dwell time (reset time or sensor delay)—it is the duration during which a PIR motion sensor’s output remains HIGH after detecting motion before returning to a LOW state.

PIR motion sensor how it works

Parts Required

For this example, we’ll use the following parts:

Note: the Mini AM312 PIR Motion Sensor we’re using in this project operates at 3.3V. However, if you’re using another PIR motion sensor like the HC-SR501, it operates at 5V. You can either modify it to operate at 3.3V or simply power it using the VBUS pin that will output 5V if you’re powering the Raspberry Pi Pico via USB using 5V.

This example can also be made with a pushbutton instead.

In the figure below, we provide the pinout for the Mini AM312 PIR motion sensor. If you’re using another motion sensor, please check its pinout before assembling the circuit.

Mini pir motion sensor pinout

The following table shows the connections between the PIR motion sensor and the Raspberry Pi Pico:

PIR Motion SensorRaspberry Pi Pico
GNDGND
DataAny digital pin (example GPIO 21)
3.3V3V3(OUT)

Circuit Diagram

We’ll wire the PIR motion sensor data pin to GPIO 21 and the LED to GPIO 20.

RPi Pico LED Pushbutton Circuit

Code

The following code will set the PIR motion sensor as an interrupt. When motion is detected, an LED will be turned on for 20 seconds after the last detected movement. After that period, the LED will be turned off, and the motion sensor will be able to detect motion again.

With this example, you’ll see another application of one-shot timers while learning about detecting motion with PIR sensors.

# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-interrupts-micropython/

from machine import Pin, Timer
import time

# PIR sensor pin
pir_pin = 21
# LED pin 
led_pin = 20

# Set up LED and PIR sensor
led = Pin(led_pin, Pin.OUT)
pir = Pin(pir_pin, Pin.IN)

# Create timer
motion_timer = Timer()

# Create timer
motion = False
motion_printed = False

def handle_motion(pin):
    global motion
    motion = True
    motion_timer.init(mode=Timer.ONE_SHOT, period=20000, callback=turn_off_led)

def turn_off_led(timer):
    global motion, motion_printed
    led.off()  # Turn off the LED
    print('Motion stopped!')
    motion = False
    motion_printed = False

# Attach interrupt to the PIR motion sensor
pir.irq(trigger=Pin.IRQ_RISING, handler=handle_motion)

while True:
    if motion and not motion_printed:
        print('Motion detected!')
        led.on()  # Turn on the LED
        motion_printed = True
    elif not motion:
        time.sleep(0.1)
        # Other tasks that you might need to do in the loop

View raw code

How the Code Works

We start by declaring the LED and the PIR motion sensor on the respective GPIO pins they are connected to.

# PIR sensor pin
pir_pin = 21
# LED pin
led_pin = 20
# Set up LED and PIR sensor
led = Pin(led_pin, Pin.OUT)
pir = Pin(pir_pin, Pin.IN)

We create a timer that will be responsible for turning off the LED after 20 seconds since motion was detected.

# Create timer
motion_timer = Timer()

We create two global variables motion, and motion_printed. The motion variable is to signal throughout the code whether motion was detected or not. The motion_printed variable will allow us to check whether the ‘Motion detected!’ message was already printed on the Shell.

# Create global variables
motion = False
motion_printed = False

We attach an interrupt to the PIR motion sensor in rising mode. This means that when motion is detected, the handle_motion function will run.

pir.irq(trigger=Pin.IRQ_RISING, handler=handle_motion)

Things to Consider When Writing ISRs

Interrupts are handled in interrupt service routines (ISR), which is the function that runs when the interrupt happens (in our example, it’s the handle_motion function). When an interrupt happens, the processor stops what it is doing, works temporarily on the ISR, and then gets back to what it was doing before (the main code).

It is a good practice to build ISR as small as possible, so the processor gets back to the execution of the main program quickly. The best approach is to signal the main code that the interrupt has happened by using a flag or a counter, for example. Here, we use the motion variable as a flag to indicate that motion was detected. Then, the main code should have all the things we want to happen when motion is detected like turning an LED on and printing a message on the Shell.

More details about writing ISRs can be found here.

Let’s proceed with the code. Inside the handle_motion function, we set the global variable motion to True, so that we know in all parts of the code that motion was detected, and we initialize a one-shot timer that will turn off the LED after 20 seconds by calling the turn_off_led() function.

def handle_motion(pin):
    global motion
    motion = True
    motion_timer.init(mode=Timer.ONE_SHOT, period=20000, callback=turn_off_led)

In the While loop, we check whether motion was detected or not. If motion has been detected and if the message hasn’t been printed yet on the Shell, we’ll print a message, turn the LED on, and set the motion_printed variable to True.

while True:
    if motion and not motion_printed:
        print('Motion detected!')
        led.on()  # Turn on the LED
        motion_printed = True

After the 20000 milliseconds, the turn_off_led function will run and turn the LED off and set the motion and motion_printed global variables to False.

def turn_off_led(timer):
    global motion, motion_printed
    led.off()  # Turn off the LED
    print('Motion stopped!')
    motion = False
    motion_printed = False

The motion variable can only become True again if motion is detected and the handle_motion function is called.

There are numerous ways to achieve the same result. This is just one of the examples to show you how single-shot timers can be used in your code.

Testing the Code

Run the previous code on your Raspberry Pi Pico. Wave your hand in front of the PIR motion sensor.

RPi Pico Testing a PIR Motion Sensor

It will print a message on the Shell and turn on an LED for 20 seconds.

RPi Pico - Testing the PIR Motion Sensor - Thonny IDE Shell

After 20 seconds, the LED will turn off.

RPi Pico Testing a PIR Motion Sensor

Wrapping Up

In this guide, you learned about interrupts with the Raspberry Pi Pico programmed with MicroPython. We covered external interrupts and timer interrupts.

We hope you’ve found this guide and the examples useful and that you can apply the concepts learned to your projects.

If you want to learn more about programming and controlling the Raspberry Pi Pico using MicroPython, check out our resources:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

1 thought on “Raspberry Pi Pico with Interrupts: External and Timer Interrupts (MicroPython)”

  1. Thank you for posting this. Your tutorials are well written and easy to understand.

    Please consider doing a tutorial in the future on using the Pico for RS485 half-duplex UART communications. I haven’t been able to locate a “direction” output from the PICO UART to control the direction pin of an RS-485 buffer. Most of Microchip’s AVR microcontrollers include such an output, but I haven’t been able to figure out how to get that from the Pico.

    Thank you!

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.