Matriz de leds con MAX7219 y Arduino Nano

Probando 4 displays de 8x8 leds rojos controlados por el MAX7219 concatenados en serie y manejados desde el Arduino Nano.

El módulo WCMCU incluye la matriz de 64 leds, el circuito de control con el MAX7219 y regletas de pins para conectar la matriz de leds a la placa del circuito de control, para conectar la alimentación y los pins de comunicaciones serie y otra regleta para conectar un módulo WCMCU con el siguiente cuando se usan varios en cadena.

Vista de la placa de control por el lado del MAX7219 antes de soldarle las regletas que permiten conectar la matriz de 8x8 leds...

Vista posterior de la placa de control del módulo WCMCU...

Matriz de 64 leds rojos...

Vista posterior de la matriz de leds con los pins de conexión...

Circuito de control con las regletas de alimentación, datos y conexión con la matriz de leds ya soldadas...

Posición en la que hay que conectar la matriz de leds. El lado de la matriz de leds que trae un código serigrafiado "1088AS" y un saliente de plástico en el centro tiene que ir del lado del circuito de control donde está serigrafiado "DISY1"...

Vista posterior de la disposición en la que hay que conectar la matriz y el circuito de control...

Probando un único módulo WCMCU con el Arduino Nano...

En este momento estamos conectando en cadena 4 módulos WCMCU y poniéndole las matrices de led...

Los cuatro módulos WCMCU se han conectado entre sí con alambre (clips de sujetar papeles finos). Estos "clips" permiten la conexión eléctrica y a mayores, sirven para darle rigidez al montaje manteniendo los cuatro módulos siempre unidos formando una única matriz de 256 leds...

Vista posterior de los cuatro módulos WCMCU unidos con clips de sujetar papeles (alambre fino) de manera que quedan fijos como si fuesen un único circuito...

Los cuatro módulos WCMCU ya con las matrices de 8x8 leds colocadas...

Cada módulo o matriz de 8x8 leds mide aproximadamente unos 33x33mm. Los cuatro módulos unidos miden unos 130mm de largo más otros 15mm más para los pins de conexión y miden unos 33mm de alto.

Los leds tienen mucha intensidad lumínica y se ven muy bien con el ojo humano pero en las fotos ese rojo tan intenso de los led sale casi en color blanco.

Probando los cuatro módulos WCMCU con el Arduino Nano

Si se encienden los 256 leds a la vez hay que tener una fuente de alimentación con suficiente amperaje porque consumen algo más de 1A a los 5V...

Vídeo del funcionamiento de este montaje (Archivo MP4. Tamaño: 10,6 MB)...

Existen varias librerías para facilitar el manejo de matrices de leds con MAX7219 desde Arduino Nano. En este caso se usa la librería llamada MD_Parola que se puede descargar desde https://github.com/MajicDesigns/MD_Parola y se usa con un programa de ejemplo de miliohm.com descargado desde: https://miliohm.com/how-to-use-max7219-led-matrix-running-text-display-sensor-data-add-more-led-matrix-with-arduino/

Cableado entre el Arduino Nano y el la matriz de leds WCMCU

Arduino NanoMatriz de leds WCMCU
5V VCC
GND GND
D10 CS
D11 DIN
D13 CLK

El VCC de la matriz de leds se puede conectar a la salida de 5V del Arduino como se indica en la tabla anterior pero si se encienden a la vez muchos de los 256 led, esa opción no daría suficiente amparaje así que finalmente el VCC de las matrices de led no se conectaron al Arduino sino que se conectaron a una fuente de alimentación externa de 5V DC. El GND de esa fuente externa se conectó al GND del Arduino.

Las conexiones entre Arduino Nano y los módulos WCMCU indicadas anteriormente son las adecuadas para este ejemplo utilizado en las pruebas pero con otras librerías puede que los pins utilizados del Arduino sean otros.

También suele ser necesario indicar en el programa Arduino el número de MAX7219 utilizados en cadena. Por ejemplo en el código que se muestra más abajo se indica en el programa que se han usado 4 módulos en serie mediante la línea: #define MAX_DEVICES 4 pero ese número puede que varíe si se usan menos o más matrices dispuestas en serie.

En las siguientes líneas se muestra el código usado en las pruebas que muestra textos en scroll y que se ha descargado desde: https://miliohm.com/how-to-use-max7219-led-matrix-running-text-display-sensor-data-add-more-led-matrix-with-arduino/

// https://miliohm.com/how-to-use-max7219-led-matrix-running-text-display-sensor-data-add-more-led-matrix-with-arduino/
//
// Use the Parola library to scroll text on the display
//
// Demonstrates the use of the scrolling function to display text received
// from the serial interface
//
// User can enter text on the serial monitor and this will display as a
// scrolling message on the display.
// Speed for the display is controlled by a pot on SPEED_IN analog in.
// Scrolling direction is controlled by a switch on DIRECTION_SET digital in.
// Invert ON/OFF is set by a switch on INVERT_SET digital in.
//
// UISwitch library can be found at https://github.com/MajicDesigns/MD_UISwitch
// MD_MAX72XX library can be found at https://github.com/MajicDesigns/MD_MAX72XX
//

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

// set to 1 if we are implementing the user interface pot, switch, etc
#define USE_UI_CONTROL 0

#if USE_UI_CONTROL
#include <MD_UISwitch.h>
#endif

// Turn on debug statements to the serial output
#define DEBUG 0

#if DEBUG
#define PRINT(s, x) { Serial.print(F(s)); Serial.print(x); }
#define PRINTS(x) Serial.print(F(x))
#define PRINTX(x) Serial.println(x, HEX)
#else
#define PRINT(s, x)
#define PRINTS(x)
#define PRINTX(x)
#endif

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

// HARDWARE SPI
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// SOFTWARE SPI
//MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// Scrolling parameters
#if USE_UI_CONTROL
const uint8_t SPEED_IN = A5;
const uint8_t DIRECTION_SET = 8;  // change the effect
const uint8_t INVERT_SET = 9;     // change the invert

const uint8_t SPEED_DEADBAND = 5;
#endif // USE_UI_CONTROL

//uint8_t scrollSpeed = 25;    // default frame delay value
uint8_t scrollSpeed = 50;    // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
//uint16_t scrollPause = 2000; // in milliseconds
uint16_t scrollPause = 1000; // in milliseconds

// Global message buffers shared by Serial and Scrolling functions
#define    BUF_SIZE    75
char curMessage[BUF_SIZE] = { "" };
// char newMessage[BUF_SIZE] = { "Hello! Enter new message?" };
char newMessage[BUF_SIZE] = { "alinos.sytes.net  2023   J I D S" };
bool newMessageAvailable = true;

#if USE_UI_CONTROL

MD_UISwitch_Digital uiDirection(DIRECTION_SET);
MD_UISwitch_Digital uiInvert(INVERT_SET);

void doUI(void)
{
  // set the speed if it has changed
  {
    int16_t speed = map(analogRead(SPEED_IN), 0, 1023, 10, 150);

    if ((speed >= ((int16_t)P.getSpeed() + SPEED_DEADBAND)) ||
      (speed <= ((int16_t)P.getSpeed() - SPEED_DEADBAND)))
    {
      P.setSpeed(speed);
      scrollSpeed = speed;
      PRINT("\nChanged speed to ", P.getSpeed());
    }
  }

  if (uiDirection.read() == MD_UISwitch::KEY_PRESS) // SCROLL DIRECTION
  {
    PRINTS("\nChanging scroll direction");
    scrollEffect = (scrollEffect == PA_SCROLL_LEFT ? PA_SCROLL_RIGHT : PA_SCROLL_LEFT);
    P.setTextEffect(scrollEffect, scrollEffect);
    P.displayClear();
    P.displayReset();
  }

  if (uiInvert.read() == MD_UISwitch::KEY_PRESS)  // INVERT MODE
  {
    PRINTS("\nChanging invert mode");
    P.setInvert(!P.getInvert());
  }
}
#endif // USE_UI_CONTROL

void readSerial(void)
{
  static char *cp = newMessage;

  while (Serial.available())
  {
    *cp = (char)Serial.read();
    if ((*cp == '\n') || (cp - newMessage >= BUF_SIZE-2)) // end of message character or full buffer
    {
      *cp = '\0'; // end the string
      // restart the index for next filling spree and flag we have a message waiting
      cp = newMessage;
      newMessageAvailable = true;
    }
    else  // move char pointer to next position
      cp++;
  }
}

void setup()
{
  Serial.begin(57600);
  Serial.print("\n[Parola Scrolling Display]\nType a message for the scrolling display\nEnd message line with a newline");

#if USE_UI_CONTROL
  uiDirection.begin();
  uiInvert.begin();
  pinMode(SPEED_IN, INPUT);

  doUI();
#endif // USE_UI_CONTROL

  P.begin();
  P.displayText(curMessage, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect);
}

void loop()
{
#if USE_UI_CONTROL
  doUI();
#endif // USE_UI_CONTROL

  if (P.displayAnimate())
  {
    if (newMessageAvailable)
    {
      strcpy(curMessage, newMessage);
      newMessageAvailable = false;
    }
    P.displayReset();
  }
  readSerial();
}

Pulsa aquí para descargar el código "parola1.ino" utilizado en esta prueba o accede al ejemplo de miliohm.com en la página: https://miliohm.com/how-to-use-max7219-led-matrix-running-text-display-sensor-data-add-more-led-matrix-with-arduino/. En el repositorio de GitHub de la librería: "MajicDesigns / MD_Parola" https://github.com/MajicDesigns/MD_Parola se pueden encontrar más ejemplos.


