Sesenta y cuatro LEDs RGB, cada uno con su propio color y su propio brillo, y un solo cable de datos para manejarlos a todos. Esa es la gracia de un panel WS2812B de 8×8: con un ESP32, un pin GPIO y la librería FastLED puedes convertir una grilla de 64 píxeles en un reloj, un indicador de temperatura, un ícono animado para tu escritorio o el cartel luminoso de tu taller.
Al terminar esta guía vas a saber tres cosas concretas: cómo encender un LED específico dándole coordenadas (x, y) en vez de un número de índice, cómo dibujar una figura completa y animarle el brillo, y cómo calcular cuánta corriente necesita tu panel antes de conectarlo a algo que no la aguante. Esto último es lo que separa un proyecto que funciona de un ESP32 que se reinicia solo.

El concepto: por qué basta un cable
Cada LED del panel es en realidad un WS2812B, un encapsulado 5050 que trae adentro tres chips (rojo, verde y azul) más un pequeño controlador. Ese controlador es la clave: los 64 LEDs están encadenados en serie y cada uno lee los primeros 24 bits que le llegan, se los queda como su color, y reenvía el resto al siguiente de la fila. Por eso no importa si tienes 8 o 256 píxeles: siempre es un solo pin de datos.
Ese protocolo es de un solo hilo y sensible al tiempo. los bits se distinguen por el ancho del pulso, del orden de los cientos de nanosegundos. No lo vas a implementar tú: FastLED se encarga de generar esos pulsos con el timing exacto usando el hardware RMT del ESP32.
Hay dos detalles del panel que conviene tener claros antes de escribir una línea de código:
- El orden de color es GRB, no RGB. La mayoría de los WS2812B espera primero verde, después rojo, después azul. Si declaras
RGBen vez deGRB, todo se ve con los colores cambiados (tu rojo sale verde). No es una falla del panel. - El cableado interno suele ser zigzag. La fila 0 va de izquierda a derecha, la fila 1 de derecha a izquierda, la fila 2 de nuevo de izquierda a derecha, y así. Si ignoras esto y calculas el índice como
y * 8 + x, las filas impares te van a salir espejadas. Más abajo vas a ver la función que lo corrige.

Mirando el panel por atrás vas a encontrar dos juegos de pines: los de entrada (marcados DIN, V+, V-) y los de salida (DO, V+, V-). Los de salida existen para encadenar más paneles, algo que retomamos en las variantes.
Lo que necesitas
| Componente | Cantidad | Para qué |
|---|---|---|
| Placa ESP32 DevKit WROOM-32 | 1 | Cerebro del proyecto |
| Matriz LED RGB 8x8 WS2812B (64 LEDs) | 1 | El display |
| Fuente 5V 2A con plug 5.5x2.1mm | 1 | Alimentar los LEDs |
| Adaptador jack DC hembra a terminales | 1 | Pasar del plug de la fuente a cables sueltos |
| Cables Dupont hembra hembra 20cm | 1 set | Conexiones |
| Cable USB Tipo C a USB Tipo A 1mt | 1 | Programar el ESP32 |
En software solo necesitas el Arduino IDE con el soporte de placas ESP32 ya instalado. Si todavía no lo tienes, instala primero el core de Espressif desde el Gestor de Tarjetas.
Presupuesto de corriente: el cálculo que casi todos se saltan
Este es el punto donde la mayoría de los proyectos con WS2812B falla, así que vale la pena hacerlo bien antes de conectar nada.
Un LED WS2812B a blanco pleno (los tres chips internos al máximo) consume aproximadamente 60 mA: unos 20 mA por color. Multiplica por 64 píxeles y te da 3,84 A en el peor caso absoluto. Ese peor caso solo ocurre si pintas la matriz completa de blanco al 100 % de brillo. algo que en la práctica casi nunca haces, y que además encandila.
Con FastLED.setBrightness(80), que es el valor de los ejemplos, estás limitando el brillo a un 31 % (80 de 255). El consumo cae en la misma proporción: cerca de 1,2 A con toda la matriz encendida en blanco, y bastante menos con colores y figuras parciales. Por eso una fuente de 5V 2A alcanza cómodamente para este tutorial.
Tres reglas prácticas que se derivan de esto:
- No alimentes los 64 LEDs desde el pin 5V del ESP32. El regulador de la placa y el puerto USB del computador no están hechos para entregar más de ~500 mA. Puedes hacerlo para probar con dos o tres píxeles a brillo bajo; con la matriz completa el ESP32 se va a reiniciar por caída de tensión (brownout).
- Si subes el brillo, recalcula. Con
BRIGHTNESS 255y animaciones blancas necesitas una fuente de 5A, no de 2A. - Si el consumo te preocupa, limítalo por software. FastLED tiene
FastLED.setMaxPowerInVoltsAndMilliamps(5, 2000);— puedes agregar esa línea en elsetup()y la librería baja el brillo automáticamente para no pasarse de 2 A.
Conexiones
El cableado es corto: un pin de datos y la alimentación.
| Panel 8×8 | Va conectado a |
|---|---|
DIN |
GPIO 2 del ESP32 (o cualquier otro GPIO de salida) |
V+ |
+5V de la fuente externa |
V- |
GND de la fuente externa y GND del ESP32 |

Hay un detalle que es fácil pasar por alto y que causa la mitad de los problemas: la tierra de la fuente externa y la tierra del ESP32 tienen que estar unidas. La señal de datos es una tensión medida contra GND; si el panel y la placa no comparten referencia, el panel recibe basura y verás parpadeos aleatorios o LEDs que se quedan pegados en un color.
Sobre el jack DC: la fuente de 5V termina en un plug macho de 5.5×2.1 mm, así que necesitas el adaptador jack DC hembra a terminales para sacar los dos cables (positivo al centro, negativo a la malla) que van a V+ y V-. Verifica la polaridad con un multímetro antes de energizar: los WS2812B no perdonan la inversión.
Dos mejoras opcionales que valen la pena si vas a dejar el montaje permanente:
- Una resistencia de 330 Ω a 470 Ω en serie con la línea de datos, lo más cerca posible del
DIN, amortigua los reflejos de la señal. - Un condensador electrolítico de 1000 µF / 6.3V o más entre
V+yV-absorbe el golpe de corriente del arranque y evita que el primer LED se dañe.
Ninguna de las dos es obligatoria para que el ejemplo funcione, pero son práctica estándar en instalaciones con LEDs direccionables.
Un punto sobre el nivel lógico: el ESP32 saca 3.3 V en sus GPIO y el WS2812B espera idealmente 0.7 × VCC, o sea unos 3.5 V. En la práctica la enorme mayoría de los paneles funciona sin problema con 3.3 V directo. Si el tuyo se porta errático con el cable de datos largo, un conversor de nivel a 5V resuelve el tema.
Instalar la librería FastLED
Hay varias librerías para WS2812B; FastLED es la más completa y la que usamos acá.
- Abre el Arduino IDE y ve al Gestor de Librerías (
Herramientas→Gestionar bibliotecas…). - Busca FastLED.
- Instala la versión de Daniel Garcia.

Ejemplo 1. Encender píxeles por coordenada (x, y)
Este primer sketch enciende tres LEDs en posiciones distintas, cada uno con su color y su brillo, y después apaga todo. Cárgalo tal cual a tu placa.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-64-ws2812b-8x8-matrix-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <FastLED.h>
#define DIN_PIN 2
#define MATRIX_WIDTH 8
#define MATRIX_HEIGHT 8
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
#define BRIGHTNESS 80 // Brightness (0-255)
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define ZIGZAG true // Set false if your panel is wired in straight rows instead of zigzag
#define DELAY_MS 500
CRGB leds[NUM_LEDS];
// Convert (x,y) coordinates to the corresponding index in the matrix
uint16_t coordToIndex(uint8_t x, uint8_t y) {
if (ZIGZAG && (y & 0x01)) {
x = (MATRIX_WIDTH - 1) - x;
}
return (y * MATRIX_WIDTH) + x;
}
// Set the color of a pixel at (x,y)
void setPixel(uint8_t x, uint8_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t brightness = 255) {
if (x >= MATRIX_WIDTH || y >= MATRIX_HEIGHT)
return;
CRGB color = CRGB(r, g, b);
color.nscale8(brightness);
leds[coordToIndex(x, y)] = color;
}
void setup() {
FastLED.addLeds<LED_TYPE, DIN_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
}
void loop() {
setPixel(0, 0, 255, 0, 0); // First LED x=0 and y=0 | Red - Full brightness
FastLED.show();
delay(DELAY_MS);
setPixel(3, 3, 0, 255, 0, 128); // LED x=3 and y=3 | Green - 50% brightness
FastLED.show();
delay(DELAY_MS);
setPixel(7, 7, 0, 0, 255, 200); // Last LED x=7 and y=7 | Blue - ~78% brightness
FastLED.show();
delay(DELAY_MS);
FastLED.clear(); // All LEDs off
FastLED.show();
delay(DELAY_MS);
}
Cómo funciona
Lo interesante acá no son los #define, sino las dos funciones auxiliares.
coordToIndex() traduce un par de coordenadas al índice real dentro de la cadena de LEDs. Si el panel está cableado en zigzag y la fila es impar (y & 0x01), invierte la coordenada horizontal antes de calcular la posición:
uint16_t coordToIndex(uint8_t x, uint8_t y) {
if (ZIGZAG && (y & 0x01)) {
x = (MATRIX_WIDTH - 1) - x;
}
return (y * MATRIX_WIDTH) + x;
}
Si tu panel resulta estar cableado en filas rectas en vez de zigzag, cambia ZIGZAG a false y listo. Es el primer parámetro que debes revisar si las figuras te salen deformadas.
setPixel() valida que las coordenadas estén dentro de la matriz, arma un color CRGB, lo escala con nscale8() según el brillo pedido y lo escribe en el arreglo global. Ojo con esto: escribir en el arreglo no enciende nada. Los LEDs físicos recién cambian cuando llamas a FastLED.show(), que es la función que dispara el envío de los 64 × 24 bits por el pin de datos.

En el loop() el sketch enciende el píxel (0,0) en rojo a brillo completo, el (3,3) en verde a la mitad y el (7,7) en azul a un 78 %, con medio segundo entre cada uno, y después apaga la matriz con FastLED.clear().

Ejemplo 2. Dibujar un corazón con efecto latido
El salto de "un píxel" a "una figura" es más corto de lo que parece: una figura no es más que una matriz de ceros y unos que recorres pintando los unos.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-64-ws2812b-8x8-matrix-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <FastLED.h>
#define DIN_PIN 2
#define MATRIX_WIDTH 8
#define MATRIX_HEIGHT 8
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
#define BRIGHTNESS 80 // Brightness (0-255)
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define ZIGZAG true // Set false if your panel is wired in straight rows instead of zigzag
#define FLIP_H false // Set true if the image displays mirrored left to right
#define FLIP_V false // Set true if the image displays upside down
CRGB leds[NUM_LEDS];
// Heart shape (8x8)
const bool heart[MATRIX_HEIGHT][MATRIX_WIDTH] = {
{0,0,0,0,0,0,0,0},
{0,1,1,0,0,1,1,0},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{0,1,1,1,1,1,1,0},
{0,0,1,1,1,1,0,0},
{0,0,0,1,1,0,0,0}
};
// Convert (x,y) coordinates to the corresponding index in the matrix
uint16_t coordToIndex(uint8_t x, uint8_t y) {
if (FLIP_H) x = (MATRIX_WIDTH - 1) - x;
if (FLIP_V) y = (MATRIX_HEIGHT - 1) - y;
if (ZIGZAG && (y & 0x01)) {
x = (MATRIX_WIDTH - 1) - x;
}
return (y * MATRIX_WIDTH) + x;
}
// Set the color of a pixel at (x,y)
void setPixel(uint8_t x, uint8_t y, CRGB color) {
if (x >= MATRIX_WIDTH || y >= MATRIX_HEIGHT)
return;
leds[coordToIndex(x, y)] = color;
}
// Draws the heart shape - scales its color by a brightness factor (0.0 - 1.0)
void drawShape(CRGB color, float scale) {
FastLED.clear();
CRGB c = color;
c.nscale8_video((uint8_t)(scale * 255));
for (uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
for (uint8_t x = 0; x < MATRIX_WIDTH; x++) {
if (heart[y][x]) setPixel(x, y, c);
}
}
}
// Pulses a heartrate LED pattern by changing the brightness over durationMs
// It creates a fade in and fade out effect
void pulse(CRGB color, float from, float to, uint16_t durationMs) {
const uint8_t steps = 24;
for (uint8_t i = 0; i <= steps; i++) {
float t = (float)i / steps;
float eased = (1 - cos(t * PI)) / 2.0;
float scale = from + (to - from) * eased;
drawShape(color, scale);
FastLED.show();
delay(durationMs / steps);
}
}
void setup() {
FastLED.addLeds<LED_TYPE, DIN_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
FastLED.show();
}
void loop() {
// Red color
CRGB color = CRGB(255, 0, 0);
// Heartbeat animation
pulse(color, 0.30, 1.00, 120);
pulse(color, 1.00, 0.55, 140);
pulse(color, 0.55, 0.85, 100);
pulse(color, 0.85, 0.30, 160);
drawShape(color, 0.30);
FastLED.show();
delay(300);
}
Cómo funciona
El arreglo heart[8][8] es literalmente el dibujo: cada 1 es un LED que se enciende. Puedes reemplazarlo por cualquier ícono de 8×8 que diseñes en papel cuadriculado. una carita, una flecha, una letra.
drawShape() limpia el buffer, escala el color con nscale8_video() (esta variante, a diferencia de nscale8(), nunca apaga del todo un LED encendido, lo que hace que los desvanecidos se vean más parejos) y recorre la grilla encendiendo donde el arreglo tiene un 1.
pulse() es lo que le da vida: hace la transición de brillo entre dos valores en 24 pasos, pero no de forma lineal. La línea float eased = (1 - cos(t * PI)) / 2.0; aplica una interpolación coseno, que arranca lento, acelera al medio y frena al final. Es la misma curva que usan las animaciones de interfaz para verse naturales; con un fade lineal el latido parece un parpadeo mecánico.
Los cuatro llamados a pulse() en el loop() reproducen la forma real de un latido: una subida fuerte, una bajada parcial, un segundo repunte más suave y el descenso final.
Este par de sketches también aparecen con FLIP_H y FLIP_V. Si tu corazón sale invertido o de cabeza. porque montaste el panel rotado. , cambia esas constantes a true en vez de reescribir el arreglo.

Ejemplo 3. Arcoíris en movimiento
El último ejemplo enciende un LED por cuadro hasta llenar la matriz, y va corriendo el tono de cada píxel según hace cuánto se encendió.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-64-ws2812b-8x8-matrix-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <FastLED.h>
#define DIN_PIN 2
#define MATRIX_WIDTH 8
#define MATRIX_HEIGHT 8
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
#define BRIGHTNESS 80 // Brightness (0-255)
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define ZIGZAG true // Set false if your panel is wired in straight rows instead of zigzag
// Rainbow animation
#define BASE_HUE 160 // Initial blue hue for new LED (0-255)
#define HUE_STEP_PER_TICK 3 // Amount the LED hue shifts per frame
#define DELAY_MS 80 // Animation speed
uint16_t ledsLit = 0; // Number of LEDs currently turned on
uint16_t frame = 0; // Counts animation frames
CRGB leds[NUM_LEDS];
// Convert (x,y) coordinates to the corresponding index in the matrix
uint16_t coordToIndex(uint8_t x, uint8_t y) {
if (ZIGZAG && (y & 0x01)) {
x = (MATRIX_WIDTH - 1) - x;
}
return (y * MATRIX_WIDTH) + x;
}
// Set the color of a pixel at (x,y)
void setPixel(uint8_t x, uint8_t y, CRGB color, uint8_t brightness = 255) {
if (x >= MATRIX_WIDTH || y >= MATRIX_HEIGHT)
return;
color.nscale8(brightness);
leds[coordToIndex(x, y)] = color;
}
void setup() {
FastLED.addLeds<LED_TYPE, DIN_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
FastLED.show();
}
void loop() {
// Turns on 1 LED per frame until fully lit
if (ledsLit < NUM_LEDS) {
ledsLit++;
}
// Update colors of all currently lit LEDs
for (uint16_t i = 0; i < ledsLit; i++) {
uint8_t x = i % MATRIX_WIDTH;
uint8_t y = i / MATRIX_WIDTH;
// Calculate hue based on how long this LED has been lit
// Newer LEDs start at BASE_HUE, older ones shift further along the color wheel
uint16_t age = frame - i;
uint8_t hue = BASE_HUE + (uint8_t)(age * HUE_STEP_PER_TICK);
setPixel(x, y, CHSV(hue, 255, 255));
}
FastLED.show();
delay(DELAY_MS);
frame++;
}
Cómo funciona
La clave está en usar HSV en vez de RGB. CHSV(hue, 255, 255) describe un color por su tono (0-255 dando la vuelta completa al círculo cromático), su saturación y su valor. Recorrer un arcoíris con HSV es sumarle 1 al tono; hacer lo mismo en RGB implicaría interpolar tres canales a mano.
El truco del efecto es la variable age: cada LED calcula hace cuántos cuadros está encendido (frame - i) y desplaza su tono en proporción a esa antigüedad. Los recién encendidos quedan cerca del azul (BASE_HUE 160) y los más viejos ya avanzaron por todo el espectro, lo que produce el degradé que se mueve.
Fíjate también en que hue es un uint8_t: cuando pasa de 255 vuelve a 0 por desborde natural, y el arcoíris se cierra solo sin necesidad de un módulo.

Cuando algo no funciona
Los cuatro síntomas típicos y su causa real:
- Los colores están cambiados (el rojo sale verde): tu panel usa un orden distinto al declarado. Cambia
COLOR_ORDERdeGRBaRGBy vuelve a cargar. - Las filas impares salen espejadas: el panel no es zigzag. Pon
ZIGZAGenfalse. - El ESP32 se reinicia en loop apenas enciendes muchos LEDs: caída de tensión. Estás alimentando desde USB o la fuente no da la corriente necesaria. Revisa el presupuesto de corriente de más arriba.
- Parpadeos aleatorios o el primer LED queda pegado: falta la tierra común entre la fuente y el ESP32, o el cable de datos es muy largo. Une los GND y agrega la resistencia de 330 Ω en serie con
DIN.
Un consejo de depuración: parte siempre con un solo píxel encendido en rojo. Si ese píxel se ve bien, el cableado y la librería están correctos, y todo lo demás es lógica de tu código.
Variantes y mejoras
Con la base funcionando, tres direcciones concretas para llevarlo más lejos:
- Reloj de escritorio con texto en scroll vía MQTT. El ESP32 ya tiene WiFi: sincroniza la hora por NTP y dibuja dígitos de 3×5 píxeles en la matriz. Si además le agregas un cliente MQTT y lo suscribes a un tópico de tu Home Assistant, puedes mandarle mensajes desde tu casa inteligente. "lavadora lista", la temperatura exterior o un aviso de que llegó una visita. y hacerlos pasar en scroll. La librería
PubSubClientmásFastLEDbastan; el texto en scroll se resuelve dibujando la fuente con un desplazamiento horizontal que aumenta en cada cuadro. - Encadenar varios paneles. El pin
DOdel panel va alDINdel siguiente. Con cuatro paneles armas un display de 32×8 (suficiente para palabras completas): solo cambiaMATRIX_WIDTHa 32 y ajustacoordToIndex()para saltar entre paneles. Recuerda recalcular la corriente: cuatro paneles son 256 LEDs. - Que reaccione al sonido. Con un módulo de micrófono conectado a una entrada ADC del ESP32 puedes mapear el nivel de audio a la altura de las columnas y tener un vúmetro de 8 barras. Un paso más allá es correr una FFT simple para separar graves y agudos en columnas distintas.
Personalización para Chile
En MechatronicStore encuentras todo lo necesario con stock local:
- Matriz LED RGB 8x8 WS2812 64 bits (SKU GN3-12). $17.800 CLP
- ESP32 con WiFi y Bluetooth ESP WROOM-32, entrada Tipo C (SKU X2-10V2). $7.990 CLP
- Transformador cargador fuente de alimentación 5V 2A (SKU B-001). $3.490 CLP
- Adaptador jack DC hembra (SKU GD1-10). $790 CLP
- Cables hembra hembra 40 piezas 20cm (SKU C-413). $3.190 CLP
- Cable USB Tipo C a USB Tipo A 1mt (SKU B-101). $2.190 CLP
Total aproximado del proyecto: $35.450 CLP.
Un par de equivalencias respecto al tutorial original: donde el original habla de un "5V 2A power adapter" genérico, el transformador B-001 cumple exactamente la misma función y ya viene con plug de 5.5×2.1 mm, que es el que calza con el adaptador a terminales. Y donde dice "ESP32 board, any model of your choice", el ESP WROOM-32 de entrada Tipo C es el modelo más común del catálogo y el que usa el pinout de los diagramas; por eso el cable que necesitas es USB C a USB A y no micro USB.
Si prefieres empezar más barato para probar el código, la Matriz LED RGB 4×4 WS2812 (SKU GO1-11, $5.790 CLP) usa el mismo protocolo y la misma librería: basta con cambiar MATRIX_WIDTH y MATRIX_HEIGHT a 4.
Recursos
- Tutorial original (inglés): ESP32: 64 WS2812B RGB LED 8×8 Matrix (Arduino IDE). Random Nerd Tutorials
- Librería FastLED (GitHub): FastLED/FastLED
- Documentación y ejemplos de FastLED: Wiki oficial
Versión chilena inspirada en el tutorial de Rui Santos y Sara Santos, con componentes en stock local en MechatronicStore.










