- A 16x16 LED / Dot matrix that uses a 74HC138 decoder IC
- An Arduino
- Something to program the Arduino with
I expect you to have a reasonable understanding of the Arduino and how to program it. I recommend Great Scott's Arduino 101, 102 and 103 tutorials for getting started with the Arduino.
First connect power and ground to their respective pins on the Arduino. Next connect the data pins to digital out pins on the Arduino.
If you are feeling fancy you could store the constants using a
#defineinstead. It does the same thing but is slightly faster.
Create a new sketch for this project. First set constants for each pin at the top of your sketch.
// LED Matrix constants
const unsigned int CLOCK = 8 // Pin marked "CLK" on your matrix
const unsigned int DATA = 7 // Pin marked "DI" on your matrix
const unsigned int LATCH = 9 // Pin marked "LAT" on your matrix
const unsigned int G = 6 // Pin marked "G" on your matrix
const unsigned int ROW_A = 5 // Pin marked "A" on your matrix
const unsigned int ROW_B = 4 // Pin marked "B" on your matrix
const unsigned int ROW_C = 3 // Pin marked "C" on your matrix
const unsigned int ROW_D = 2 // Pin marked "D" on your matrixYou also need to set the pins to out in the setup function.
void setup() {
// Set all of the displays pins to outputs
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(G, OUTPUT);
pinMode(ROW_A, OUTPUT);
pinMode(ROW_B, OUTPUT);
pinMode(ROW_C, OUTPUT);
pinMode(ROW_D, OUTPUT);
}You will need some way to store what is going to be shown on the matrix. This is going to be an array of unsigned ints. Each bit of the int will represent the state of pixel on the matrix.
[Memory to matrix map] Diagram: How pixel states are stored
You should add the following array to the top of your program.
unsigned int buffer[16] = {
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000
};0b is what you put before a binary version of a number. 0s represents an off LED and 1s represents an on LED.
Sending data to the screen is the hardest part of this tutorial. First create a function called render that will be executed in the main loop function.
// The default main loop
void loop() {
render();
}
// Render to the matrix
void render() {
/* Render code */
}Next you need to add a loop that loops through 16 times to render each column.
// Render the matix
void render() {
for (unsigned int i = 0; i < 16; i++) {
/* Render code */
}
}The render code you will write will do the following:
- Pull
Ghigh - Write the first 4 bits of
i(column that you are currently rendering) toA,B,CandD - Pull
LATCHlow - Send pixels with
shiftOut - Pull
LATCHhigh - Pull
Glow - Delay for
100microseconds
for (unsigned int i = 0; i < 16; i++) {
// Pull G high
digitalWrite(G, HIGH);
// Send column ID
// Pull LATCH low
// Send pixels
// Set LATCH high and G low
// Delay for 100 μs
}Some nice simple code for you.
for (unsigned int i = 0; i < 16; i++) {
// Pull high
digitalWrite(G, HIGH);
// Send column ID
digitalWrite(ROW_A, bitRead(i, 0));
digitalWrite(ROW_B, bitRead(i, 1));
digitalWrite(ROW_C, bitRead(i, 2));
digitalWrite(ROW_D, bitRead(i, 3));
// Pull LATCH low
digitalWrite(LATCH, LOW);
// Send pixels
// Set LATCH high and G low
// Delay for 100 μs
}bitRead grabs the bit at that position fro that variable. This sends a 4 bit number representing the column ID.
for (unsigned int i = 0; i < 16; i++) {
// Pull high
digitalWrite(G, HIGH);
// Send column ID
digitalWrite(ROW_A, bitRead(i, 0));
digitalWrite(ROW_B, bitRead(i, 1));
digitalWrite(ROW_C, bitRead(i, 2));
digitalWrite(ROW_D, bitRead(i, 3));
// Pull LATCH low
digitalWrite(LATCH, LOW);
// Send pixels
shiftOut(DATA, CLOCK, MSBFIRST, highByte(buffer[i]));
shiftOut(DATA, CLOCK, MSBFIRST, lowByte(buffer[i]));
// Set LATCH high and G low
// Delay for 100 μs
}shiftOut sends data along the DATA line whilst also sending a clock signal on the CLOCK line. highByte sends the first byte and lowByte sends the second byte of the two byte int that represents the pixels in each column.
for (unsigned int i = 0; i < 16; i++) {
// Pull high
digitalWrite(G, HIGH);
// Send column ID
digitalWrite(ROW_A, bitRead(i, 0));
digitalWrite(ROW_B, bitRead(i, 1));
digitalWrite(ROW_C, bitRead(i, 2));
digitalWrite(ROW_D, bitRead(i, 3));
// Pull LATCH low
digitalWrite(LATCH, LOW);
// Send pixels
shiftOut(DATA, CLOCK, MSBFIRST, highByte(buffer[i]));
shiftOut(DATA, CLOCK, MSBFIRST, lowByte(buffer[i]));
// Set LATCH high and G low
digitalWrite(LATCH, HIGH);
digitalWrite(G, LOW);
// Delay for 100 μs
delayMicroseconds(100);
}This finishes up the final part of the render function.
If you plan to change the contents of the screen automatically, a pixelWrite function will be immensely helpful.
bool writePixel(unsigned int x, unsigned int y, unsigned int state) {
// Check if the point is on the screen
if (x > 15 || y > 15) return false
// Write to the frame / screen buffer
bitWrite(buffer[y], 15 - x, state);
return true
}Finally! You have got some code that lets you write to the screen!
void setup() {
/* Setup code */
/* ... */
for (unsigned int i = 0; i < 20; i++)
{
setPixel(random(0, 15), random(0, 15), 1);
}
}Places 20 random dots on the screen.
If you have found an issue and solved it please post it in the comments along with a fix for it so I can add it here.
I have an issue where my matrix is inverted. If you are having the same issue then go to the render function and add a ~ in front of the buffer[i].
shiftOut(DATA, CLOCK, MSBFIRST, highByte(~buffer[i]));
shiftOut(DATA, CLOCK, MSBFIRST, lowByte(~buffer[i]));