Here's a more interesting example that uses tasks to control the direction and speed of a NeoPixel animation. This example has been tested on an Adafruit QT Py RP2040, with a 24-NeoPixel ring connected to board.A0
. Three pushbuttons are connected to board.A1
, board.A2
, and board.A3
; the other side of the buttons is grounded so that pressing the buttons brings the pins low.
Pressing button A1 will reverse the direction of the animation. Pressing A2 and A3 will slow down or speed up the animation by changing the delay between animation cycles.
As in the previous examples on the Communicating Between Tasks page, a shared object is used to communicate between the task using the values and the tasks settings the values.
# SPDX-FileCopyrightText: 2022 Dan Halbert for Adafruit Industries # # SPDX-License-Identifier: MIT import asyncio import board import keypad import neopixel from rainbowio import colorwheel pixel_pin = board.A0 num_pixels = 24 pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.03, auto_write=False) class Controls: def __init__(self): self.reverse = False self.wait = 0.0 async def rainbow_cycle(controls): while True: # Increment by 2 instead of 1 to speed the cycle up a bit. for j in range(255, -1, -2) if controls.reverse else range(0, 256, 2): for i in range(num_pixels): rc_index = (i * 256 // num_pixels) + j pixels[i] = colorwheel(rc_index & 255) pixels.show() await asyncio.sleep(controls.wait) async def monitor_buttons(reverse_pin, slower_pin, faster_pin, controls): """Monitor buttons that reverse direction and change animation speed. Assume buttons are active low. """ with keypad.Keys( (reverse_pin, slower_pin, faster_pin), value_when_pressed=False, pull=True ) as keys: while True: key_event = keys.events.get() if key_event and key_event.pressed: key_number = key_event.key_number if key_number == 0: controls.reverse = not controls.reverse elif key_number == 1: # Lengthen the interval. controls.wait = controls.wait + 0.001 elif key_number == 2: # Shorten the interval. controls.wait = max(0.0, controls.wait - 0.001) # Let another task run. await asyncio.sleep(0) async def main(): controls = Controls() buttons_task = asyncio.create_task( monitor_buttons(board.A1, board.A2, board.A3, controls) ) animation_task = asyncio.create_task(rainbow_cycle(controls)) # This will run forever, because no tasks ever finish. await asyncio.gather(buttons_task, animation_task) asyncio.run(main())
Page last edited January 22, 2025
Text editor powered by tinymce.