Back

Activity 2.6: LED Array Animation

divider

Activity 2.6

LED Array Animation

Key Concepts

Lists of Objects

Functions Calling Functions

Animation

Two More LEDs

Activity 2.4 used three LEDs. Today you add two more and make the whole row animate — lights that move, fill, and flash on command.

The Problem With Five Variables

led1 = Pin(28, Pin.OUT)
led2 = Pin(29, Pin.OUT)
led3 = Pin(30, Pin.OUT)
led4 = Pin(31, Pin.OUT)
led5 = Pin(32, Pin.OUT)

Five separate names. To do anything to all of them you write five lines — and to make a light move, you write a lot more than five.

You Have Seen This Problem Before

Back in Activity 1.18, score1, score2, and score3 became a list. The same fix works here.

leds = [
Pin(28, Pin.OUT),
Pin(29, Pin.OUT),
Pin(30, Pin.OUT),
]

A list can hold anything — numbers, strings, and objects, like the Pin objects you have been making since 2.3.

One Loop, Every LED

for led in leds:
led.value(1)

Exactly the traversal loop from Activity 1.20 — except each led is a real pin on a real board, so this loop lights up hardware.

What Is an Animation, Really?

An animation is nothing more than a pattern of on and off, separated by pauses. Change the pattern and you change the effect:

  • Chase — one light on at a time, moving down the row
  • Fill — each light joins the ones before it
  • Blink All — the whole row together

You already built Fill in 2.4. It was the countdown.

Functions Calling Functions

def blink_all(leds, wait, times):
for i in range(times):
all_on(leds)
time.sleep(wait)
all_off(leds)
time.sleep(wait)

blink_all() does not touch a single pin itself — it calls all_on() and all_off(). Small functions stack into bigger ones.

Note the Unused Loop Variable

for i in range(times): — and i is never used, exactly like the liftoff blink in Activity 2.4. The loop is counting repetitions, nothing more.

Today's Objectives

  • Storing a group of Pin objects in a list
  • Traversing the array with a for loop to build an animation
  • Calling one function from inside another
  • Letting the user pick an animation from a menu

Key Terms

LED Array
A row of LEDs treated as one group instead of as separate lights.
List of Objects
A list whose elements are objects rather than plain numbers or strings — here, one Pin per LED.
Animation
A pattern of on/off states separated by pauses, producing the illusion of movement.

'F' → Fullscreen

divider

Build

Create a new MicroPython program named 2-6-led-array.


Task 1: Wire the Array and Light It Up

  • Keep Activity 2.4's three LEDs and add two more, with their own resistors, on GPIO 31 and 32.
  • Store all five Pin objects in one list named leds.
  • Turn every LED on with a single for loop, to prove all five are wired correctly.

The two new pins sit immediately to the left of 30 in the same block on the top header, so the five you need run 32, 31, 30, 29, 28 reading left to right:

The SparkFun IoT RedBoard RP2350 with the five pins labeled 32, 31, 30, 29, and 28 outlined together on the top headerCircuit diagram showing five LEDs, each with its own resistor, wired to GPIO 28 through 32 and sharing a common ground, labeled with their list positions leds[0] through leds[4]

Plug them in physically left to right in list order. The order the LEDs sit in your breadboard is the order the animation appears to move. If your chase looks like it is jumping around instead of sweeping, the wiring order does not match the list order — the code is probably fine.

[PHOTO PLACEHOLDER — Task 1: Five LEDs Wired in a Row, All Lit]
LED Array Animation
from machine import Pin
import time
leds = [
Pin(28, Pin.OUT),
Pin(29, Pin.OUT),
Pin(30, Pin.OUT),
Pin(31, Pin.OUT),
Pin(32, Pin.OUT),
]
for led in leds:
led.value(1)

Task 2: The Chase

  • Change the loop so each LED turns on, pauses briefly, then turns off before the next one lights.
  • Adjust the pause until the movement reads as a single light traveling down the row.
LED Array Animation
from machine import Pin
import time
leds = [
Pin(28, Pin.OUT),
Pin(29, Pin.OUT),
Pin(30, Pin.OUT),
Pin(31, Pin.OUT),
Pin(32, Pin.OUT),
]
for led in leds:
led.value(1)
time.sleep(0.1)
led.value(0)
[PHOTO PLACEHOLDER — Task 2: Chase Mid-Sweep, One LED Lit]

Task 3: Two Animations, Two Functions

  • Write all_off(leds), which turns every LED off.
  • Move your chase into a function chase(leds, wait).
  • Add a second animation fill(leds, wait), where each LED stays lit as the next joins — then clears.
  • Run one after the other.
LED Array Animation
from machine import Pin
import time
leds = [
Pin(28, Pin.OUT),
Pin(29, Pin.OUT),
Pin(30, Pin.OUT),
Pin(31, Pin.OUT),
Pin(32, Pin.OUT),
]
def all_off(leds):
for led in leds:
led.value(0)
def chase(leds, wait):
for led in leds:
led.value(1)
time.sleep(wait)
led.value(0)
def fill(leds, wait):
for led in leds:
led.value(1)
time.sleep(wait)
all_off(leds)
chase(leds, 0.1)
fill(leds, 0.2)

Task 4: Blink All

  • Write all_on(leds) to match all_off(leds).
  • Write blink_all(leds, wait, times) that flashes the whole row a given number of times — by calling all_on() and all_off(), not by touching pins directly.
LED Array Animation
from machine import Pin
import time
leds = [
Pin(28, Pin.OUT),
Pin(29, Pin.OUT),
Pin(30, Pin.OUT),
Pin(31, Pin.OUT),
Pin(32, Pin.OUT),
]
def all_on(leds):
for led in leds:
led.value(1)
def all_off(leds):
for led in leds:
led.value(0)
def chase(leds, wait):
for led in leds:
led.value(1)
time.sleep(wait)
led.value(0)
def fill(leds, wait):
for led in leds:
led.value(1)
time.sleep(wait)
all_off(leds)
def blink_all(leds, wait, times):
for i in range(times):
all_on(leds)
time.sleep(wait)
all_off(leds)
time.sleep(wait)
chase(leds, 0.1)
fill(leds, 0.2)
blink_all(leds, 0.2, 5)

Task 5: The Animation Menu

  • Replace the three fixed calls with a menu that prints the options and reads the user's choice.
  • Run the matching animation, then show the menu again — the same sentinel while pattern you used for the task-list app in Activity 1.20.
  • Quit cleanly on q, turning every LED off on the way out.
LED Array Animation
from machine import Pin
import time
leds = [
Pin(28, Pin.OUT),
Pin(29, Pin.OUT),
Pin(30, Pin.OUT),
Pin(31, Pin.OUT),
Pin(32, Pin.OUT),
]
def all_on(leds):
for led in leds:
led.value(1)
def all_off(leds):
for led in leds:
led.value(0)
def chase(leds, wait):
for led in leds:
led.value(1)
time.sleep(wait)
led.value(0)
def fill(leds, wait):
for led in leds:
led.value(1)
time.sleep(wait)
all_off(leds)
def blink_all(leds, wait, times):
for i in range(times):
all_on(leds)
time.sleep(wait)
all_off(leds)
time.sleep(wait)
all_off(leds)
running = True
while running:
print()
print("1 - Chase")
print("2 - Fill")
print("3 - Blink All")
print("q - Quit")
choice = input("Pick an animation: ")
if choice == "1":
chase(leds, 0.1)
elif choice == "2":
fill(leds, 0.2)
elif choice == "3":
blink_all(leds, 0.2, 5)
elif choice == "q":
running = False
else:
print("Not an option.")
all_off(leds)
print("Goodbye.")

Challenge (Optional): Bounce

  • Add a fourth animation that sweeps down the row and then back again, without repeating the LED at each end twice.
  • You will need to walk the list backwards, which means reaching for a position number instead of for led in leds: — look at leds[0] and leds[4] on the circuit diagram above.
divider

Checkpoint

When you run your script:

  • The menu should appear, listing three animations and a quit option
  • Chase should show one light sweeping cleanly from one end of the row to the other
  • Fill should light each LED in turn, each staying on, then clear the whole row
  • Blink All should flash all five together five times
  • An unrecognized choice should print a message and show the menu again, not crash
  • q should turn every LED off and end the program
divider

Reflection

Answer the following questions before submitting your work.

  1. What did putting the five Pin objects in a list let you do that five separate variables would not?
  2. blink_all() never calls .value() itself. Explain what it does instead, and why that is easier to read than turning five pins on and off inside it.
  3. Your chase() and fill() functions contain almost the same loop. What single difference makes one look like a moving light and the other look like a bar filling up?
divider

Submit

Submit the required files to the appropriate dropbox.

Activity Complete