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.
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.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × LED matrix, bare 8x8 (1088AS)
- 8 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
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 pin | Connects to |
|---|---|
| LED matrix, bare 8x8 (1088AS) pin R4 | Arduino Uno R3 pin 13 |
| LED matrix, bare 8x8 (1088AS) pin R3 | Arduino Uno R3 pin 12 |
| LED matrix, bare 8x8 (1088AS) pin R2 | Arduino Uno R3 pin 11 |
| LED matrix, bare 8x8 (1088AS) pin R1 | Arduino Uno R3 pin 10 |
| Resistor, 220 Ω (8) pin 1 | Arduino Uno R3 pin 9 |
| Resistor, 220 Ω (7) pin 1 | Arduino Uno R3 pin 8 |
| Resistor, 220 Ω (6) pin 1 | Arduino Uno R3 pin 7 |
| Resistor, 220 Ω (5) pin 1 | Arduino Uno R3 pin 6 |
| Resistor, 220 Ω (4) pin 1 | Arduino Uno R3 pin 5 |
| Resistor, 220 Ω (3) pin 1 | Arduino Uno R3 pin 4 |
| Resistor, 220 Ω (2) pin 1 | Arduino Uno R3 pin 3 |
| Resistor, 220 Ω (1) pin 1 | Arduino Uno R3 pin 2 |
| LED matrix, bare 8x8 (1088AS) pin R5 | Arduino Uno R3 pin A0 |
| LED matrix, bare 8x8 (1088AS) pin R6 | Arduino Uno R3 pin A1 |
| LED matrix, bare 8x8 (1088AS) pin R7 | Arduino Uno R3 pin A2 |
| LED matrix, bare 8x8 (1088AS) pin R8 | Arduino Uno R3 pin A3 |
| Resistor, 220 Ω (2) pin 2 | LED matrix, bare 8x8 (1088AS) pin C2 |
| Resistor, 220 Ω (3) pin 2 | LED matrix, bare 8x8 (1088AS) pin C3 |
| Resistor, 220 Ω (5) pin 2 | LED matrix, bare 8x8 (1088AS) pin C5 |
| Resistor, 220 Ω (8) pin 2 | LED matrix, bare 8x8 (1088AS) pin C8 |
| Resistor, 220 Ω (7) pin 2 | LED matrix, bare 8x8 (1088AS) pin C7 |
| Resistor, 220 Ω (1) pin 2 | LED matrix, bare 8x8 (1088AS) pin C1 |
| Resistor, 220 Ω (6) pin 2 | LED matrix, bare 8x8 (1088AS) pin C6 |
| Resistor, 220 Ω (4) pin 2 | LED 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.
// 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 indrawFor. 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.