How to make a customized LED matrix panel using an Arduino Nano board

How to make a customized LED matrix panel using an Arduino Nano board

Hello and welcome back. In this project, we will learn how to make a customized LED matrix panel using an Arduino Nano board. For this project, I used four 8×8 LED matrices along with four MAX7219 driver modules. Using this LED matrix panel, we can display text, characters, animations, and various shapes on the screen. I have already added 40 different design patterns, including multiple visual effects, and you can easily change or add your own patterns by modifying the code.

Also, I designed a custom PCB specifically for this LED matrix panel. Because of this PCB design, there is no need to use breadboards or jumper wires, which makes the project cleaner and suitable for long-term use. You can modify it to your table clock, Text banner, etc.

Ok, let’s do this project step by step. The required components are given below.

Disclosure: These Amazon links are Affiliate links. As an Amazon Associate, I earn from qualifying purchases.

Step 1

Firstly, identify these components.

Step 2

Secondly, let’s order the PCBs for this project.

  • Click the “Instant Quote” button and upload the Gerber file, which you can download from the link below.
  • Gerber file – Download
  • For this project, I ordered five red PCBs. Next, select the build time and shipping method. Finally, click “Save to Cart” and complete the payment.

Step 3

Thirdly, let’s unbox the PCB package and check the PCB quality.

Step 4

Next, carefully solder the resistors, capacitors, two-pin terminal, and female headers onto the PCB.

Step 5

Afterward, connect the LED displays, drivers, and Arduino Nano board carefully. Then, connect the Arduino to your computer to upload the code.

Step 6

Next, copy and paste the following program into the Arduino IDE. Then, install the MD_MAX72xx library from the library manager.

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

// ================= HARDWARE =================
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 4
#define CS_PIN 3

#define WIDTH  (MAX_DEVICES * 8)
#define HEIGHT 8