Creación de fuentes de letra o caracteres especiales

Usando la librería Parola se pueden crear fuentes de letra o caracteres customizados, es decir, se puede hacer que se iluminen los led de las matrices individualmente como se necesiten.

Por ejemplo, utilizando el sensor DHT22 se quiere mostrar la temperatura en el panel de leds y se quiere que salga como un carácter el símbolo de grados centígrados (celsius) o el de grados Fahrenheit. En este caso se van a crear dos caracteres nuevos, uno que muestra el símbolo de grados y una letra "c" para grados centígrados y otro similar pero con una letra "F" para los grados Fahrenheit.

uint8_t degC[] = { 6, 3, 3, 56, 68, 68, 68 };  // Deg C
uint8_t degF[] = { 6, 3, 3, 124, 20, 20, 4 };  // Deg F
 

void setup(void) {
  Wire.begin();
 
  P.begin(2);
  P.setInvert(false);
 
  P.setZone(0, MAX_DEVICES - 4, MAX_DEVICES - 1);
  P.setZone(1, MAX_DEVICES - 4, MAX_DEVICES - 1);
  
  P.displayZoneText(0, szMesg, PA_CENTER, SPEED_TIME, 0, PA_PRINT, PA_NO_EFFECT);
 
  P.addChar('$', degC);
  P.addChar('&', degF);
 

  dtostrf(celsius, 3, 1, szMesg);
  strcat(szMesg, "$");   // en este caso va a imprimir el valor de los grados centígrados y seguido el símbolo... ºc
  
  // Para imprimir los grados Fahrenheit se podría usar...
  dtostrf(fahrenheit, 3, 1, szMesg);
  strcat(szMesg, "&");   // en este caso se imprimiría el valor de los grados Fahrenheit seguido del símbolo... ºF

Las líneas de código anteriores se obtuvieron de la página https://how2electronics.com/8x32-max7219-dot-matrix-led-display-with-arduino/

Las matrices de bytes que definen el dibujo de esos símbolos...

  uint8_t degC[] = { 6, 3, 3, 56, 68, 68, 68 };  // Deg C
  uint8_t degF[] = { 6, 3, 3, 124, 20, 20, 4 };  // Deg F

se construyen de la siguiente forma...

uint8_t degC[] = { 6, 3, 3, 56, 68, 68, 68 };  // Deg C

El primer 6 de la línea anterior es el nº de bytes (los que son diferentes de 0) que forman el carácter que en este ejemplo serían el resto de bytes...

 3, 3, 56, 68, 68, 68 
 
Traduciendo esos bytes a binario...
 
 00000011
 00000011
 00111000
 01000100
 01000100
 01000100
 
Si girásemos ese conjunto de bits 90 grados a la izquierda se vería un símbolo: ºc   (grados centígrados)
  
 110000
 110000
 000111
 001000
 001000
 001000
 000111
 000000 

Si le metemos un espacio entre bit y bit se vería un poco mejor...
  
 1 1 0 0 0 0
 1 1 0 0 0 0
 0 0 0 1 1 1
 0 0 1 0 0 0
 0 0 1 0 0 0
 0 0 1 0 0 0
 0 0 0 1 1 1
 0 0 0 0 0 0 

Sustituyendo los 1 por * y los 0 por un espacio en blanco quedaría...

 * *        
 * *        
       * * *
     *      
     *      
     *      
       * * *
            

 
 Este otro código...
 
 uint8_t degF[] = { 6, 3, 3, 124, 20, 20, 4 };  // Deg F
 
 sería...
 
 el primer 6 indica los bytes que forman la fuente de letra...
 
 3, 3, 124, 20, 20, 4 
 
 y al convertir esos bytes a binario y rellenar con ceros hasta los 8 dígitos quedaría...
 
 00000011
 00000011
 01111100
 00010100
 00010100
 00000100
 
y si esa matriz de bits la giramos -90 grados quedaría algo como:  ºF  (grados Fahrenheit)

 11000000
 11000000
 00111111
 00100000
 00111110
 00100000
 00100000
 00000000

Se pueden separar los caracteres y sustituir los 1 por * para verlo mejor...

 * * 0 0 0 0 0 0
 * * 0 0 0 0 0 0
 0 0 * * * * * *
 0 0 * 0 0 0 0 0
 0 0 * * * * * 0
 0 0 * 0 0 0 0 0
 0 0 * 0 0 0 0 0
 0 0 0 0 0 0 0 0

Si quitamos los 0 se verá mejor el dibujo de la fuente de letra...

 * *            
 * *            
     * * * * * *
     *          
     * * * * *  
     *          
     *          

Existe una librería y una hoja de cálculo para facilitar el dibujo de caracteres... https://github.com/MajicDesigns/MD_MAX72XX/tree/main