Lopaka Basics 03: a todo color

La misma idea que en los dos primeros episodios, ahora a todo color: un tablero para el salón en una pantalla en color, creado en pocos minutos.
En este episodio descubrirás cómo una pantalla en color crea sus colores, qué significa RGB565 y por qué una sola imagen a pantalla completa no cabe en un Arduino UNO. Después crearás el tablero en Lopaka con tarjetas redondeadas, texto en color, íconos tintados y una imagen pequeña en color, y lo ejecutarás en un ESP32.
Lo que vas a crear: un tablero en color de 320×240 con un título y la hora, tres tarjetas redondeadas para temperatura, humedad y calidad del aire, y una línea sobre el clima exterior. Lo que necesitas: un navegador y el simulador en línea del episodio 1. Una placa real es opcional.
Cómo funciona una pantalla en color
Un píxel son tres luces diminutas
En el OLED de los dos episodios anteriores, un píxel está encendido o apagado. En una pantalla en color, cada píxel está formado por tres luces diminutas: roja, verde y azul. Cada una puede brillar con cualquier intensidad y, desde una distancia normal de visión, tu ojo las mezcla en un color.
Mézclalas y obtienes cualquier color. Rojo y verde juntos hacen amarillo. Las tres a máxima potencia hacen blanco. Las tres apagadas es negro.
![]()
RGB565: un color en dos bytes
Tu computadora guarda un color en 24 bits: 8 para rojo, 8 para verde y 8 para azul, unos 16,7 millones de colores. Ese es el color que escribes como #FF8200 en una página web o en Lopaka: dos dígitos hexadecimales por luz.
Los chips pequeños y sus pantallas suelen usar 16 bits, en un formato llamado RGB565:
- 5 bits para rojo,
- 6 bits para verde,
- 5 bits para azul.
El verde recibe el bit extra porque nuestros ojos son más sensibles a él. Eso hace 65.536 colores y cada píxel ocupa exactamente dos bytes.

Por qué una imagen no cabe en un UNO
Ahora las cuentas. Una pantalla de 320×240 tiene 320 × 240 = 76.800 píxeles. A dos bytes cada uno, una imagen a pantalla completa ocupa 153.600 bytes, unos 150 KB.
Un Arduino UNO tiene 32 KB de flash para todo el programa. Una imagen a pantalla completa es casi cinco veces eso. Así que en pantallas en color dibujas con formas y texto y mantienes las imágenes pequeñas.

Paso 1: un proyecto en color nuevo
Haz clic en + New Project y abre la lista Platform. Para este episodio elige AdafruitGFX Color: Adafruit GFX es una de las bibliotecas de gráficos más populares para pantallas en color. Lopaka la describe como «the shared drawing layer under most Adafruit display drivers»: la combinas con el controlador para tu panel exacto, como Adafruit_ILI9341, los colores se compactan como RGB565 y el dibujo va directo al panel.
Después completa el resto del diálogo:
- Title: «Color Weather».
- Screen Size: 320×240.
- Background Color:
#0F1B2D, un azul oscuro.
Haz clic en Save.

Lopaka convierte cada color a RGB565
El panel de código ya tiene una línea:
tft.fillScreen(0x8C5);fillScreen pinta toda la pantalla de un color y 0x8C5 es el azul oscuro en RGB565. Lopaka hace la conversión por cada color que eliges. A mano funciona así: conserva los 5 bits superiores del rojo, los 6 bits superiores del verde y los 5 bits superiores del azul, y escríbelos uno tras otro.
| Hex | Top bits | |
|---|---|---|
| red | 0x0F | 00001 |
| green | 0x1B | 000110 |
| blue | 0x2D | 00101 |
Juntos eso es 0000100011000101, o 0x08C5. Lopaka lo escribe sin el cero inicial.
Paso 2: tres tarjetas redondeadas
Elige la herramienta rectangle y arrastra una tarjeta en el lienzo. En el inspector, pon R en 12 para redondear las esquinas, activa Filled y escribe #FF8200 en Fill color para naranja. Aparece una línea en el código:
tft.fillRoundRect(10, 56, 96, 140, 12, 0xFC00);Los números son x, y, width, height, corner radius y colour. Una forma es una línea de código, por grande que sea: esta tarjeta abarca 96 × 140 píxeles y la línea que la dibuja ocupa unos pocos bytes de flash.
Repítelo para las otras dos tarjetas: azul #2D7FF9 y verde #22B573. Las tres tienen 96 píxeles de ancho y 140 de alto, en y 56, y empiezan en x 10, 112 y 214. Eso deja un margen de 10 píxeles a ambos lados de la pantalla y 6 píxeles entre las tarjetas: 10 + 3 × 96 + 2 × 6 + 10 = 320.

Paso 3: texto en color
El texto funciona como en los dos primeros episodios y ahora puede tomar cualquier color. Elige la herramienta text (Aa): aparece una capa de texto nueva en el lienzo. Escribe el texto en el inspector, elige una fuente y pon Fill color. Un texto nuevo empieza con el color que usaste por última vez, así que comprueba el color cada vez.
El título y la hora
Living roomen FreeSansBold12pt7b, blanco#FFFFFF, en la esquina superior izquierda.07:45en FreeSans12pt7b, gris azulado claro#9FB3C8, en la esquina superior derecha.
tft.setTextColor(0xFFFF);
tft.setTextWrap(false);
tft.setFont(&FreeSansBold12pt7b);
tft.setCursor(12, 35);
tft.print("Living room");setTextColor pone el color para cada texto posterior, así que Lopaka solo lo escribe otra vez cuando el color cambia. setTextWrap(false) mantiene un texto largo en una línea en lugar de partirlo en el borde de la pantalla.
Con fuentes FreeSans, la y de setCursor es la línea base: la última fila de píxeles de las letras. En el inspector el título tiene Y 36, la línea bajo esa fila (las reglas cuentan las líneas entre píxeles, como en el episodio 1), así que el código dice 35.
Una etiqueta pequeña y un número grande en cada tarjeta
Cada tarjeta recibe una etiqueta pequeña en la fuente clásica y un número grande en una FreeSans en negrita:
- Las etiquetas
TEMP,HUMIDyAIRusan Adafruit 5x7, la fuente clásica integrada en la biblioteca, con Size en2. - Los números
23C,48%yOKusan FreeSansBold18pt7b.
Los seis textos son blancos. Coloca cada etiqueta cerca de la parte superior de su tarjeta y cada número cerca de la inferior.

La fuente clásica puede ampliarse dos o tres veces: Size 2 convierte cada píxel de una letra en un bloque de 2×2. El código para la etiqueta y el número:
tft.setTextSize(2);
tft.setFont();
tft.setCursor(20, 72);
tft.print("TEMP");
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(20, 179);
tft.print("23C");setFont() sin nada entre paréntesis vuelve a la fuente clásica. La fuente clásica cuenta la y de forma distinta: setCursor toma la esquina superior izquierda del texto, no la línea base. Las letras de la etiqueta tienen 7 píxeles de alto, 14 con tamaño 2, así que el 86 del inspector se convierte en 86 − 14 = 72 en el código. Lopaka hace esta conversión por ti. Antes del número FreeSans restablece el tamaño a 1, para que la fuente grande no se duplique.
El texto dice 23C, no 23°C: las fuentes FreeSans contienen solo los caracteres ASCII básicos y el símbolo de grado no es uno de ellos.
Las fuentes cuestan flash solo cuando las usas
FreeSans y las demás fuentes de la lista vienen con la biblioteca Adafruit GFX. Cada fuente es un archivo aparte y ocupa flash solo cuando tu pantalla la usa. Lopaka añade un #include por cada fuente que usa el diseño, aquí tres:
#include "FreeSans12pt7b.h"
#include "FreeSansBold12pt7b.h"
#include "FreeSansBold18pt7b.h"Paso 4: íconos tintados
Abre la pestaña Images, busca un ícono y haz clic en él para añadirlo a la pantalla. Añade tres:
- un termómetro (busca «thermo»),
- una gota (busca «drop»),
- una hoja (busca «leaf»).
Vuelve a Layers y pon cada ícono bajo la etiqueta de su tarjeta.
Los íconos de la biblioteca son de un color, así que puedes tintarlos para que coincidan con tu diseño. Selecciona cada ícono y pon su Fill color en el azul oscuro del fondo, #0F1B2D. En las tarjetas brillantes los íconos ahora parecen recortados.
![]()
En el código, un ícono de un color se convierte en drawBitmap:
tft.drawBitmap(20, 104, image_streamline_weather_temperature_thermometer__weather_png_bits, 21, 21, 0x8C5);Los argumentos son la posición, el array de bits, el ancho y el alto, y el color. El array guarda un bit por píxel, como en el OLED del episodio 2: el termómetro mide 21×21 píxeles, 3 bytes por fila, 63 bytes en total. El color es un número aparte en el código, así que el mismo ícono puede dibujarse en cualquier color sin una segunda copia.
Paso 5: una imagen en color
Súbela como RGB
Las imágenes también pueden ser a todo color. En la pestaña Images, haz clic en Upload y elige una imagen, igual que en el episodio 2. Esta vez, cambia el convertidor de Monochrome a RGB.

El contador de arriba muestra el coste. Con su tamaño completo de 240×240 píxeles, esta imagen ocuparía 240 × 240 × 2 = 115.200 bytes, más de tres veces toda la flash de un UNO.
Redúcela a 40×40
Pon Dimensions en W 40 y H 40. Ahora la imagen ocupa 40 × 40 × 2 = 3.200 bytes, unos tres kilobytes. Ese es el punto justo para imágenes en color: detalles pequeños y coloridos. Haz clic en Import.
En el código, la imagen se convierte en un array de 1.600 números RGB565, uno por píxel, y una línea que la dibuja:
tft.drawRGBBitmap(12, 197, image_sun_cloud_pixels, 40, 40);A diferencia de drawBitmap, esta llamada no toma color: cada píxel trae el suyo.
La línea inferior
Suelta la imagen en la esquina inferior izquierda y añade una línea de texto más junto a ella: Outside: 18C, sunny en Adafruit 5x7, Size 2, en el mismo gris azulado #9FB3C8 que la hora.
Paso 6: consigue el código
Una tarjeta, tres dialectos
Cada biblioteca habla su propio dialecto. La misma tarjeta redondeada es drawRBox en U8g2, fillRoundRect en Adafruit GFX y un objeto con estilo en LVGL. Lopaka escribe el de la plataforma que elegiste.

Copia y descarga los archivos de fuente
Haz clic en Copy sobre el código. Bajo los interruptores junto al código, Lopaka enumera las Fonts y las Images que usa el diseño. Haz clic en cada uno de los tres archivos de fuente para descargarlo y pon los archivos junto a tu sketch. La imagen y los íconos ya están dentro del código copiado como arrays, así que no necesitas los archivos de imagen.