MD_MAX72XX mx(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// ================= CAMERA OPTIMIZATION =================
#define CAMERA_MODE true
const uint16_t frameDelay = 80;     // 60–90 ms best for camera
const uint16_t patternTime = 4000;  // Change pattern every 4s

unsigned long lastFrame = 0;
unsigned long lastPattern = 0;

uint8_t currentPattern = 0;
const uint8_t TOTAL_PATTERNS = 20;

// ======================================================
// PATTERNS (STAGE STYLE SHAPES ONLY)
// ======================================================

// 1. Twinkling Stars
void pat_stars() {
  mx.clear();
  for (int i = 0; i < 12; i++)
    mx.setPoint(random(HEIGHT), random(WIDTH), true);
}

// 2. Moving Stars
void pat_movingStars() {
  static int t = 0;
  mx.clear();
  for (int i = 0; i < HEIGHT; i++)
    mx.setPoint(i, (t + i * 3) % WIDTH, true);
  t++;
}

// 3. Expanding Rectangle Frame
void pat_rectExpand() {
  static int s = 0; static bool grow = true;
  mx.clear();
  for (int x = s; x < WIDTH - s; x++) {
    mx.setPoint(s, x, true);
    mx.setPoint(HEIGHT - 1 - s, x, true);
  }
  for (int y = s; y < HEIGHT - s; y++) {
    mx.setPoint(y, s, true);
    mx.setPoint(y, WIDTH - 1 - s, true);
  }
  grow ? s++ : s--;
  if (s >= 3) grow = false;
  if (s <= 0) grow = true;
}

// 4. Rectangle Scanner
void pat_rectScan() {
  static int x = 0;
  mx.clear();
  for (int y = 0; y < HEIGHT; y++)
    mx.setPoint(y, x, true);
  x = (x + 1) % WIDTH;
}

// 5. Circle Pulse
void pat_circlePulse() {
  static int r = 2; static bool grow = true;
  mx.clear();
  int cx = WIDTH / 2, cy = HEIGHT / 2;
  for (int y = 0; y < HEIGHT; y++)
    for (int x = 0; x < WIDTH; x++) {
      int d = (x - cx)*(x - cx) + (y - cy)*(y - cy);
      if (abs(d - r*r) < 4) mx.setPoint(y, x, true);
    }
  grow ? r++ : r--;
  if (r > 12) grow = false;
  if (r < 2) grow = true;
}

// 6. Double Circle
void pat_doubleCircle() {
  mx.clear();
  int cx = WIDTH / 2, cy = HEIGHT / 2;
  for (int y = 0; y < HEIGHT; y++)
    for (int x = 0; x < WIDTH; x++) {
      int d = (x - cx)*(x - cx) + (y - cy)*(y - cy);
      if (abs(d - 16) < 4 || abs(d - 36) < 4)
        mx.setPoint(y, x, true);
    }
}

// 7. Diamond Pulse
void pat_diamondPulse() {
  static int s = 0; static bool grow = true;
  mx.clear();
  int cx = WIDTH / 2, cy = HEIGHT / 2;
  for (int i = -s; i <= s; i++) {
    mx.setPoint(cy + i, cx, true);
    mx.setPoint(cy, cx + i, true);
  }
  grow ? s++ : s--;
  if (s >= 3) grow = false;
  if (s <= 0) grow = true;
}

// 8. Moving Diamond
void pat_diamondMove() {
  static int x = 0;
  mx.clear();
  for (int i = -2; i <= 2; i++) {
    mx.setPoint(HEIGHT / 2 + i, x, true);
    mx.setPoint(HEIGHT / 2, x + i, true);
  }
  x = (x + 1) % WIDTH;
}

// 9. Horizontal Bars
void pat_hBars() {
  static int y = 0;
  mx.clear();
  for (int x = 0; x < WIDTH; x++)
    mx.setPoint(y, x, true);
  y = (y + 1) % HEIGHT;
}

// 10. Vertical Bars
void pat_vBars() {
  static int x = 0;
  mx.clear();
  for (int y = 0; y < HEIGHT; y++)
    mx.setPoint(y, x, true);
  x = (x + 1) % WIDTH;
}

// 11. Checker Ambient
void pat_checker() {
  mx.clear();
  for (int y = 0; y < HEIGHT; y++)
    for (int x = 0; x < WIDTH; x++)
      if ((x + y) % 2 == 0)
        mx.setPoint(y, x, true);
}

// 12. Diagonal Sweep
void pat_diagonal() {
  static int t = 0;
  mx.clear();
  for (int x = 0; x < WIDTH; x++)
    mx.setPoint((x + t) % HEIGHT, x, true);
  t++;
}

// 13. Star Burst
void pat_starBurst() {
  static int t = 0;
  mx.clear();
  int cx = WIDTH / 2, cy = HEIGHT / 2;
  for (int i = 0; i < 8; i++)
    mx.setPoint((cy + t*i) % HEIGHT, (cx + t*i) % WIDTH, true);
  t++;
}

// 14. Random Sparkle (Slow)
void pat_sparkle() {
  mx.setPoint(random(HEIGHT), random(WIDTH), true);
}

// 15. Expanding Fill Box
void pat_fillExpand() {
  static int s = 0;
  mx.clear();
  for (int y = s; y < HEIGHT - s; y++)
    for (int x = s; x < WIDTH - s; x++)
      mx.setPoint(y, x, true);
  s = (s + 1) % 4;
}

// 16. Contracting Fill Box
void pat_fillContract() {
  static int s = 3;
  mx.clear();
  for (int y = s; y < HEIGHT - s; y++)
    for (int x = s; x < WIDTH - s; x++)
      mx.setPoint(y, x, true);
  s--; if (s < 0) s = 3;
}

// 17. Stage Flash Blocks
void pat_flash() {
  mx.clear();
  for (int i = 0; i < 6; i++)
    mx.setPoint(random(HEIGHT), random(WIDTH), true);
}

// 18. Center Pulse
void pat_centerPulse() {
  static bool on = false;
  mx.clear();
  if (on)
    mx.setPoint(HEIGHT / 2, WIDTH / 2, true);
  on = !on;
}

// 19. Smooth Wave
void pat_wave() {
  static int t = 0;
  mx.clear();
  for (int x = 0; x < WIDTH; x++) {
    int y = HEIGHT / 2 + sin((x + t) * 0.3) * 3;
    mx.setPoint(y, x, true);
  }
  t++;
}

// 20. Ambient Fade
void pat_ambient() {
  static bool on = true;
  on = !on;
  if (on) pat_checker();
  else mx.clear();
}

// ======================================================
void (*patterns[])() = {
  pat_stars, pat_movingStars, pat_rectExpand, pat_rectScan,
  pat_circlePulse, pat_doubleCircle, pat_diamondPulse,
  pat_diamondMove, pat_hBars, pat_vBars, pat_checker,
  pat_diagonal, pat_starBurst, pat_sparkle, pat_fillExpand,
  pat_fillContract, pat_flash, pat_centerPulse,
  pat_wave, pat_ambient
};

// ================= SETUP =================
void setup() {
  mx.begin();

  // CAMERA SAFE BRIGHTNESS
  if (CAMERA_MODE)
    mx.control(MD_MAX72XX::INTENSITY, 3);
  else
    mx.control(MD_MAX72XX::INTENSITY, 8);

  mx.clear();
  randomSeed(analogRead(A0));
}

// ================= LOOP =================
void loop() {
  if (millis() - lastFrame > frameDelay) {
    lastFrame = millis();
    patterns[currentPattern]();
  }

  if (millis() - lastPattern > patternTime) {
    lastPattern = millis();
    currentPattern = (currentPattern + 1) % TOTAL_PATTERNS;
    mx.clear();
  }
}
  • Now, select the board and port. After, click the upload button.

Step 7

Next, disconnect the USB cable and connect an external power supply to the LED matrix display. You can easily use a 9V battery to power it.

Now it’s time to check out your project! You can watch the full video guide below. We hope to see you in the next project. Have a great day!

How to make a customized LED matrix panel using an Arduino Nano board

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *