Skip to Content

Tutorial Arduino para display de matriz de pontos LED MAX7219

Tutorial Arduino para display de matriz de pontos LED MAX7219

Neste tutorial, vais aprender a controlar um display de matriz de pontos LED com Arduino. Incluí um diagrama de ligação e vários exemplos de código! O código deste tutorial pode ser usado para displays 8×8, 8×32 e até maiores. MAX7219 LED dot matrix display com Arduino. Incluí um diagrama de ligação e vários exemplos de código! O código deste tutorial pode ser usado para displays 8×8, 8×32 e até maiores.

Para este tutorial, vou usar o MD_Parola em combinação com a biblioteca MD_MAX72XX Arduino. Estas bibliotecas facilitam muito a exibição de texto a rolar e outras animações. Na primeira parte deste artigo, vou abordar o básico de como imprimir texto no display. Depois, veremos texto a rolar e outras animações de texto. Por fim, vou mostrar como usar sprites de texto.

Se quiseres aprender mais sobre este ou outros tipos de displays, consulta os artigos abaixo:

Artigos recomendados

Materiais

Componentes de hardware

8×32 MAX7219 LED dot matrix display × 1 Amazon
8x8-MAX7219-LED-dot-matrix-display8×8 MAX7219 LED dot matrix display (alternativa) × 1 Amazon
generic-MAX7219-8x8-LED-dot-matrix-displayGeneric 8×8 MAX7219 LED dot matrix display (alternativa) × 1 Amazon
Arduino Uno Rev 3Arduino Uno Rev3 × 1 Amazon
Jumper wires  (macho para fêmea) × 4 Amazon
USB cable type A/B × 1 Amazon
Male headers ~ 20 Amazon
Jumpers ~ 20 Amazon

Software

Arduino IDEArduino IDE

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

Sobre o driver LED MAX7219

O driver LED MAX7219 pode ser usado para controlar displays de 7 segmentos até 8 dígitos, displays de gráfico de barras ou 64 LEDs individuais. O driver comunica com o Arduino via SPI, por isso só precisas de três fios para controlar o display.

Como o MAX7219 pode controlar no máximo 64 LEDs, o tamanho máximo do display de matriz de pontos que pode conduzir é 8×8 pixels. No entanto, podes ligar em cadeia vários drivers e matrizes e controlar facilmente displays muito maiores como 8×32, 8×64 ou ainda maiores. Mesmo assim, só precisas de três fios para controlar todos os ICs, usando muito poucos pinos I/O do Arduino.

Abaixo podes encontrar as especificações de um típico display de matriz de pontos LED MAX7219 8×32.

Especificações do display de matriz de pontos LED MAX7219

Tensão de funcionamento 5 V
Driver do display MAX7219 x 4
Níveis de brilho 16
Dimensões do display 32 x 128 x 15 mm
Pixels 8×32, ⌀ 3 mm
Custo Check price

Para mais informações, podes consultar o datasheet:

Quase todos os displays que usei no passado usavam uma matriz LED 8×8 tipo 1088AS. Podes encontrar um datasheet de uma das empresas que os fabrica abaixo:

Como ligar o display de matriz de pontos ao Arduino

O driver do display LED MAX7219 comunica com o Arduino através de SPI (Serial Peripheral Interface). Com uma interface SPI há sempre um dispositivo mestre (o Arduino) que controla os dispositivos periféricos (também chamados de escravos). Podes controlar o display através da interface SPI de hardware do microcontrolador AVR do Arduino ou usando três pinos digitais arbitrários (SPI por software).

Os pinos SPI de hardware (MOSI, MISO e SCK) estão numa localização específica em cada placa Arduino. Esta interface é mais rápida do que usar SPI por software, mas precisas de usar os seguintes pinos de saída fixos:

Localização dos pinos SPI de hardware

Placa MOSI MISO SCK Nível
Arduino Uno 11 ou ICSP-4 12 ou ICSP-1 13 ou ICSP-3 5 V
Arduino Mega 51 ou ICSP-4 50 ou ICSP-1 52 ou ICSP-3 5 V
Arduino Leonardo ICSP-4 ICSP-1 ICSP-3 5 V
Arduino Due SPI-4 SPI1 SPI-3 3.3 V
Arduino MKR1000 8 10 9 3.3 V
Localização dos pinos SPI de hardware em diferentes placas Arduino.

Note que os pinos MOSI, MISO e SCK também estão numa localização física consistente no conector ICSP de 6 pinos:

ICSPHeader
Fonte: Arduino.cc

Para controlar displays MAX7219 só precisas de fazer três ligações:

  • MOSI (Master Out Slave In) ligado a DIN – A linha mestre que envia dados para os periféricos.
  • SCK (Serial Clock) ligado a CLK – Os pulsos de relógio que sincronizam a transmissão de dados gerados pelo mestre.
  • SS (Slave Select) ligado a CS – O pino em cada dispositivo que o mestre pode usar para ativar e desativar dispositivos específicos.

Podes ligar em cadeia vários displays para criar um display maior ligando o DOUT do primeiro display ao DIN do próximo. VCC, GND, CLK e CS são partilhados entre todos os displays.

Podes escolher qualquer pino digital do Arduino para o pino SS/CS. Nota que neste tutorial usei o pino 3 (ver tabela abaixo).

O diagrama de ligação abaixo mostra como ligar o display de matriz de pontos LED MAX7219 ao Arduino. Nota que ao usar a biblioteca MD_Parola, precisas de orientar o display com o conector DIN à direita, caso contrário o texto será impresso de cabeça para baixo. Para mais informações, vê a secção abaixo.

MAX7219-LED-dot-matrix-display-with-Arduino-Uno-wiring-diagram-schematic-pinout
Diagrama de ligação do display de matriz de pontos LED MAX7219 com Arduino

As ligações também estão indicadas na tabela abaixo:

Ligações do display de matriz de pontos LED MAX7219

Display MAX7219 Arduino
VCC 5 V
GND GND
DIN 11 (MOSI)
CS 3 (SS)
CLK 13 (SCK)

Se quiseres usar SPI por software, podes ligar DIN, CS e CLK a qualquer pino digital do Arduino. Só precisas de especificar os números dos pinos na configuração do código Arduino (ver exemplos abaixo).

Requisitos de alimentação

A potência máxima que o Arduino Uno pode fornecer com segurança quando alimentado por USB é cerca de 400 mA a 5 V. Se quiseres controlar um display grande, é aconselhável usar uma fonte de alimentação externa.

Instalar as bibliotecas Arduino MD_Parola e MD_MAX72XX

Para controlar o display MAX7219 vamos usar duas excelentes bibliotecas Arduino criadas por Marco Colli da MajicDesigns. A biblioteca MD_Parola pode ser usada para criar várias animações de texto como texto a rolar e efeitos de sprites. Esta biblioteca depende da MD_MAX72XX que implementa as funções de hardware da matriz LED.

Estas são algumas funções e características da biblioteca:

  • Justificação de texto à esquerda, direita ou centro
  • Texto a rolar com efeitos de entrada e saída
  • Controlar parâmetros do display e velocidade da animação
  • Múltiplos displays virtuais (zonas) em cada cadeia de módulos LED
  • Suporte para interface SPI de hardware
  • Fontes definidas pelo utilizador e/ou substituições de caracteres individuais
  • Suporte para displays de altura dupla
  • Suporte para misturar texto e gráficos no mesmo display

O Marco tem trabalhado nesta biblioteca durante vários anos e escreveu excelentes tutoriais sobre his blog. O código-fonte e documentação das bibliotecas podem ser encontrados aqui:

Podes instalar as bibliotecas através do Library Manager do Arduino IDE. Vai a Tools > Manage Libraries… ou pressiona Ctrl + Shift + I no Windows. O Library Manager abrirá e atualizará a lista de bibliotecas instaladas.

Installing an Arduino library step 1 open Library Manager
Gerir bibliotecas

Procura por ‘MD_MAX72XX’ e procura as bibliotecas da majicDesigns. Seleciona a versão mais recente e clica em instalar. Certifica-te de instalar tanto a biblioteca MD_MAX72XX como a MD_Parola.

Installing an Arduino library step 2 MD_Parola and MD_MAX72XX
Gestor de bibliotecas

Diferentes tipos de displays de matriz de pontos LED

Existem muitos tipos e tamanhos diferentes de displays de matriz de pontos LED MAX7219 no mercado. A biblioteca MD_MAX72XX suporta quase todos estes displays, mas precisas de configurar a biblioteca corretamente para o tipo de matriz que estás a usar.

Abaixo podes encontrar informações sobre como ligar e configurar os displays MAX7219 mais comuns que podes comprar no Amazon, AliExpress e eBay.

Display de matriz de pontos LED MAX7219 (Find at Amazon)

Este é provavelmente o display MAX7219 mais comum que podes encontrar. Normalmente vem como uma matriz LED 8×8 ou 8×32 e podes comprá-los com diferentes cores de LEDs.

Orientação do módulo e ligações

Podes ligar facilmente vários módulos 8×8 ou 8×32 juntos para criar um display maior. Normalmente soldo headers macho retos na parte de trás dos módulos e ligo-os com jumpers. Assim podes desmontá-los sem ter de dessoldar nenhuma ligação.

Jumpers (Find at Amazon)

O display está orientado com o lado DIN à direita. Nota que o texto impresso no PCB pode estar de cabeça para baixo nesta orientação.

           DP A  B  C  D  E  F  G 
         +------------------------+ 
         | 7  6  5  4  3  2  1  0 | D0 
 CLK <---|                      1 | D1 <--- CLK 
  CS <---|                      2 | D2 <--- CS 
DOUT <---|                      3 | D3 <--- DIN 
 GND ----|                   O  4 | D4 ---- GND 
 VCC ----|                O  O  5 | D5 ---- VCC 
         |             O  O  O  6 | D6 
         |          O  O  O  O  7 | D7 
         +------------------------+

Hardware configuration in Arduino code

When setting up the display in your Arduino code you need to set the HARDWARE_TYPE to FC16_HW and specify the number of devices you have connected. An 8×8 matrix counts as 1 device, so if you want to control an 8×32 module you need to set MAX_DEVICES to 4 (an 8×32 display contains 4 MAX7219 ICs).

// Hardware SPI:
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 2

// Create a new instance of the MD_MAX72XX class:
MD_Parola matrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// For software SPI you also need to specify the DATA_PIN and the CLK_PIN connections:
// #define DATA_PIN 3
// #define CLK_PIN 4

// Create a new instance of the MD_MAX72XX class:
// MD_Parola matrix = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

Generic 8×8 module

MAX7219 8x8 Module (Find at Amazon)

This is an 8×8 module mounted on a green PCB with the MAX7219 IC below the LED matrix. They are characterized by the 5-pin connectors at the short ends of the rectangular PCB.

Module orientation and connections

The generic module needs to be oriented with the MAX7219 IC at the top. You can connect multiple modules together with some short female to female jumper wires. Simply connect all the pins of the DOUT side of the first module to the DIN side of the next module.

      C  C  D  G  V
      L  S  I  N  C
      K     N  D  C
      |  |  |  |  |
      V  V  V  |  |
  D7 D6 D5 D4 D3 D2 D1 D0
+------------------------+
| 7  6  5  4  3  2  1  0 | DP
|                      1 | A
|                      2 | B
|                      3 | C
| O                    4 | D
| O  O                 5 | E
| O  O  O              6 | F
| O  O  O  O           7 | G
+------------------------+
      |  |  |  |  |
      V  V  V  |  |
      C  C  D  G  V
      L  S  O  N  C
      K     U  D  C
            T

Hardware configuration in Arduino code

For the generic display modules, you need to set the HARDWARE_TYPE to GENERIC_HW. The rest of the setup and MAX_DEVICES is the same as for the FC-16 modules.

// Hardware SPI:
#define HARDWARE_TYPE MD_MAX72XX::GENERIC_HW
#define MAX_DEVICES 1
#define CS_PIN 2

// Create a new instance of the MD_MAX72XX class:
MD_Parola matrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// For software SPI you also need to specify the DATA_PIN and the CLK_PIN connections:
// #define DATA_PIN 3
// #define CLK_PIN 4

// Create a new instance of the MD_MAX72XX class:
// MD_Parola matrix = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

Arduino example codes

Below you will find several example codes that cover the basic functions of the MD_Parola Arduino library. After each example I explain how the code works so you should be able to modify it to suit your needs. You can also find more examples when you go to File > Examples > MD_Parola in the Arduino IDE, but they don't include any explanation so they might be a bit hard to follow.

Basic Arduino example code to print text

With the example code below you can print text on the display without any animations.

You can upload the example code to your Arduino via the Arduino IDE. For this tutorial, I used this standard 8x32 LED dot matrix display (Find at Amazon) but you can use other types and/or sizes as well (see code explanation below).

/* Basic example code for MAX7219 LED dot matrix display 
  with Arduino. More info: https://www.makerguides.com */

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

// Define hardware type, size, and output pins:
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

// Create a new instance of the MD_Parola class with hardware SPI connection:
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Setup for software SPI:
// #define DATAPIN 2
// #define CLK_PIN 4
// MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

void setup() {
  // Intialize the object:
  myDisplay.begin();
  // Set the intensity (brightness) of the display (0-15):
  myDisplay.setIntensity(0);
  // Clear the display:
  myDisplay.displayClear();
}

void loop() {
  myDisplay.setTextAlignment(PA_CENTER);
  myDisplay.print("Center");
  delay(2000);
  myDisplay.setTextAlignment(PA_LEFT);
  myDisplay.print("Left");
  delay(2000);
  myDisplay.setTextAlignment(PA_RIGHT);
  myDisplay.print("Right");
  delay(2000);
  myDisplay.setTextAlignment(PA_CENTER);
  myDisplay.setInvert(true);
  myDisplay.print("Invert");
  delay(2000);
  myDisplay.setInvert(false);
  myDisplay.print(1234);
  delay(2000);
}

You should see the following output:

Text alignment

How the code works

The first step is to include all the required Arduino libraries. As I mentioned before, the MD_MAX72XX library implements the hardware functions of the LED matrix and the MD_Parola library the text effects. You will also need to include the SPI library, which comes pre-installed in the Arduino IDE. This library is used for the Serial Peripheral Interface communication between the display and the Arduino.

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

Next, we need to specify which hardware we are using. Since I used a standard 8×32 display (also known as FC-16), I set the HARDWARE_TYPE to FC16_HW. The number of MAX7219 ICs in an 8×32 display is 4 so I set MAX_DEVICES to 4. Lastly, I defined to which pin the CS pin of the display is connected (output pin 3 in this case). See the section about display types for a more detailed explanation on how to set up other types of displays.

The statement #define is used to give a name to a constant value. The compiler will replace any references to this constant with the defined value when the program is compiled. So everywhere you mention CS_PIN, the compiler will replace it with the value 3 when the program is compiled.

// Define hardware type, size, and output pins:
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

After this, a new instance of the MD_Parola class is created with the function MD_Parola(). This function needs three parameters, the first is the hardware type, the second the CS pin, and the third the number of max devices connected.

Note that I have called the MD_Parola object 'myDisplay' but you can use other names as well. You will need to change ‘myDisplay’ to the new name in the rest of the sketch.

When you want to use software SPI instead of hardware SPI, you also need to define the data and clock output pins and pass these as parameters when setting up the display object.

// Create a new instance of the MD_Parola class with hardware SPI connection:
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Setup for software SPI:
// #define DATAPIN 2
// #define CLK_PIN 4
// MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

In the setup section of the code, we first initialize the object with the function begin(). The brightness of the display can be set with the function setIntensity(). You can enter a value between 0 (minimum brightness) and 15 (maximum brightness). The display is cleared with the function displayClear().

void setup() {
  // Intialize the object:
  myDisplay.begin();
  // Set the intensity (brightness) of the display (0-15):
  myDisplay.setIntensity(0);
  // Clear the display:
  myDisplay.displayClear();
}

In the loop section of the code, we first set the alignment of the text to be printed with the function setTextAlignment(). You can left, center, and right align the text with PA_LEFT, PA_CENTER, and PA_RIGHT respectively.

Next, the string ‘Center’ is printed with myDisplay.print("Center"). Note that you need to place quotation marks (” “) around the text since we are printing a text string. When you want to print numbers, no quotation marks are necessary. For example myDisplay.print(1234). You can invert the display, i.e. LEDs normally on turn off and vice versa, with myDisplay.setInvert(true).

void loop() {
  myDisplay.setTextAlignment(PA_CENTER);
  myDisplay.print("Center");
  delay(2000);
  myDisplay.setTextAlignment(PA_LEFT);
  myDisplay.print("Left");
  delay(2000);
  myDisplay.setTextAlignment(PA_RIGHT);
  myDisplay.print("Right");
  delay(2000);
  myDisplay.setTextAlignment(PA_CENTER);
  myDisplay.setInvert(true);
  myDisplay.print("Invert");
  delay(2000);
  myDisplay.setInvert(false);
  myDisplay.print(1234);
  delay(2000);
}

