Panduan Step-by-Step: Dari Nol sampai Display Menyala
Step 1: Persiapan Hardware
Yang Anda Butuhkan:
- ESP32 DevKit V1
- P10 LED Matrix Panel (32×16, single color red)
- Power Supply 5V 5A (minimum 3A)
- Kabel jumper female-to-female (minimal 7 buah)
- Kabel USB Micro (untuk program ESP32)
- Breadboard (optional, untuk testing)
- Multimeter (optional, untuk check voltage)
Step 2: Library yang Dibutuhkan:
DMD32Plus (https://github.com/ahmadfathan/DMD32Plus)
Saat artikel ini dibuat, saya menggunakan DMD32Plus versi 1.2.0 dan Arduino IDE versi 2.3.7.
Step 3: Rangkaian
PENTING – Baca Ini Dulu:
- ⚠️ JANGAN colok power dulu sebelum wiring selesai!
- ⚠️ JANGAN power panel dari ESP32 atau USB!
- ⚠️ Panel butuh 5V dengan ampere BESAR (3-8A)
- ⚠️ GND harus common antara ESP32 dan Power Supply
Wiring Diagram:

Step 3: Kode Program
1. Blink LED di Panel:
#include <DMD32Plus.h>
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
hw_timer_t *timer = NULL;
void IRAM_ATTR triggerScan() {
dmd.scanDisplayBySPI();
}
void setup() {
Serial.begin(115200);
Serial.println("ESP32 P10 Test");
// Setup timer
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &triggerScan, true);
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
dmd.clearScreen(true);
}
void loop() {
// All ON
Serial.println("All pixels ON");
dmd.clearScreen(false);
delay(2000);
// All OFF
Serial.println("All pixels OFF");
dmd.clearScreen(true);
delay(2000);
}
PENTING:
- Panel HARUS menggunakan power supply external 5V 3-5A
- JANGAN power panel dari ESP32 atau USB!
- Pastikan GND common antara ESP32 dan power supply
2. Tampilkan Teks
#include <DMD32Plus.h>
#include "fonts/SystemFont5x7.h"
#include "fonts/Arial_black_16.h"
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
hw_timer_t *timer = NULL;
// Brightness setup
#define PWM_FREQ 5000
#define PWM_CHANNEL 0
#define PWM_RESOLUTION 8
#define PIN_DMD_nOE 22
void IRAM_ATTR triggerScan() {
dmd.scanDisplayBySPI();
}
void setupBrightnessPWM() {
ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(PIN_DMD_nOE, PWM_CHANNEL);
}
void setBrightness(uint8_t brightness) {
ledcWrite(PWM_CHANNEL, brightness);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &triggerScan, true);
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
dmd.clearScreen(true);
setupBrightnessPWM();
setBrightness(200);
Serial.println("Display Text Demo");
}
void loop() {
// Text dengan System Font
dmd.clearScreen(true);
dmd.selectFont(System5x7);
dmd.drawString(2, 4, "HELLO", 5, GRAPHICS_NORMAL);
delay(2000);
// Text dengan font besar
dmd.clearScreen(true);
dmd.selectFont(Arial_Black_16);
dmd.drawString(1, 0, "DMD", 3, GRAPHICS_NORMAL);
delay(2000);
// Multi-line text
dmd.clearScreen(true);
dmd.selectFont(System5x7);
dmd.drawString(1, 0, "Line1", 5, GRAPHICS_NORMAL);
dmd.drawString(1, 8, "Line2", 5, GRAPHICS_NORMAL);
delay(2000);
}
Tips Text:
- System5x7: Cocok untuk multi-line text
- Arial_Black_16: Cocok untuk text besar single line
- Untuk 1 panel (32×16), jangan terlalu panjang
3. Demo Jam Digital
#include <DMD32Plus.h>
#include "fonts/SystemFont5x7.h"
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
hw_timer_t *timer = NULL;
// Brightness
#define PWM_FREQ 5000
#define PWM_CHANNEL 0
#define PWM_RESOLUTION 8
#define PIN_DMD_nOE 22
// Variabel jam (simulasi)
int hours = 12;
int minutes = 30;
int seconds = 0;
unsigned long lastUpdate = 0;
boolean colonOn = true;
void IRAM_ATTR triggerScan() {
dmd.scanDisplayBySPI();
}
void setupBrightnessPWM() {
ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(PIN_DMD_nOE, PWM_CHANNEL);
}
void setBrightness(uint8_t brightness) {
ledcWrite(PWM_CHANNEL, brightness);
}
void updateTime() {
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
if (hours >= 24) hours = 0;
}
}
}
void displayClock() {
dmd.clearScreen(true);
dmd.selectFont(System5x7);
char h[3], m[3];
sprintf(h, "%02d", hours);
sprintf(m, "%02d", minutes);
// Format HH:MM
dmd.drawString(5, 4, h, 2, GRAPHICS_NORMAL);
if (colonOn) {
dmd.drawString(15, 4, ":", 1, GRAPHICS_OR);
} else {
dmd.drawString(15, 4, " ", 1, GRAPHICS_NORMAL);
}
dmd.drawString(19, 4, m, 2, GRAPHICS_NORMAL);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &triggerScan, true);
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
dmd.clearScreen(true);
setupBrightnessPWM();
setBrightness(150); // Brightness medium untuk clock
Serial.println("Digital Clock Demo");
}
void loop() {
// Update waktu setiap 1 detik
if (millis() - lastUpdate >= 1000) {
updateTime();
lastUpdate = millis();
}
// Toggle colon setiap 500ms
static unsigned long lastBlink = 0;
if (millis() - lastBlink >= 500) {
colonOn = !colonOn;
lastBlink = millis();
}
displayClock();
delay(50);
}
Jika menggunakan RTC Real-time:
Install library RTClib dan tambahkan:
#include <RTClib.h>
RTC_DS3231 rtc;
// Di setup():
rtc.begin();
// Di loop():
DateTime now = rtc.now();
hours = now.hour();
minutes = now.minute();
seconds = now.second();
4. Graphics & Animasi dengan Fade
#include <DMD32Plus.h>
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
hw_timer_t *timer = NULL;
// Brightness
#define PWM_FREQ 5000
#define PWM_CHANNEL 0
#define PWM_RESOLUTION 8
#define PIN_DMD_nOE 22
void IRAM_ATTR triggerScan() {
dmd.scanDisplayBySPI();
}
void setupBrightnessPWM() {
ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(PIN_DMD_nOE, PWM_CHANNEL);
}
void setBrightness(uint8_t brightness) {
ledcWrite(PWM_CHANNEL, brightness);
}
// Fade in effect
void fadeIn(int duration) {
for (int b = 0; b <= 255; b += 5) {
setBrightness(b);
delay(duration / 51); // 255/5 = 51 steps
}
}
// Fade out effect
void fadeOut(int duration) {
for (int b = 255; b >= 0; b -= 5) {
setBrightness(b);
delay(duration / 51);
}
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &triggerScan, true);
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
dmd.clearScreen(true);
setupBrightnessPWM();
setBrightness(0); // Mulai dari gelap
Serial.println("Graphics & Animation Demo");
}
void loop() {
// === Animasi 1: Box dengan Fade In ===
dmd.clearScreen(true);
dmd.drawBox(0, 0, 31, 15, GRAPHICS_NORMAL);
dmd.drawFilledBox(10, 5, 21, 10, GRAPHICS_NORMAL);
fadeIn(1000); // Fade in 1 detik
delay(2000);
fadeOut(1000); // Fade out 1 detik
delay(500);
// === Animasi 2: Circle dengan Fade ===
setBrightness(0);
dmd.clearScreen(true);
dmd.drawCircle(16, 8, 7, GRAPHICS_NORMAL);
dmd.drawCircle(16, 8, 4, GRAPHICS_NORMAL);
fadeIn(1000);
delay(2000);
fadeOut(1000);
delay(500);
// === Animasi 3: Expanding Circle dengan Fade ===
setBrightness(200);
for (int r = 1; r <= 15; r++) {
dmd.clearScreen(true);
dmd.drawCircle(16, 8, r, GRAPHICS_NORMAL);
delay(80);
}
fadeOut(800);
delay(500);
// === Animasi 4: Loading Bar dengan Fade ===
setBrightness(0);
dmd.clearScreen(true);
dmd.drawBox(2, 6, 29, 10, GRAPHICS_NORMAL);
fadeIn(500);
// Animate loading bar
for (int x = 3; x < 29; x++) {
dmd.drawFilledBox(3, 7, x, 9, GRAPHICS_NORMAL);
delay(50);
}
delay(1000);
fadeOut(500);
delay(500);
// === Animasi 5: Bouncing Box ===
setBrightness(200);
int x = 0, y = 0;
int dx = 1, dy = 1;
int boxSize = 5;
for (int frame = 0; frame < 80; frame++) {
dmd.clearScreen(true);
dmd.drawFilledBox(x, y, x + boxSize, y + boxSize, GRAPHICS_NORMAL);
x += dx;
y += dy;
if (x <= 0 || x >= (32 - boxSize)) dx = -dx;
if (y <= 0 || y >= (16 - boxSize)) dy = -dy;
delay(40);
}
fadeOut(800);
delay(500);
}
Efek Fade Tambahan:
// Pulse effect (loop terang-redup)
void pulseEffect(int cycles) {
for (int i = 0; i < cycles; i++) {
fadeIn(500);
fadeOut(500);
}
}
// Quick flash
void flashEffect(int times) {
for (int i = 0; i < times; i++) {
setBrightness(255);
delay(100);
setBrightness(0);
delay(100);
}
}
5. Running Text dengan Container
#include <DMD32Plus.h>
#include <DMDContainer.h>
#include "fonts/SystemFont5x7.h"
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
hw_timer_t *timer = NULL;
// Brightness
#define PWM_FREQ 5000
#define PWM_CHANNEL 0
#define PWM_RESOLUTION 8
#define PIN_DMD_nOE 22
// Container untuk running text
DMDContainer container(0, 0, 31, 15);
void IRAM_ATTR triggerScan() {
dmd.scanDisplayBySPI();
}
void setupBrightnessPWM() {
ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(PIN_DMD_nOE, PWM_CHANNEL);
}
void setBrightness(uint8_t brightness) {
ledcWrite(PWM_CHANNEL, brightness);
}
void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &triggerScan, true);
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
dmd.clearScreen(true);
setupBrightnessPWM();
setBrightness(200);
container.setFont(System5x7);
Serial.println("Running Text Demo");
}
void loop() {
char text[] = "Welcome to Indonesia - ESP32 P10 Display";
// Start dari kanan luar (pixel 32)
int16_t posX = 32;
dmd.clearScreen(true);
// Loop sampai text keluar sempurna di kiri
while (true) {
container.clear();
// Draw text dan dapatkan width
uint16_t textWidth = container.appendText(posX, 4, text, strlen(text));
// Draw container ke DMD
dmd.drawContainer(&container);
// Gerakkan ke kiri
posX--;
// Jika text sudah keluar sempurna, break
if (posX + textWidth < 0) {
break;
}
delay(30); // Kecepatan scroll
}
delay(500);
}
Running Text dengan Border:
void loop() {
char text[] = "Bordered Text Demo";
int16_t posX = 32;
while (true) {
// Clear dan redraw border
dmd.clearScreen(true);
dmd.drawBox(0, 0, 31, 15, GRAPHICS_NORMAL);
container.clear();
uint16_t w = container.appendText(posX, 4, text, strlen(text));
dmd.drawContainer(&container);
posX--;
if (posX + w < 0) break;
delay(30);
}
delay(500);
}
Step 4. Tips & Troubleshooting
Brightness Settings:
setBrightness(255); // Maksimal (outdoor siang)
setBrightness(200); // Terang (indoor siang)
setBrightness(150); // Medium (indoor)
setBrightness(100); // Redup (malam)
setBrightness(50); // Sangat redup (hemat daya)
Common Issues:
1. Display tidak menyala:
- Cek power supply 5V terhubung ke panel
- Cek GND common antara ESP32 dan PSU
- Cek semua kabel pin
2. Display flicker:
- Cek koneksi CLK dan LAT
- Kabel jangan terlalu panjang (max 20cm)
3. Brightness tidak berubah:
- Pastikan
setupBrightnessPWM()dipanggil setelah DMD init - Cek koneksi pin GPIO 22 (nOE)
4. Text terpotong:
- Untuk 1 panel (32×16), gunakan System5x7 untuk text panjang
- Arial_Black_16 hanya untuk text pendek
Auto Brightness dengan LDR:
#define LDR_PIN 34
void loop() {
int ldrValue = analogRead(LDR_PIN);
int brightness = map(ldrValue, 0, 4095, 50, 255);
setBrightness(brightness);
// ... rest of your code
}
Multiple Panel (2 panel horizontal):
#define DISPLAYS_ACROSS 2 // Ubah dari 1 ke 2
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
// Container juga berubah
DMDContainer container(0, 0, 63, 15); // 64x16 untuk 2 panel
Step 5. Template Project Lengkap (Opsional)
Copy template ini untuk project baru:
#include <DMD32Plus.h>
#include <DMDContainer.h>
#include "fonts/SystemFont5x7.h"
#include "fonts/Arial_black_16.h"
#define DISPLAYS_ACROSS 1
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
hw_timer_t *timer = NULL;
// Brightness Control
#define PWM_FREQ 5000
#define PWM_CHANNEL 0
#define PWM_RESOLUTION 8
#define PIN_DMD_nOE 22
void IRAM_ATTR triggerScan() {
dmd.scanDisplayBySPI();
}
void setupBrightnessPWM() {
ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
ledcAttachPin(PIN_DMD_nOE, PWM_CHANNEL);
}
void setBrightness(uint8_t brightness) {
ledcWrite(PWM_CHANNEL, brightness);
}
void setup() {
Serial.begin(115200);
// Setup timer
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &triggerScan, true);
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
// Init display
dmd.clearScreen(true);
// Setup brightness
setupBrightnessPWM();
setBrightness(200);
Serial.println("ESP32 P10 Project Ready!");
}
void loop() {
// Your code here
}
Selamat berkreasi dengan ESP32 dan P10 LED Matrix!
