Skip to content

Instantly share code, notes, and snippets.

@trickypr
Last active December 21, 2019 01:19
Show Gist options
  • Select an option

  • Save trickypr/255349f1f7df605f44e0909c41c71921 to your computer and use it in GitHub Desktop.

Select an option

Save trickypr/255349f1f7df605f44e0909c41c71921 to your computer and use it in GitHub Desktop.
Learning how to use a 16 x 16 LED dot matrix display with an Arduino

Getting started with a 16 x 16 LED dot matrix

What you need

  • A 16x16 LED / Dot matrix that uses a 74HC138 decoder IC
  • An Arduino
  • Something to program the Arduino with

What you would know

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.

Connecting up your 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.

Set up the pins in code

If you are feeling fancy you could store the constants using a #define instead. 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 matrix

You 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);
}

Screen Storage

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 screen data to the matrix

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:

  1. Pull G high
  2. Write the first 4 bits of i (column that you are currently rendering) to A, B, C and D
  3. Pull LATCH low
  4. Send pixels with shiftOut
  5. Pull LATCH high
  6. Pull G low
  7. Delay for100 microseconds

G to high

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.

Column ID and latch low

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.

Send pixels

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.

Set LATCH and G then wait 100 μs

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.

Writing to pixels

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!

Example write: Random dots

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.

Common issues

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.

Inverted colors

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]));
#include <Arduino.h>
// 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 matrix
// The pattern to be displayed on the screen
// Closest to a frame buffer in modern graphics cards
unsigned int buffer[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0
};
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);
}
void loop()
{
render();
}
void render() {
// Draw to the screen
for (unsigned int i = 0; i < 16; i++)
{
// Start draw
digitalWrite(G, HIGH);
// Identify which line the screen is on
digitalWrite(ROW_A, bitRead(i, 0));
digitalWrite(ROW_B, bitRead(i, 1));
digitalWrite(ROW_C, bitRead(i, 2));
digitalWrite(ROW_D, bitRead(i, 3));
// Open latch
digitalWrite(LATCH, LOW);
// Send over the pixles
shiftOut(DATA, CLOCK, MSBFIRST, highByte(~buffer[i]));
shiftOut(DATA, CLOCK, MSBFIRST, lowByte(~buffer[i]));
// Close Latch
digitalWrite(LATCH, HIGH);
// Finish draw
digitalWrite(G, LOW);
// Let the LEDs remain visible for long enough that they reach their full brightness
delayMicroseconds(100);
}
}
void setPixel(unsigned int x, unsigned int y, unsigned int state) {
// Check if the pixel is on the screen
if (x > 16 || y > 16) return;
// Add the pixel to the pattern to be displayed
bitWrite(buffer[y], 15 - x, state);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment