Note

Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.

Why Join?

  • Expert Support: Solve post-sale issues and technical challenges with help from our community and team.

  • Learn & Share: Exchange tips and tutorials to enhance your skills.

  • Exclusive Previews: Get early access to new product announcements and sneak peeks.

  • Special Discounts: Enjoy exclusive discounts on our newest products.

  • Festive Promotions and Giveaways: Take part in giveaways and holiday promotions.

👉 Ready to explore and create with us? Click [here] and join today!

5.4 Displaying Graphics on an 8x8 LED Matrix

In this lesson, we’ll learn how to control an 8x8 LED matrix using the Raspberry Pi Pico 2 and two 74HC595 shift registers. We’ll display patterns and simple graphics by controlling individual LEDs on the matrix.

What You’ll Need

In this project, we need the following components.

It’s definitely convenient to buy a whole kit, here’s the link:

Name

ITEMS IN THIS KIT

LINK

Newton Lab Kit

450+

Newton Lab Kit

You can also buy them separately from the links below.

SN

COMPONENT

QUANTITY

LINK

1

Raspberry Pi Pico 2

1

BUY

2

Micro USB Cable

1

3

Breadboard

1

BUY

4

Jumper Wires

Several

BUY

5

LED Dot Matrix

1

6

74HC595

2

BUY

Understanding the 8x8 LED Matrix

An 8x8 LED matrix consists of 64 LEDs arranged in 8 rows and 8 columns. Each LED can be individually controlled by applying voltage across its row and column. By controlling the current through each pair of rows and columns, we can control each LED to display characters or patterns.

In this setup, we’ll use two 74HC595 shift registers to control the rows and columns of the LED matrix, effectively expanding the number of outputs from the Raspberry Pi Pico 2 while using only a few GPIO pins.

Circuit Diagram

sch_ledmatrix

The 8x8 LED dot matrix is controlled by two 74HC595 shift registers: one controls the rows, and the other controls the columns. These two chips share the Pico’s GPIO pins GP18, GP19, and GP20, greatly conserving the Pico’s I/O ports.

The Pico outputs a 16-bit binary number at a time. The first 8 bits are sent to the 74HC595 controlling the rows, and the last 8 bits are sent to the 74HC595 controlling the columns. This allows the dot matrix to display specific patterns.

Q7’ (Pin 9): This serial data output pin of the first 74HC595 connects to the DS (Pin 14) of the second 74HC595, enabling you to chain multiple 74HC595 chips together.

Wiring Diagram

Building the circuit can be complex, so let’s proceed step by step.

Step 1: First, insert the pico, the LED dot matrix and two 74HC595 chips into breadboard. Connect the 3.3V and GND of the pico to holes on the two sides of the board, then hook up pin16 and 10 of the two 74HC595 chips to VCC, pin 13 and pin 8 to GND.

Note

In the Fritzing image above, the side with label is at the bottom.

wiring_ledmatrix_4

Step 2: Connect pin 11 of the two 74HC595 together, and then to GP20; then pin 12 of the two chips, and to GP19; next, pin 14 of the 74HC595 on the left side to GP18 and pin 9 to pin 14 of the second 74HC595.

wiring_ledmatrix_3

Step 3: The 74HC595 on the right side is to control columns of the LED dot matrix. See the table below for the mapping. Therefore, Q0-Q7 pins of the 74HC595 are mapped with pin 13, 3, 4, 10, 6, 11, 15, and 16 respectively.

74HC595

Q0

Q1

Q2

Q3

Q4

Q5

Q6

Q7

LED Dot Matrix

13

3

4

10

6

11

15

16

wiring_ledmatrix_2

Step 4: Now connect the ROWs of the LED dot matrix. The 74HC595 on the left controls ROW of the LED dot matrix. See the table below for the mapping. We can see, Q0-Q7 of the 74HC595 on the left are mapped with pin 9, 14, 8, 12, 1, 7, 2, and 5 respectively.

74HC595

Q0

Q1

Q2

Q3

Q4

Q5

Q6

Q7

LED Dot Matrix

9

14

8

12

1

7

2

5

wiring_ledmatrix_1

Writing the Code

We’ll write a MicroPython program to display a pattern on the LED matrix.

Note

  • Open the 5.4_8x8_pixel_graphics.py from newton-lab-kit/micropython or copy the code into Thonny, then click “Run” or press F5.

  • Ensure the correct interpreter is selected: MicroPython (Raspberry Pi Pico).COMxx.

import machine
import time

# Define the pins connected to the 74HC595 shift register
sdi = machine.Pin(18, machine.Pin.OUT)   # Serial Data Input
rclk = machine.Pin(19, machine.Pin.OUT)  # Storage Register Clock (RCLK)
srclk = machine.Pin(20, machine.Pin.OUT) # Shift Register Clock (SRCLK)

# Define the glyph data for the letter 'X' with lit pixels and background off
glyph = [0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E]

def hc595_in(dat):
    """
    Shifts 8 bits of data into the 74HC595 shift register.
    """
    for bit in range(7, -1, -1):
        srclk.low()
        sdi.value((dat >> bit) & 1)  # Output data bit by bit
        srclk.high()
        time.sleep_us(1)  # Short delay to ensure proper timing

def hc595_out():
    """
    Latches the data from the shift register to the storage register,
    updating the outputs.
    """
    rclk.high()
    rclk.low()

while True:
    for i in range(8):
        hc595_in(glyph[i])       # Send the column data for the current row
        hc595_in(1 << i)         # Activate the current row
        hc595_out()              # Update the display
        time.sleep_ms(1)         # Delay for visual persistence

When you run this code, the 8x8 LED matrix will display an ‘X’ shape, with the LEDs lighting up to form the pattern of the letter ‘X’ across the matrix.

Understanding the Code

  1. Importing Modules:

    • machine: Provides access to hardware-related functions, such as controlling GPIO pins.

    • time: Used for adding delays to control timing.

  2. Defining Pins:

    • sdi: Sends serial data into the shift register.

    • rclk: Latches the shifted data to the output pins.

    • srclk: Shifts the data into the register on each rising edge.

  3. Defining the Glyph for ‘X’:

    • Each element represents a row in the LED matrix.

    • The hex values correspond to the LEDs that should be lit (0) or off (1) in each row.

    • This pattern forms a symmetrical ‘X’ shape across the matrix.

    glyph = [0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E]
    
  4. Function hc595_in(dat):

    • This function sends 8 bits of data (dat) into the shift register serially.

    • It iterates from the most significant bit to the least significant bit.

    • The srclk pin is toggled to shift each bit into the register.

    • The sdi pin sets the data line high or low depending on the current bit.

    def hc595_in(dat):
        """
        Shifts 8 bits of data into the 74HC595 shift register.
        """
        for bit in range(7, -1, -1):
            srclk.low()
            sdi.value((dat >> bit) & 1)  # Output data bit by bit
            srclk.high()
            time.sleep_us(1)  # Short delay to ensure proper timing
    
  5. Function hc595_out():

    • This function latches the shifted data from the shift register to the output register.

    • A rising edge on the rclk pin transfers the data to the output pins, updating the LEDs.

    def hc595_out():
    
        rclk.high()
        rclk.low()
    
  6. Main Loop:

    • The loop continuously refreshes the display to create a persistent image of the letter ‘X’.

    • The for loop iterates over each row index from 0 to 7.

    • hc595_in(1 << i) activates one row at a time by setting a single bit high.

    • hc595_in(glyph[i]) sends the column data for the current row, determining which LEDs in that row should be lit.

    • hc595_out() latches the data, updating the LED matrix display.

    • time.sleep_ms(1) provides a short delay to ensure that each row is displayed long enough to be perceived by the human eye.

    • This rapid scanning creates the illusion of the entire ‘X’ being displayed simultaneously.

    while True:
        for i in range(8):
            hc595_in(glyph[i])       # Send the column data for the current row
            hc595_in(1 << i)         # Activate the current row
            hc595_out()              # Update the display
            time.sleep_ms(1)         # Delay for visual persistence
    

Experimenting Further

  • Changing the Pattern

    Try replacing the pattern list with the following arrays to display different graphics. Replace pattern in your code with pattern_heart or pattern_smile to see different images.

    # Heart shape
    pattern_heart = [
        0b11111111,
        0b10011001,
        0b00000000,
        0b00000000,
        0b00000000,
        0b10000001,
        0b11000011,
        0b11100111
    ]
    
    # Smile face
    pattern_smile = [
        0b11000011,  # Row 0
        0b10111101,  # Row 1
        0b01011010,  # Row 2
        0b01111110,  # Row 3
        0b01011010,  # Row 4
        0b01100110,  # Row 5
        0b10111101,  # Row 6
        0b11000011   # Row 7
    ]
    
  • Animating the Display

    Create multiple patterns and cycle through them to create animations:

    import machine
    import time
    
    # Define pins connected to the 74HC595 shift registers
    sdi = machine.Pin(18, machine.Pin.OUT)   # Serial Data Input
    rclk = machine.Pin(19, machine.Pin.OUT)  # Register Clock (Latch)
    srclk = machine.Pin(20, machine.Pin.OUT) # Shift Register Clock
    
    # Heart shape
    pattern_heart = [
        0b11111111,
        0b10011001,
        0b00000000,
        0b00000000,
        0b00000000,
        0b10000001,
        0b11000011,
        0b11100111
    ]
    
    # Smile face
    pattern_smile = [
        0b11000011,  # Row 0
        0b10111101,  # Row 1
        0b01011010,  # Row 2
        0b01111110,  # Row 3
        0b01011010,  # Row 4
        0b01100110,  # Row 5
        0b10111101,  # Row 6
        0b11000011   # Row 7
    ]
    
    def hc595_in(dat):
        """
        Shift 8 bits of data into the 74HC595 shift register.
        """
        for bit in range(7, -1, -1):
            srclk.low()                            # Prepare to shift data
            sdi.value((dat >> bit) & 1)            # Set data bit
            srclk.high()                           # Shift data bit into register
            time.sleep_us(1)                       # Short delay for timing
    
    def hc595_out():
        """
        Latch the shifted data to the output pins of the 74HC595.
        """
        rclk.high()                               # Latch data (rising edge)
        rclk.low()                                # Prepare for next data
    
    def display_pattern(pattern):
        """
        Display a given 8x8 pattern on the LED matrix.
        """
        for _ in range(500):                      # Display the pattern for a certain duration
            for i in range(8):
                hc595_in(pattern[i])              # Send column data for current row
                hc595_in(1 << i)                  # Activate current row
                hc595_out()                       # Update the output
                time.sleep_ms(1)                  # Short delay for persistence
    
    while True:
        display_pattern(pattern_heart)            # Display the heart shape
        display_pattern(pattern_smile)            # Display the smiley face
    
  • Design Your Own Patterns

    Each byte represents a row; bits set to 0 turn on the LED in that column. Create custom patterns by defining your own pattern list.

Conclusion

In this lesson, you’ve learned how to control an 8x8 LED matrix using the Raspberry Pi Pico 2 and two 74HC595 shift registers. By understanding how to manipulate bits and use shift registers, you can display patterns and graphics on the LED matrix.