Si olvidas los archivos de fuente, el compilador se detiene con fatal error: FreeSans12pt7b.h: No such file or directory.
Lopaka genera este código para el tablero. El array de la imagen tiene 1.600 números, así que aquí está acortado; Copy te da todo.
// [BEGIN lopaka generated]
#include "FreeSans12pt7b.h"
#include "FreeSansBold12pt7b.h"
#include "FreeSansBold18pt7b.h"
static const unsigned char PROGMEM image_drop_bits[] = {0x10,0x38,0x7c,0x7c,0xfe,0xde,0xde,0xde,0x7c,0x38};
static const unsigned char PROGMEM image_streamline_ecology_leaf_bug__ecology_png_bits[] = {0x00,0x00,0x30,0x00,0x00,0x48,0x00,0x00,0x88,0x00,0x3f,0x08,0x03,0xe0,0x08,0x0c,0x00,0x08,0x10,0xe0,0x08,0x21,0x70,0x88,0x41,0xd1,0x08,0x40,0xe2,0x08,0x80,0x0c,0x08,0x80,0x30,0x10,0x80,0xc0,0x10,0x83,0x00,0x20,0x84,0x00,0x20,0x88,0x00,0x40,0x50,0x00,0x80,0x20,0x03,0x00,0x50,0x0c,0x00,0x8f,0xf0,0x00,0x80,0x00,0x00};
static const unsigned char PROGMEM image_streamline_weather_temperature_thermometer__weather_png_bits[] = {0x03,0x00,0x00,0x04,0x80,0x00,0x04,0x80,0x00,0x04,0x87,0x80,0x04,0x80,0x00,0x04,0x80,0x00,0x04,0x80,0x00,0x04,0x87,0x80,0x04,0x80,0x00,0x04,0x80,0x00,0x07,0x80,0x00,0x07,0x87,0x80,0x07,0x80,0x00,0x07,0x80,0x00,0x0f,0xc0,0x00,0x1f,0x60,0x00,0x1f,0xa0,0x00,0x1f,0xa0,0x00,0x1f,0xe0,0x00,0x0f,0xc0,0x00,0x07,0x80,0x00};
static const uint16_t PROGMEM image_sun_cloud_pixels[] = {/* 1,600 RGB565 values, shortened here */};
void drawScreen_1(void) {
tft.fillScreen(0x8C5);
// rect 1
tft.fillRoundRect(10, 56, 96, 140, 12, 0xFC00);
// rect 2
tft.fillRoundRect(112, 56, 96, 140, 12, 0x2BFF);
// rect 3
tft.fillRoundRect(214, 56, 96, 140, 12, 0x25AE);
// string 4
tft.setTextColor(0xFFFF);
tft.setTextWrap(false);
tft.setFont(&FreeSansBold12pt7b);
tft.setCursor(12, 35);
tft.print("Living room");
// string 5
tft.setTextColor(0x9D99);
tft.setFont(&FreeSans12pt7b);
tft.setCursor(246, 35);
tft.print("07:45");
// string 6
tft.setTextColor(0xFFFF);
tft.setTextSize(2);
tft.setFont();
tft.setCursor(20, 72);
tft.print("TEMP");
// string 7
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(20, 179);
tft.print("23C");
// string 8
tft.setTextSize(2);
tft.setFont();
tft.setCursor(122, 72);
tft.print("HUMID");
// string 9
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(122, 179);
tft.print("48%");
// string 10
tft.setTextSize(2);
tft.setFont();
tft.setCursor(224, 72);
tft.print("AIR");
// string 11
tft.setTextSize(1);
tft.setFont(&FreeSansBold18pt7b);
tft.setCursor(224, 179);
tft.print("OK");
// streamline-weather-temperature-thermometer--weather.png
tft.drawBitmap(20, 104, image_streamline_weather_temperature_thermometer__weather_png_bits, 21, 21, 0x8C5);
// drop
tft.drawBitmap(122, 104, image_drop_bits, 7, 10, 0x8C5);
// streamline-ecology-leaf-bug--ecology.png
tft.drawBitmap(224, 104, image_streamline_ecology_leaf_bug__ecology_png_bits, 21, 21, 0x8C5);
// sun_cloud
tft.drawRGBBitmap(12, 197, image_sun_cloud_pixels, 40, 40);
// string 16
tft.setTextColor(0x9D99);
tft.setTextSize(2);
tft.setFont();
tft.setCursor(62, 211);
tft.print("Outside: 18C, sunny");
}
// [END lopaka generated]Paso 7: ejecútalo en un ESP32
El sketch
Esta vez ejecutamos la pantalla en un ESP32, una placa más rápida, popular para pantallas en color; una placa ESP32 típica tiene 4 MB de flash. La pantalla es un módulo ILI9341 de 320×240 por SPI.
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// ILI9341 320x240 color display on SPI
#define TFT_CS 15
#define TFT_DC 2
#define TFT_RST 4
Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);
// Paste the Lopaka code here
void setup() {
tft.begin();
tft.setRotation(1); // landscape, 320x240
drawScreen_1();
}
void loop() {
}Adafruit_ILI9341 tft(...)crea el objeto de pantalla y le dice qué pines usa para selección de chip, datos/comando y reinicio. El código de Lopaka lo llamatft, así que mantén ese nombre.- El ILI9341 es un panel vertical, 240 de ancho y 320 de alto.
setRotation(1)lo gira a horizontal, 320×240, el tamaño que diseñamos. drawScreen_1()se ejecuta una vez, ensetup(). La pantalla mantiene su imagen hasta que algo dibuja encima, así queloop()queda vacío por ahora.
Cableado en el simulador
En el simulador del episodio 1, empieza un proyecto ESP32 nuevo y añade una pantalla ILI9341. Conéctala:
- VCC y LED (la retroiluminación) a 3V3, GND a GND,
- CS a 15, D/C a 2, RST a 4,
- MOSI a 23, SCK a 18, MISO a 19.
Añade las bibliotecas Adafruit ILI9341 y Adafruit GFX Library, pega el sketch con el código de Lopaka en su sitio, añade los tres archivos de fuente al proyecto y pulsa Play. El tablero aparece en la pantalla simulada.

Sin búfer de fotogramas
¿Recuerdas el búfer de fotogramas del episodio 1, la imagen completa guardada en RAM antes de ir a la pantalla? A 320×240 en color necesitaría los mismos 150 KB que una imagen a pantalla completa. Las bibliotecas en color como Adafruit GFX lo saltan y dibujan directo a la pantalla: cada fillRoundRect y print envía sus píxeles por SPI al instante.
Eso mantiene el uso de RAM mínimo. Compilado para el ESP32, el sketch usa el 23% del espacio de programa y el 7% de la RAM. El mismo sketch compilado para un Arduino UNO:
Sketch uses 25946 bytes (80%) of program storage space. Maximum is 32256 bytes.
Global variables use 317 bytes (15%) of dynamic memory, leaving 1731 bytes for local variables. Maximum is 2048 bytes.Solo el 15% de la RAM del UNO. La flash es la parte ajustada: 80%, y las tres fuentes y la imagen de 3.200 bytes son una parte grande de ello.
En una placa real
- Voltaje de señal. El ESP32 trabaja a 3,3 V, como el ILI9341. Muchos módulos ILI9341 económicos no tienen adaptador de nivel, así que en una placa de 5 V como el UNO comprueba el anuncio de tu módulo antes de cablearlo.
- El controlador. Algunos módulos de 320×240 usan en su lugar el controlador ST7789. Para esos, incluye
Adafruit_ST7789.h, crea la pantalla comoAdafruit_ST7789 tft(TFT_CS, TFT_DC, TFT_RST);y arráncala contft.init(240, 320);en lugar detft.begin();. El código de Lopaka se mantiene igual.
Paso 8: ideas de la galería
¿Necesitas ideas? La Projects Gallery tiene miles de proyectos públicos. Abre uno, pulsa Fork y Lopaka lo copia en tus proyectos, listo para cambiar.
Resumen
- Tres luces hacen cada color: cada píxel mezcla rojo, verde y azul.
- RGB565 los compacta en dos bytes: 5 bits de rojo, 6 de verde, 5 de azul, y Lopaka convierte cada color por ti.
- Las formas ganan a las imágenes grandes: una tarjeta es una línea de código, una imagen a pantalla completa son 150 KB, así que mantén las imágenes pequeñas.
Próximo episodio: Live Data. Hacemos que estos números cambien solos. Lee el episodio 4 o míralo en YouTube.
¿Listo para probar? Abre Lopaka y crea tu propio tablero en color.