Writing on a 3×3 LED matrix on my Raspberry Pi

Recently I was given a Rasberry Pi by Jungle Minds, so I had to do a little project with it.

I followed along with this great tutorial on how to create a 3×3 LED matrix. I didn’ t follow the tutorial to the letter, for instance I used the gpiozero library and made a custom function to write texts.

Proof 🙂

The code

Take a look at the code on BitBucket (might be more recent) or just look at it here :).

# -*- coding: utf-8 -*-

"""Render text on a 3x3 led matrix on the Raspberry Pi.

Author: Julius huijnk

Heavily inspired on these YouTube videos by Gaven MacDonald:
'Raspberry Piu Project: The LED Matrix'


Gaven MacDonald uses the RPi library, this uses the gpiozero library.
"""

from gpiozero import LED
from time import sleep


anodeLeft = LED(4)     # Left column
anodeMiddle = LED(17)  # Middle column
anodeRight = LED(27)   # Right column

cathodeFront = LED(25)   # Front row
cathodeMiddle = LED(24)  # Middle row
cathodeBack = LED(23)    # Back row

anodes = [anodeLeft, anodeMiddle, anodeRight]
cathodes = [cathodeFront, cathodeMiddle, cathodeBack]

# Frames, based on symbols
f_ = [[0, 0, 0],
      [0, 0, 0],
      [0, 0, 0]]

f__ = [[0, 0, 0],
       [0, 0, 0],
       [1, 1, 1]]

f_a = [[0, 1, 0],
       [1, 1, 1],
       [1, 0, 1]]

f_b = [[1, 1, 0],
       [1, 1, 1],
       [1, 1, 1]]

f_c = [[1, 1, 1],
       [1, 0, 0],
       [1, 1, 1]]

f_d = [[1, 1, 0],
       [1, 0, 1],
       [1, 1, 0]]

f_e = [[1, 1, 1],
       [1, 1, 0],
       [1, 1, 1]]

f_f = [[1, 1, 1],
       [1, 1, 0],
       [1, 0, 0]]

f_g = [[1, 1, 0],
       [1, 0, 1],
       [1, 1, 1]]

f_h = [[1, 0, 1],
       [1, 1, 1],
       [1, 0, 1]]

f_i = [[1, 1, 1],
       [0, 1, 0],
       [1, 1, 1]]

f_j = [[0, 0, 1],
       [1, 0, 1],
       [1, 1, 1]]

f_k = [[1, 0, 1],
       [1, 1, 0],
       [1, 0, 1]]

f_l = [[1, 0, 0],
       [1, 0, 0],
       [1, 1, 1]]

f_m = [[1, 1, 1],
       [1, 1, 1],
       [1, 0, 1]]

f_n = [[1, 1, 1],
       [1, 0, 1],
       [1, 0, 1]]

f_o = [[1, 1, 1],
       [1, 0, 1],
       [1, 1, 1]]

f_p = [[1, 1, 1],
       [1, 1, 1],
       [1, 0, 0]]

f_q = [[1, 1, 1],
       [1, 1, 1],
       [0, 0, 1]]

f_r = [[1, 1, 1],
       [1, 0, 0],
       [1, 0, 0]]

f_s = [[0, 1, 1],
       [0, 1, 0],
       [1, 1, 0]]

f_t = [[1, 1, 1],
       [0, 1, 0],
       [0, 1, 0]]

f_u = [[1, 0, 1],
       [1, 0, 1],
       [1, 1, 1]]

f_v = [[1, 0, 1],
       [1, 0, 1],
       [0, 1, 0]]

f_w = [[1, 0, 1],
       [1, 1, 1],
       [1, 1, 1]]

f_x = [[1, 0, 1],
       [0, 1, 0],
       [1, 0, 1]]

f_y = [[1, 0, 1],
       [0, 1, 0],
       [0, 1, 0]]

f_z = [[1, 1, 0],
       [0, 1, 0],
       [0, 1, 1]]

symbol_frames = {" ": f_,
                 "_": f__,
                 "a": f_a,
                 "b": f_b,
                 "c": f_c,
                 "d": f_d,
                 "e": f_e,
                 "f": f_f,
                 "g": f_g,
                 "h": f_h,
                 "i": f_i,
                 "j": f_j,
                 "k": f_k,
                 "l": f_l,
                 "m": f_m,
                 "n": f_n,
                 "o": f_o,
                 "p": f_p,
                 "q": f_q,
                 "r": f_r,
                 "s": f_s,
                 "t": f_t,
                 "u": f_u,
                 "v": f_v,
                 "w": f_w,
                 "x": f_x,
                 "y": f_y,
                 "z": f_z}


def make_animation(text):
    """Splits text in symbols and returns list of frames based on each symbol"""
    frames = []

    # Splits text in separate symbols. For example "hi" becomes ["h", "i"]
    symbols = list(text)

    for symbol in symbols:
        # Retreive frame based on symbol. For example for "e" it adds f_e
        frames += [symbol_frames[symbol]]
    return frames


def set_cathodes(on=True):
    """Turns on/off all cathodes.
    With all anode on, turning off all cathodes would turn all leds on
    """
    for cathode in cathodes:
        if on:
            cathode.on()
        else:
            cathode.off()


def set_rows(front, middle, back):
    """Assuming the anode for this column is on
    Then for every true value a led will turn on
    Calling this function, 0 and 1 can be used for True and False values
    """
    # First set all led lights off
    set_cathodes(on=True)
    if front:
        cathodeFront.off()   # Turn Led on
    if middle:
        cathodeMiddle.off()  # Turn Led on
    if back:
        cathodeBack.off()    # Turn Led on


def setColumn(sleep_time, column_nr, front, middle, back):
    """For every column (anode) the Leds are set on/off
    sleep_time sets how long all leds in this column will be on

    Since we don"t want user to notice each column being lighted separately,
    the sleep_time should be rather short, like 0.001 second
    """
    if not front and not middle and not back:
        # No Leds will shine. They will be darker if anode is also off
        anodes[column_nr].off()
        set_cathodes(on=False)
        sleep(sleep_time)
    else:
        # At least one led will shine
        anodes[column_nr].on()
        set_rows(front, middle, back)
        sleep(sleep_time)
        anodes[column_nr].off()
        set_cathodes(on=False)


def render_frame(s, frame):
    """Goes over very column to display one frame"""
    for column_nr, rows in enumerate(frame):
        setColumn(sleep_time=s,
                  column_nr=column_nr,
                  front=rows[0],
                  middle=rows[1],
                  back=rows[2])


def set_frame(frame_time, frame):
    """Makes frame render a (large) number of times, so the user has time to
    see it. frame_time sets how long user will see this frame.
    """
    # Time spent on each colum is 1/3 of frame_time
    # 160 with .002 is roughly a second (0.002 x 3 x 160 = 0.96 sec)
    # range needs int, so the float that might occur is converted to int
    for _ in range(int(round(160 * frame_time))):
        render_frame(.002, frame)


def present_text(text, times=1, frame_time=0.3):
    """Presents the text on a 3x3 led screen."""

    # Make frames based on each symbol in the text
    word_frames = make_animation(text.lower())

    for _ in range(times):
        for word_frame in word_frames:
            set_frame(frame_time, word_frame)  # Show symbol frame
            set_frame(frame_time, f_)          # Empty frame


def test_make_animation():
    """Test for make_animation function"""
    assert([f_a, f_b, f_c], make_animation("abc"))
    print((make_animation("abc")))


# test_make_animation()

present_text("Super", 3, 0.3)

Have fun!