The dot matrix that we’re going to use in this guide is a 8×8 matrix which means that it has 8 columns and 8 rows, so it contains a total of 64 LEDs.
The MAX7219 chip makes it easier to control the dot matrix, by just using 3 digital pins of the Arduino board.
I think the best option is to buy the dot matrix with the MAX7219 chip as a module, it will simplify the wiring. You can check the dot matrix at Maker Advisor and find the best price.
You can control more than one matrix at a time. For that you just need to connect them to each other, as they have pins in both sides to extend the dot matrix.
Parts required
For this guide you’ll need:
- 1x 8×8 Dot Matrix with MAX7219
- Arduino UNO – read Best Arduino Starter Kits
- 1x 1k ohm Potentiometer
- Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Pin Wiring
You only need to connect 5 pins from the dot matrix to your Arduino board. The wiring is pretty straightforward:
Dot matrix pin | Wiring to Arduino Uno |
GND | GND |
VCC | 5V |
DIN | Digital pin |
CS | Digital pin |
CLK | Digital pin |
How to control the dot matrix with Arduino
For making it easier to control the dot matrix, you need to download and install in your Arduino IDE the LedControl library. To install the library follow these steps:
- Click here to download the LedControl library. You should have a .zip folder in your Downloads
- Unzip the .zip folder and you should get LedControl-master folder
- Rename your folder from
LedControl-masterto LedControl - Move the LedControl folder to your Arduino IDE installation libraries folder
- Finally, re-open your Arduino IDE
Using the LedControl library functions
The easiest way to display something on the dot matrix is by using the functions setLed(), setRow() or setColumn(). These functions allow you to control one single led, one row or one column at a time.
Here’s the parameters for each function:
setLed(addr, row, col, state)
- addr is the address of your matrix, for example, if you have just 1 matrix, the int addr will be zero.
- row is the row where the led is located
- col is the column where the led is located
- state
- It’s true or 1 if you want to turn the led on
- It’s false or 0 if you want to switch it off
setRow(addr, row, value)
setCol(addr, column, value)
Index
As previously stated, this matrix has 8 columns and 8 rows. Each one is indexed from 0 to 7. Here’s a figure for better understanding:
If you want to display something in the matrix, you just need to know if in a determined row or column, the LEDs that are on or off.
For example, if you want to display a happy face, here’s what you need to do:
Code
Here’s a simple sketch that displays three types of faces: a sad face, a neutral face and a happy face. Upload the following code to your board:
/*
Created by Rui Santos
All the resources for this project:
https://randomnerdtutorials.com/
*/
#include "LedControl.h"
#include "binary.h"
/*
DIN connects to pin 12
CLK connects to pin 11
CS connects to pin 10
*/
LedControl lc=LedControl(12,11,10,1);
// delay time between faces
unsigned long delaytime=1000;
// happy face
byte hf[8]= {B00111100,B01000010,B10100101,B10000001,B10100101,B10011001,B01000010,B00111100};
// neutral face
byte nf[8]={B00111100, B01000010,B10100101,B10000001,B10111101,B10000001,B01000010,B00111100};
// sad face
byte sf[8]= {B00111100,B01000010,B10100101,B10000001,B10011001,B10100101,B01000010,B00111100};
void setup() {
lc.shutdown(0,false);
// Set brightness to a medium value
lc.setIntensity(0,8);
// Clear the display
lc.clearDisplay(0);
}
void drawFaces(){
// Display sad face
lc.setRow(0,0,sf[0]);
lc.setRow(0,1,sf[1]);
lc.setRow(0,2,sf[2]);
lc.setRow(0,3,sf[3]);
lc.setRow(0,4,sf[4]);
lc.setRow(0,5,sf[5]);
lc.setRow(0,6,sf[6]);
lc.setRow(0,7,sf[7]);
delay(delaytime);
// Display neutral face
lc.setRow(0,0,nf[0]);
lc.setRow(0,1,nf[1]);
lc.setRow(0,2,nf[2]);
lc.setRow(0,3,nf[3]);
lc.setRow(0,4,nf[4]);
lc.setRow(0,5,nf[5]);
lc.setRow(0,6,nf[6]);
lc.setRow(0,7,nf[7]);
delay(delaytime);
// Display happy face
lc.setRow(0,0,hf[0]);
lc.setRow(0,1,hf[1]);
lc.setRow(0,2,hf[2]);
lc.setRow(0,3,hf[3]);
lc.setRow(0,4,hf[4]);
lc.setRow(0,5,hf[5]);
lc.setRow(0,6,hf[6]);
lc.setRow(0,7,hf[7]);
delay(delaytime);
}
void loop(){
drawFaces();
}
In the end, you’ll have something like this:
Pong Game
The pong game that you’re about to try was created by Alessandro Pasotti.
For the pong game, you just need to add a 1k ohm potentiometer to the previous schematic. Assemble the new circuit as shown below:
Code
Then, upload the following code to your Arduino board:
/*
* Play pong on an 8x8 matrix - project from itopen.it
*/
#include "LedControl.h"
#include "Timer.h"
#define POTPIN A5 // Potentiometer
#define PADSIZE 3
#define BALL_DELAY 200
#define GAME_DELAY 10
#define BOUNCE_VERTICAL 1
#define BOUNCE_HORIZONTAL -1
#define NEW_GAME_ANIMATION_SPEED 50
#define HIT_NONE 0
#define HIT_CENTER 1
#define HIT_LEFT 2
#define HIT_RIGHT 3
//#define DEBUG 1
byte sad[] = {
B00000000,
B01000100,
B00010000,
B00010000,
B00000000,
B00111000,
B01000100,
B00000000
};
byte smile[] = {
B00000000,
B01000100,
B00010000,
B00010000,
B00010000,
B01000100,
B00111000,
B00000000
};
Timer timer;
LedControl lc = LedControl(12,11,10,1);
byte direction; // Wind rose, 0 is north
int xball;
int yball;
int yball_prev;
byte xpad;
int ball_timer;
void setSprite(byte *sprite){
for(int r = 0; r < 8; r++){
lc.setRow(0, r, sprite[r]);
}
}
void newGame() {
lc.clearDisplay(0);
// initial position
xball = random(1, 7);
yball = 1;
direction = random(3, 6); // Go south
for(int r = 0; r < 8; r++){
for(int c = 0; c < 8; c++){
lc.setLed(0, r, c, HIGH);
delay(NEW_GAME_ANIMATION_SPEED);
}
}
setSprite(smile);
delay(1500);
lc.clearDisplay(0);
}
void setPad() {
xpad = map(analogRead(POTPIN), 0, 1020, 8 - PADSIZE, 0);
}
void debug(const char* desc){
#ifdef DEBUG
Serial.print(desc);
Serial.print(" XY: ");
Serial.print(xball);
Serial.print(", ");
Serial.print(yball);
Serial.print(" XPAD: ");
Serial.print(xpad);
Serial.print(" DIR: ");
Serial.println(direction);
#endif
}
int checkBounce() {
if(!xball || !yball || xball == 7 || yball == 6){
int bounce = (yball == 0 || yball == 6) ? BOUNCE_HORIZONTAL : BOUNCE_VERTICAL;
#ifdef DEBUG
debug(bounce == BOUNCE_HORIZONTAL ? "HORIZONTAL" : "VERTICAL");
#endif
return bounce;
}
return 0;
}
int getHit() {
if(yball != 6 || xball < xpad || xball > xpad + PADSIZE){
return HIT_NONE;
}
if(xball == xpad + PADSIZE / 2){
return HIT_CENTER;
}
return xball < xpad + PADSIZE / 2 ? HIT_LEFT : HIT_RIGHT;
}
bool checkLoose() {
return yball == 6 && getHit() == HIT_NONE;
}
void moveBall() {
debug("MOVE");
int bounce = checkBounce();
if(bounce) {
switch(direction){
case 0:
direction = 4;
break;
case 1:
direction = (bounce == BOUNCE_VERTICAL) ? 7 : 3;
break;
case 2:
direction = 6;
break;
case 6:
direction = 2;
break;
case 7:
direction = (bounce == BOUNCE_VERTICAL) ? 1 : 5;
break;
case 5:
direction = (bounce == BOUNCE_VERTICAL) ? 3 : 7;
break;
case 3:
direction = (bounce == BOUNCE_VERTICAL) ? 5 : 1;
break;
case 4:
direction = 0;
break;
}
debug("->");
}
// Check hit: modify direction is left or right
switch(getHit()){
case HIT_LEFT:
if(direction == 0){
direction = 7;
} else if (direction == 1){
direction = 0;
}
break;
case HIT_RIGHT:
if(direction == 0){
direction = 1;
} else if(direction == 7){
direction = 0;
}
break;
}
// Check orthogonal directions and borders ...
if((direction == 0 && xball == 0) || (direction == 4 && xball == 7)){
direction++;
}
if(direction == 0 && xball == 7){
direction = 7;
}
if(direction == 4 && xball == 0){
direction = 3;
}
if(direction == 2 && yball == 0){
direction = 3;
}
if(direction == 2 && yball == 6){
direction = 1;
}
if(direction == 6 && yball == 0){
direction = 5;
}
if(direction == 6 && yball == 6){
direction = 7;
}
// "Corner" case
if(xball == 0 && yball == 0){
direction = 3;
}
if(xball == 0 && yball == 6){
direction = 1;
}
if(xball == 7 && yball == 6){
direction = 7;
}
if(xball == 7 && yball == 0){
direction = 5;
}
yball_prev = yball;
if(2 < direction && direction < 6) {
yball++;
} else if(direction != 6 && direction != 2) {
yball--;
}
if(0 < direction && direction < 4) {
xball++;
} else if(direction != 0 && direction != 4) {
xball--;
}
xball = max(0, min(7, xball));
yball = max(0, min(6, yball));
debug("AFTER MOVE");
}
void gameOver() {
setSprite(sad);
delay(1500);
lc.clearDisplay(0);
}
void drawGame() {
if(yball_prev != yball){
lc.setRow(0, yball_prev, 0);
}
lc.setRow(0, yball, byte(1 << (xball)));
byte padmap = byte(0xFF >> (8 - PADSIZE) << xpad) ;
#ifdef DEBUG
//Serial.println(padmap, BIN);
#endif
lc.setRow(0, 7, padmap);
}
void setup() {
// The MAX72XX is in power-saving mode on startup,
// we have to do a wakeup call
pinMode(POTPIN, INPUT);
lc.shutdown(0,false);
// Set the brightness to a medium values
lc.setIntensity(0, 8);
// and clear the display
lc.clearDisplay(0);
randomSeed(analogRead(0));
#ifdef DEBUG
Serial.begin(9600);
Serial.println("Pong");
#endif
newGame();
ball_timer = timer.every(BALL_DELAY, moveBall);
}
void loop() {
timer.update();
// Move pad
setPad();
#ifdef DEBUG
Serial.println(xpad);
#endif
// Update screen
drawGame();
if(checkLoose()) {
debug("LOOSE");
gameOver();
newGame();
}
delay(GAME_DELAY);
}
Demonstration
Here’s the final demonstration of me playing the pong game. Have fun!
Wrapping up
Have you ever used the dot matrix in your Arduino Projects?
Let me know by leaving a comment below.
If you like this post probably you might like my next ones (click here to subscribe my blog). Thanks for reading,
Rui
GREAT JOB ! I will build one 🙂
Thank you very much for sharing !
You’re welcome Roger! Thanks for reading,
Rui
awesome project but one thing i wanna mention is that instead of writing binary codes to turn on a specific led i would prefer to define every led by name and declare it as the binary code of that led. this will just make it a little bit user friendly
Yes, that’s also a good alternative. Thanks for the suggestion,
Rui
Very clear and detailed. Easy to implement for a beginner and fun for more advanced user.
Thanks for reading Robert! I’m glad you liked it
thank you!!!! master!!
Thanks for reading!
Hello, I copied the code for the 8×8 LED game, but I keep getting this error. Any ideas why?
Error compiling for board Arduino/Genuino Uno.
I also copied it to Codebender and I get 1 sketch error and 2 library errors, can you help?
github.com/JChristensen/Timer
🙂 You have to install it…
what a wonderful job! I have been searching for guide on how to control led matrix using Arduino but this is the best guide I have ever have. Thanks
You’re welcome!
Rui
I love those 8×8’s 🙂
Hello sir …. I am an engineering 1st year student and I love to read about Arduino from your tutorials . They are so simple and well written….I just did the pong game on the led matrix module and it worked fine …. Can u post the code for the space invaders game using ledcontrol library .. I could surprise all my friends then
Thanks for the request, but right now I need to finish other projects.
I’m glad you found this tutorial useful.
Have a great day,
Rui
I’m very new to arduino’s, but when I try to compile it can not find the Timer.h library, where can I find this one?
The first one worked really good.
Simply search for the Arduino Timer library: playground.arduino.cc/Code/Timer
Could you make a tutorial for an 8×8 Dot Matrix without MAX7219?
Hello sir;
Pls,
give me a library file called ‘ binary.h ‘ file.
I need only this file(binary.h).
and I am learning in holeNight.
thanks sir.
I don’t know what you’re talking about.
The library that I show in this blog post should have everything that you need to use the Dot Matrix.
Regards,
Rui
very good for learing
Thanks 🙂
Would love it if ppl cared to really comment their codes if they share them for newbies to learn 😀
Pro coders wont propably be interested in checking at all how someone coded a pong.
Newbies wont benefit much if the comments are like “Check stuff” and then theres tens of lines of code..
Hi. I’m sorry for the trouble.
The pong game was adapted from itopen.it website. So, that’s why it is not commented as we usually do in our codes.
We in class unloaded your program and went looking for libraries, finding everything that is now the arduino in function ball_timer = timer.every (BALL_DELAY, moveBall); You do not have to worry about what’s wrong with “moveBall”. Do you know why or can you help ??? P:S se fores português, fala em pt, thanks
Olá Inês. Desculpa, não percebi a tua pergunta.
O código do jogo não foi criado por nós. Foi adaptado do site itopen.it, como dizemos no código.
Dá uma olhada no site deles e vê se encontras algo que te possa ajudar.
🙂
Hi I tried uploading ,all the leds in the matrix glow at once and nothing happens.Is there a different way of doing it.Is there a difference between common cathode and common annode?
Thanks.
With these exact Matrix modules with MAX7219 chip, it should work regardless of being common cathode/anode.
I’m not sure why you’re experiencing that problem, because I never encountered that issue.
Regards,
Rui
You probably connected the wires for the DIN CS CLK incorrectly. Found this out while I was working on it and all the LED lit up too
Awesome and easy one.can i make the 32*32 with this design.and what will be change in code
This project could be expanded to something like that, but I don’t have any information on that exact subject.
It gave me an error when I uploaded it. It was saying “no matching function for call to ‘Timer::every(int, void (&)())'”
Hi Caleb.
Can you install the following library and see if it works?
https://github.com/JChristensen/Timer
Regards,
Sara
The problem seems to be with a newer version of the timer library. The older version you linked works fine though!
Thank you very much
Great job, Very clear and easy to understand. Your code explanation was also great. I have learned a lot from this page. THANK YOU
Thank you 🙂
Thanks a lot Sara and Rui,
Used the first bit in an university engineering task (this site was referenced). Would have loved to include the pong game as well, but we were being marked on size of the program.
Really made my life a lot easier
Great info, have it running with my Arduino, can I transfer to a “ATTINY85” with same code??.
Thanks a lot! Rui Santos… Your
website has really helped me…. Especially while learning about esp32. Keep spreading knowledge like this… Love from India ♥️
Thanks 😀
Hi! When I plugged the matrix, my Arduino can’t turn on. Any workaround?
Hi! I added the ability to make an ton, when the ball touch the wall.
It works fine.
I can send the code.
Hi, This is great ! I connected it and it works just fine. However I have four of them connected. I can address only the first one. how do i work with 4 of them? Thank you!
Hi, I have just put together this 8X8 dot matrix circuit and it works beautifully, even managed to add the “zero” and “one” to the sketch! This works fine on a single 8×8 but if I hook it up to a 4 block of 8×8 (32×8) then the rightmost 8×8 is fine, next in adds some LEDS, and the same for the remaining two 8X8’s. The random LED’s are always the same ones and I have tried swapping over the 8X8 blocks with the same results.
Do you think I have a faulty PCB/Max7219 chip(s), or is there additional code required to drive the 4 segments?
Love your channel, I’ve learned loads, thank you so much.