Scrolling text Arduino example code

When you want to print a message on a dot matrix display, you will often find that the display is too small to fit the entire message. The solution is in the MD_Parola library, which makes it super easy to create scrolling text effects. In the following examples, I will show you how to set this up, as well as how to use some of the other available text effects.

Scrolling text

You can copy the code below by clicking on the button in the top right corner of the code field.

/* Example code for scrolling text effect on 
   MAX7219 LED dot matrix display with Arduino. 
   More info: https://www.makerguides.com */

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

// Define hardware type, size, and output pins:
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

// Create a new instance of the MD_Parola class with hardware SPI connection:
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Setup for software SPI:
// #define DATA_PIN 2
// #define CLK_PIN 4
// MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

void setup() {
  // Intialize the object:
  myDisplay.begin();
  // Set the intensity (brightness) of the display (0-15):
  myDisplay.setIntensity(0);
  // Clear the display:
  myDisplay.displayClear();
  myDisplay.displayText("Scrolling text", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
}

void loop() {
  if (myDisplay.displayAnimate()) {
    myDisplay.displayReset();
  }
}

How the code works

The first part of the code up to the end of the setup section is exactly the same as in the previous example. At the end of the setup section, we specify how we want to display the text with the function displayText(pText, align, speed, pause, effectIn, effectOut). This function takes 5 arguments.

The first parameter is the text string, in this case "Scrolling text".

The second argument sets the alignment of the text during the optional pause. You can use the same alignment options as in the previous example, i.e. PA_CENTER, PA_LEFT, or PA_RIGHT.

The third and fourth arguments set the speed of the animation and pause time respectively. The speed of the display is the time in milliseconds between animation frames. The lower this time the faster the animation. If you want to pause the text in between the in and out animation, you can set the pause time in milliseconds. I set it to zero so the text scrolls continuously.

Next, the in and out effects are specified. In this case I used PA_SCROLL_LEFT for both. See the example below for other text effects.

  myDisplay.displayText("Scrolling text", PA_CENTER, 100, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);

In the loop section, you only need two functions to create a scrolling text display.

First, we use the function displayAnimate() in an if statement. This function animates the display using the currently specified text and animation parameters and returns true when the animation has finished. When the animation has finished, we reset the display with the function displayReset() so the text is displayed in a loop.

void loop() {
  if (myDisplay.displayAnimate()) {
    myDisplay.displayReset();
  }
}

Other text effects

The library includes several other text effects that you can use:

  • PA_PRINT,
  • PA_SCAN_HORIZ,
  • PA_SCROLL_LEFT,
  • PA_WIPE,
  • PA_SCROLL_UP_LEFT,
  • PA_SCROLL_UP,
  • PA_OPENING_CURSOR,
  • PA_GROW_UP,
  • PA_MESH,
  • PA_SCROLL_UP_RIGHT,
  • PA_BLINDS,
  • PA_CLOSING,
  • PA_RANDOM,
  • PA_GROW_DOWN,
  • PA_SCAN_VERT,
  • PA_SCROLL_DOWN_LEFT,
  • PA_WIPE_CURSOR,
  • PA_DISSOLVE,
  • PA_OPENING,
  • PA_CLOSING_CURSOR,
  • PA_SCROLL_DOWN_RIGHT,
  • PA_SCROLL_RIGHT,
  • PA_SLICE,
  • PA_SCROLL_DOWN

The example code below steps through the different effect so you can see what they look like.

/*Example code for scrolling text and other text effects 
  on MAX7219 LED dot matrix display with Arduino. 
  More info: https://www.makerguides.com */

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

int i = 0;

textEffect_t texteffect[] =
{
  PA_PRINT,
  PA_SCAN_HORIZ,
  PA_SCROLL_LEFT,
  PA_WIPE,
  PA_SCROLL_UP_LEFT,
  PA_SCROLL_UP,
  PA_OPENING_CURSOR,
  PA_GROW_UP,
  PA_MESH,
  PA_SCROLL_UP_RIGHT,
  PA_BLINDS,
  PA_CLOSING,
  PA_RANDOM,
  PA_GROW_DOWN,
  PA_SCAN_VERT,
  PA_SCROLL_DOWN_LEFT,
  PA_WIPE_CURSOR,
  PA_DISSOLVE,
  PA_OPENING,
  PA_CLOSING_CURSOR,
  PA_SCROLL_DOWN_RIGHT,
  PA_SCROLL_RIGHT,
  PA_SLICE,
  PA_SCROLL_DOWN
};

// Define hardware type, size, and output pins:
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 3

// Create a new instance of the MD_Parola class with hardware SPI connection:
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Setup for software SPI:
// #define DATA_PIN 2
// #define CLK_PIN 4
// MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

void setup() {
  myDisplay.begin();
  myDisplay.setIntensity(0);
  myDisplay.setTextAlignment(PA_CENTER);
  myDisplay.setPause(1000);
  myDisplay.setSpeed(100);
  myDisplay.displayClear();
}

void loop() {
  if (myDisplay.displayAnimate()) {
    if (i < sizeof(texteffect)) {
      i++;
    }
    else {
      i = 0;
    }
    myDisplay.displayText("Hello", myDisplay.getTextAlignment(), 
                          myDisplay.getSpeed(), myDisplay.getPause(), 
                          texteffect[i], texteffect[i]);
    myDisplay.displayReset();
  }
}

Text sprites

A relatively new function of the MD_Parola library is animated text sprites. In computer graphics, a sprite is a two-dimensional bitmap that is integrated into a larger scene (in this case, the matrix display).

A sprite is made up of a number of frames that run sequentially to make the animation on the display. Once the animation reaches the last frame it restarts from the first frame.

Note that I used an 8×64 matrix display for this example by connecting two 8×32 displays together (MAX_DEVICES is set to 8).

/*Example code for sprite text effect on 
  MAX7219 LED dot matrix display with Arduino. 
  More info: https://www.makerguides.com */

#include "MD_Parola.h"
#include "MD_MAX72xx.h"
#include "SPI.h"

// Define hardware type, size, and output pins:
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8
#define CS_PIN 3

// Create a new instance of the MD_Parola class with hardware SPI connection:
MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Setup for software SPI:
// #define DATA_PIN 2
// #define CLK_PIN 4
// MD_Parola myDisplay = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// Sprite definitions:
const uint8_t F_PMAN1 = 6;
const uint8_t W_PMAN1 = 8;
const uint8_t PROGMEM pacman1[F_PMAN1 * W_PMAN1] =  // gobbling pacman animation
{
  0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
};

const uint8_t F_PMAN2 = 6;
const uint8_t W_PMAN2 = 18;
const uint8_t PROGMEM pacman2[F_PMAN2 * W_PMAN2] =  // pacman pursued by a ghost
{
  0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
  0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c, 0x00, 0x00, 0x00, 0xfe, 0x7b, 0xf3, 0x7f, 0xfb, 0x73, 0xfe,
};

const uint8_t F_WAVE = 14;
const uint8_t W_WAVE = 14;
const uint8_t PROGMEM wave[F_WAVE * W_WAVE] =  // triangular wave / worm
{
  0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10,
  0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20,
  0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40,
  0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
  0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
  0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
  0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10,
  0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08,
  0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04,
  0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02,
  0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02,
  0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04,
  0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08,
};

const uint8_t F_ROLL1 = 4;
const uint8_t W_ROLL1 = 8;
const uint8_t PROGMEM roll1[F_ROLL1 * W_ROLL1] =  // rolling square
{
  0xff, 0x8f, 0x8f, 0x8f, 0x81, 0x81, 0x81, 0xff,
  0xff, 0xf1, 0xf1, 0xf1, 0x81, 0x81, 0x81, 0xff,
  0xff, 0x81, 0x81, 0x81, 0xf1, 0xf1, 0xf1, 0xff,
  0xff, 0x81, 0x81, 0x81, 0x8f, 0x8f, 0x8f, 0xff,
};

const uint8_t F_ROLL2 = 4;
const uint8_t W_ROLL2 = 8;
const uint8_t PROGMEM roll2[F_ROLL2 * W_ROLL2] =  // rolling octagon
{
  0x3c, 0x4e, 0x8f, 0x8f, 0x81, 0x81, 0x42, 0x3c,
  0x3c, 0x72, 0xf1, 0xf1, 0x81, 0x81, 0x42, 0x3c,
  0x3c, 0x42, 0x81, 0x81, 0xf1, 0xf1, 0x72, 0x3c,
  0x3c, 0x42, 0x81, 0x81, 0x8f, 0x8f, 0x4e, 0x3c,
};

const uint8_t F_LINES = 3;
const uint8_t W_LINES = 8;
const uint8_t PROGMEM lines[F_LINES * W_LINES] =  // spaced lines
{
  0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
  0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
  0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
};

const uint8_t F_ARROW1 = 3;
const uint8_t W_ARROW1 = 10;
const uint8_t PROGMEM arrow1[F_ARROW1 * W_ARROW1] =  // arrow fading to center
{
  0x18, 0x3c, 0x7e, 0xff, 0x7e, 0x00, 0x00, 0x3c, 0x00, 0x00,
  0x18, 0x3c, 0x7e, 0xff, 0x00, 0x7e, 0x00, 0x00, 0x18, 0x00,
  0x18, 0x3c, 0x7e, 0xff, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x18,
};

const uint8_t F_ARROW2 = 3;
const uint8_t W_ARROW2 = 9;
const uint8_t PROGMEM arrow2[F_ARROW2 * W_ARROW2] =  // arrow fading to outside
{
  0x18, 0x3c, 0x7e, 0xe7, 0x00, 0x00, 0xc3, 0x00, 0x00,
  0x18, 0x3c, 0x7e, 0xe7, 0xe7, 0x00, 0x00, 0x81, 0x00,
  0x18, 0x3c, 0x7e, 0xe7, 0x00, 0xc3, 0x00, 0x00, 0x81,
};

const uint8_t F_SAILBOAT = 1;
const uint8_t W_SAILBOAT = 11;
const uint8_t PROGMEM sailboat[F_SAILBOAT * W_SAILBOAT] =  // sail boat
{
  0x10, 0x30, 0x58, 0x94, 0x92, 0x9f, 0x92, 0x94, 0x98, 0x50, 0x30,
};

const uint8_t F_STEAMBOAT = 2;
const uint8_t W_STEAMBOAT = 11;
const uint8_t PROGMEM steamboat[F_STEAMBOAT * W_STEAMBOAT] =  // steam boat
{
  0x10, 0x30, 0x50, 0x9c, 0x9e, 0x90, 0x91, 0x9c, 0x9d, 0x90, 0x71,
  0x10, 0x30, 0x50, 0x9c, 0x9c, 0x91, 0x90, 0x9d, 0x9e, 0x91, 0x70,
};

const uint8_t F_HEART = 5;
const uint8_t W_HEART = 9;
const uint8_t PROGMEM heart[F_HEART * W_HEART] =  // beating heart
{
  0x0e, 0x11, 0x21, 0x42, 0x84, 0x42, 0x21, 0x11, 0x0e,
  0x0e, 0x1f, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x1f, 0x0e,
  0x0e, 0x1f, 0x3f, 0x7e, 0xfc, 0x7e, 0x3f, 0x1f, 0x0e,
  0x0e, 0x1f, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x1f, 0x0e,
  0x0e, 0x11, 0x21, 0x42, 0x84, 0x42, 0x21, 0x11, 0x0e,
};

const uint8_t F_INVADER = 2;
const uint8_t W_INVADER = 10;
const uint8_t PROGMEM invader[F_INVADER * W_INVADER] =  // space invader
{
  0x0e, 0x98, 0x7d, 0x36, 0x3c, 0x3c, 0x36, 0x7d, 0x98, 0x0e,
  0x70, 0x18, 0x7d, 0xb6, 0x3c, 0x3c, 0xb6, 0x7d, 0x18, 0x70,
};

const uint8_t F_ROCKET = 2;
const uint8_t W_ROCKET = 11;
const uint8_t PROGMEM rocket[F_ROCKET * W_ROCKET] =  // rocket
{
  0x18, 0x24, 0x42, 0x81, 0x99, 0x18, 0x99, 0x18, 0xa5, 0x5a, 0x81,
  0x18, 0x24, 0x42, 0x81, 0x18, 0x99, 0x18, 0x99, 0x24, 0x42, 0x99,
};

const uint8_t F_FBALL = 2;
const uint8_t W_FBALL = 11;
const uint8_t PROGMEM fireball[F_FBALL * W_FBALL] =  // fireball
{
  0x7e, 0xab, 0x54, 0x28, 0x52, 0x24, 0x40, 0x18, 0x04, 0x10, 0x08,
  0x7e, 0xd5, 0x2a, 0x14, 0x24, 0x0a, 0x30, 0x04, 0x28, 0x08, 0x10,
};

const uint8_t F_CHEVRON = 1;
const uint8_t W_CHEVRON = 9;
const uint8_t PROGMEM chevron[F_CHEVRON * W_CHEVRON] =  // chevron
{
  0x18, 0x3c, 0x66, 0xc3, 0x99, 0x3c, 0x66, 0xc3, 0x81,
};

const uint8_t F_WALKER = 5;
const uint8_t W_WALKER = 7;
const uint8_t PROGMEM walker[F_WALKER * W_WALKER] =  // walking man
{
  0x00, 0x48, 0x77, 0x1f, 0x1c, 0x94, 0x68,
  0x00, 0x90, 0xee, 0x3e, 0x38, 0x28, 0xd0,
  0x00, 0x00, 0xae, 0xfe, 0x38, 0x28, 0x40,
  0x00, 0x00, 0x2e, 0xbe, 0xf8, 0x00, 0x00,
  0x00, 0x10, 0x6e, 0x3e, 0xb8, 0xe8, 0x00,
};

void setup() {
  myDisplay.begin();
  myDisplay.setIntensity(0);
  myDisplay.displayClear();
  myDisplay.setSpriteData(pacman2, W_PMAN2, F_PMAN2, pacman2, W_PMAN2, F_PMAN2);
  myDisplay.displayText("Parola sprites", PA_CENTER, 50, 1000, PA_SPRITE, PA_SPRITE);
}

void loop() {
  if (myDisplay.displayAnimate()) {
    myDisplay.displayReset();
  }
}

How the code works

After setting up the display like before, the text sprites are defined.

Two constants are used to define the sprite, one for the width (number of bytes) data for one sprite and the other for the number of frames contained in the animation. The total number of bytes required is the width * number of frames. Note that the sprite data is stored in PROGMEM to save RAM space.

Each row of the array is made up of hexadecimal numbers that set which LEDs need to light up in each column of the sprite.

The example includes many different sprite definitions, which you can also find in one of the examples that come with the library.

// Sprite definitions:
const uint8_t F_PMAN1 = 6;
const uint8_t W_PMAN1 = 8;
const uint8_t PROGMEM pacman1[F_PMAN1 * W_PMAN1] =  // gobbling pacman animation
{
  0x00, 0x81, 0xc3, 0xe7, 0xff, 0x7e, 0x7e, 0x3c,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x3c, 0x7e, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x24, 0x66, 0xe7, 0xff, 0xff, 0xff, 0x7e, 0x3c,
  0x00, 0x42, 0xe7, 0xe7, 0xff, 0xff, 0x7e, 0x3c,
};

In the setup, the function setSpriteData(inData, inWidth, inFrames, outData, outWidth, outFrames) is used to set up user data needed so that the library can display the sprite when the PA_SPRITE animation type is selected in the displayText() function.

You can select any of the predefined sprites, in this case I used pacman2 (pacman pursued by a ghost).

  myDisplay.setSpriteData(pacman2, W_PMAN2, F_PMAN2, pacman2, W_PMAN2, F_PMAN2);
  myDisplay.displayText("Parola sprites", PA_CENTER, 50, 1000, PA_SPRITE, PA_SPRITE);

The loop section is the same as before.

Conclusion

In this article, I have shown you how you can use a MAX7219 LED dot matrix display with Arduino. We looked at the basics of printing text, scrolling text, other text effects, and text sprites. There still are some less frequently used functions in the MD_Parola library that I haven't covered in this tutorial but you can check those out in the MD_Parola documentation on GitHub.

We also haven't talked about the fact that the MD_Parola library can divide a display into multiple zones that run different animations. Read the post Coordinate Parola Zone Animations on MAX7219 Display and Parola A to Z – Multi Zone Displays for more information on that.

Finally, if you want to chain different animation, switch between different animations by pressing buttons, or regulate the speed of the animation via an analog input have a look at the Control Parola Animations on MAX7219 LED Display tutorial, where we cover these use cases.

If you have any questions, feel free to ask them in the comment section.

Happy tinkering!