Built-in project · Arduino Uno R3

Heart on a bare 8x8 matrix, on an Arduino Uno

A bare 1088AS 8x8 LED matrix on sixteen Uno pins and no driver chip: the sketch lights one row at a time, fast, and a heart beats on it. The whole build, an Arduino Uno and 9 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Advanced About 45 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $28. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • Multiplexing: only one row is ever on
  • Persistence of vision
  • Rows as cathodes and columns as anodes on a matrix
  • Storing a picture as one byte per row
  • Reading single bits with shifts and masks
  • Difficulty: Advanced
  • Time: About 45 minutes
  • Board: Arduino Uno R3
  • Parts: 10

How it works

A bare 1088AS matrix has no driver chip, so the Uno drives all sixteen lines. The eight columns go to pins 2 to 9, each through a 220 ohm resistor. The eight rows go to pins 10 to 13 and A0 to A3. Rows are the cathodes: pulling one LOW lets the lit dots in that row glow.

drawFor lights one row at a time. It sets the eight column pins from one byte of the picture, pulls that row LOW for 2 ms, then sets it HIGH again. Eight rows take about 16 ms, so the picture is redrawn about 60 times a second and your eye sees a steady image.

loop shows the BIG heart for 400 ms, the SMALL heart for 250 ms, then 150 ms of dark. That is the heartbeat.

Parts list

10 parts, plus the jumper wires. They retail for about $28; on Mokxi they're free.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
LED matrix, bare 8x8 (1088AS) pin R4Arduino Uno R3 pin 13
LED matrix, bare 8x8 (1088AS) pin R3Arduino Uno R3 pin 12
LED matrix, bare 8x8 (1088AS) pin R2Arduino Uno R3 pin 11
LED matrix, bare 8x8 (1088AS) pin R1Arduino Uno R3 pin 10
Resistor, 220 Ω (8) pin 1Arduino Uno R3 pin 9
Resistor, 220 Ω (7) pin 1Arduino Uno R3 pin 8
Resistor, 220 Ω (6) pin 1Arduino Uno R3 pin 7
Resistor, 220 Ω (5) pin 1Arduino Uno R3 pin 6
Resistor, 220 Ω (4) pin 1Arduino Uno R3 pin 5
Resistor, 220 Ω (3) pin 1Arduino Uno R3 pin 4
Resistor, 220 Ω (2) pin 1Arduino Uno R3 pin 3
Resistor, 220 Ω (1) pin 1Arduino Uno R3 pin 2
LED matrix, bare 8x8 (1088AS) pin R5Arduino Uno R3 pin A0
LED matrix, bare 8x8 (1088AS) pin R6Arduino Uno R3 pin A1
LED matrix, bare 8x8 (1088AS) pin R7Arduino Uno R3 pin A2
LED matrix, bare 8x8 (1088AS) pin R8Arduino Uno R3 pin A3
Resistor, 220 Ω (2) pin 2LED matrix, bare 8x8 (1088AS) pin C2
Resistor, 220 Ω (3) pin 2LED matrix, bare 8x8 (1088AS) pin C3
Resistor, 220 Ω (5) pin 2LED matrix, bare 8x8 (1088AS) pin C5
Resistor, 220 Ω (8) pin 2LED matrix, bare 8x8 (1088AS) pin C8
Resistor, 220 Ω (7) pin 2LED matrix, bare 8x8 (1088AS) pin C7
Resistor, 220 Ω (1) pin 2LED matrix, bare 8x8 (1088AS) pin C1
Resistor, 220 Ω (6) pin 2LED matrix, bare 8x8 (1088AS) pin C6
Resistor, 220 Ω (4) pin 2LED matrix, bare 8x8 (1088AS) pin C4

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// A bare 8x8 LED matrix, no driver chip: sixteen pins, one row at a time.
//
//   1088AS: rows R1..R8 are the cathodes, columns C1..C8 the anodes
//   columns C1..C8 -> pins 2 to 9, each through its own 220 ohm
//   rows R1..R8    -> pins 10, 11, 12, 13, A0, A1, A2, A3
//
// A row is selected by pulling it LOW; a dot in it lights when its column is
// HIGH. Only one row is ever on, for two milliseconds, so each column pin
// carries one LED's current and the whole picture is redrawn about 60 times
// a second. The eye does the rest.

const uint8_t COLUMN_PINS[8] = {2, 3, 4, 5, 6, 7, 8, 9};
const uint8_t ROW_PINS[8] = {10, 11, 12, 13, A0, A1, A2, A3};

// One byte a row, the left column in the top bit.
const uint8_t BIG[8] = {0x00, 0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18};
const uint8_t SMALL[8] = {0x00, 0x00, 0x24, 0x7E, 0x7E, 0x3C, 0x18, 0x00};

void drawFor(const uint8_t *picture, unsigned long ms) {
  unsigned long start = millis();
  while (millis() - start < ms) {
    for (uint8_t r = 0; r < 8; r++) {
      for (uint8_t c = 0; c < 8; c++) digitalWrite(COLUMN_PINS[c], (picture[r] >> (7 - c)) & 1);
      digitalWrite(ROW_PINS[r], LOW);
      delay(2);
      digitalWrite(ROW_PINS[r], HIGH);
    }
  }
}

void setup() {
  for (uint8_t i = 0; i < 8; i++) {
    pinMode(COLUMN_PINS[i], OUTPUT);
    pinMode(ROW_PINS[i], OUTPUT);
    digitalWrite(ROW_PINS[i], HIGH);  // every row off
  }
}

void loop() {
  drawFor(BIG, 400);
  drawFor(SMALL, 250);
  delay(150);  // dark between beats
}

Code walkthrough

The key functions of the sketch, and what each one does.

drawFor sketch.ino

drawFor repeats for a set number of milliseconds. For each row it writes the eight column pins from that row's byte, pulls the row pin LOW for 2 ms so those dots light, then sets it HIGH to turn the row off before moving on.

void drawFor(const uint8_t *picture, unsigned long ms) {
  unsigned long start = millis();
  while (millis() - start < ms) {
    for (uint8_t r = 0; r < 8; r++) {
      for (uint8_t c = 0; c < 8; c++) digitalWrite(COLUMN_PINS[c], (picture[r] >> (7 - c)) & 1);
      digitalWrite(ROW_PINS[r], LOW);
      delay(2);
      digitalWrite(ROW_PINS[r], HIGH);
    }
  }
}

setup sketch.ino

setup makes all sixteen pins outputs and sets every row pin HIGH, which turns every row off. A row only lights when it is pulled LOW.

void setup() {
  for (uint8_t i = 0; i < 8; i++) {
    pinMode(COLUMN_PINS[i], OUTPUT);
    pinMode(ROW_PINS[i], OUTPUT);
    digitalWrite(ROW_PINS[i], HIGH);  // every row off
  }
}

loop sketch.ino

loop calls drawFor with the big heart for 400 ms and the small heart for 250 ms, then waits 150 ms with nothing drawn. Changing those numbers changes the beat.

void loop() {
  drawFor(BIG, 400);
  drawFor(SMALL, 250);
  delay(150);  // dark between beats
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The heart is mirrored or scrambled. This project
    Wire columns C1 to C8 to pins 2 to 9 in order, and rows R1 to R8 to pins 10 to 13 and A0 to A3 in order.
  • One column is missing or dim. This project
    Each column has its own 220 ohm resistor. Check that one.
  • The picture flickers. This project
    Each row stays on for 2 ms in drawFor. Make that delay much longer and the flicker shows.
  • Several LEDs light at once or the wrong ones appear. LED matrix
    Scan one row at a time, fast, and turn off the previous row first. Check the datasheet pin map for rows and columns, since the 1088AS pin order is not intuitive.
  • LEDs are dim or pins are overloaded. LED matrix
    Use a current limiting resistor on each column, around 220 ohms. A single pin cannot drive a whole row of LEDs on, so use a driver chip such as a 74HC595 or transistors.
  • The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
    Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure.
  • A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
    Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground.
  • Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
    Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.