Primeros Pasos con el Kit DIY TRMNL 7.5" (OG) en Arduino
Introducción
El Kit DIY TRMNL 7.5" (OG) es una plataforma de desarrollo versátil que cuenta con el potente XIAO ESP32-S3 Plus como su cerebro. Este Kit DIY combina el poder de procesamiento del ESP32-S3 con una hermosa pantalla ePaper de 7.5 pulgadas, creando la base perfecta para proyectos de visualización de información de bajo consumo. Esta guía se enfoca en programar el Kit DIY TRMNL usando el framework de Arduino, proporcionándote el conocimiento esencial para utilizar sus diversas características de hardware.
Primeros Pasos
Antes de profundizar en las características específicas, configuremos nuestro entorno de desarrollo para el Kit DIY TRMNL 7.5" (OG).
Preparación del Entorno
Para programar el Kit DIY TRMNL con Arduino, necesitarás configurar el IDE de Arduino con soporte para ESP32.
Si esta es tu primera vez usando Arduino, te recomendamos encarecidamente que consultes Primeros Pasos con Arduino.
Paso 1. Descarga e instala el IDE de Arduino e inicia la aplicación Arduino.

Paso 2. Añade soporte para placas ESP32 al IDE de Arduino.
En el IDE de Arduino, ve a Archivo > Preferencias y añade la siguiente URL al campo "URLs adicionales del Gestor de Tarjetas":
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Paso 3. Instalar el paquete de placa ESP32.
Navega a Herramientas > Placa > Gestor de Placas, busca "esp32" e instala el paquete ESP32 de Espressif Systems.
Paso 4. Seleccionar la placa correcta.
Ve a Herramientas > Placa > ESP32 Arduino y selecciona "XIAO_ESP32S3_PLUS".
Paso 5. Conecta tu Kit DIY TRMNL a tu computadora usando un cable USB-C.
Paso 6. Selecciona el puerto correcto desde Herramientas > Puerto.
Ejemplos de Arduino
Ahora exploremos las características principales del Kit DIY TRMNL con ejemplos de código de Arduino.
Botones de Usuario
El Kit DIY TRMNL cuenta con tres botones programables por el usuario (D1, D2, D4) y un botón de reinicio. Creemos un ejemplo simple para detectar pulsaciones de botones.
Ejemplo de Prueba de Botones
Este ejemplo leerá el estado de los tres botones de usuario e imprimirá su estado en el Monitor Serie.
// TRMNL DIY Kit - Button Test Example
// Define button pins
const int BUTTON_D1 = D1; // First user button
const int BUTTON_D2 = D2; // Second user button
const int BUTTON_D4 = D4; // Third user button
void setup() {
// Initialize serial communication
Serial.begin(115200);
while (!Serial) {
; // Wait for serial port to connect
}
Serial.println("TRMNL DIY Kit - Button Test");
// Configure button pins as inputs with internal pull-up resistors
pinMode(BUTTON_D1, INPUT_PULLUP);
pinMode(BUTTON_D2, INPUT_PULLUP);
pinMode(BUTTON_D4, INPUT_PULLUP);
}
void loop() {
// Read button states (buttons are LOW when pressed because of pull-up resistors)
bool d1Pressed = !digitalRead(BUTTON_D1);
bool d2Pressed = !digitalRead(BUTTON_D2);
bool d4Pressed = !digitalRead(BUTTON_D4);
// Print button states if any button is pressed
if (d1Pressed || d2Pressed || d4Pressed) {
Serial.print("Button D1: ");
Serial.print(d1Pressed ? "PRESSED" : "released");
Serial.print(" | Button D2: ");
Serial.print(d2Pressed ? "PRESSED" : "released");
Serial.print(" | Button D4: ");
Serial.println(d4Pressed ? "PRESSED" : "released");
// Add a small delay to avoid repeated readings
delay(200);
}
}
Cómo Funciona el Código:
-
Definimos constantes de pin para los tres botones de usuario (D1, D2, D4).
-
En la función
setup()
, inicializamos la comunicación serie y configuramos los pines de los botones como entradas con resistencias pull-up internas. -
En la función
loop()
, leemos el estado de cada botón. Dado que estamos usando resistencias pull-up, los pines leen LOW cuando se presionan los botones. -
Invertimos las lecturas (con el operador
!
) para quetrue
signifique "presionado" yfalse
signifique "liberado". -
Si se presiona cualquier botón, imprimimos el estado de todos los botones en el Monitor Serie.
-
Un pequeño retraso previene lecturas repetidas rápidas cuando se mantiene presionado un botón.

Monitoreo de Voltaje de Batería
El Kit DIY TRMNL 7.5" (OG) incluye un circuito para monitorear el voltaje de la batería conectado al pin D0 (GPIO1). Una característica importante de este diseño es que también incluye un pin de control (GPIO6) para habilitar/deshabilitar la alimentación del ADC, lo que ayuda a conservar la batería cuando no se está midiendo activamente.
Ejemplo de Monitoreo de Voltaje de Batería
// TRMNL DIY Kit - Battery Voltage Monitoring Example
#define BATTERY_PIN 1 // GPIO1 (A0) - BAT_ADC
#define ADC_EN_PIN 6 // GPIO6 (A5) - ADC_EN
const float CALIBRATION_FACTOR = 0.968;
void setup() {
// Initialize serial communication
Serial.begin(115200);
while (!Serial) {
; // Wait for serial port to connect
}
Serial.println("TRMNL DIY Kit - Battery Voltage Monitoring Example");
// Configure ADC_EN
pinMode(ADC_EN_PIN, OUTPUT);
digitalWrite(ADC_EN_PIN, LOW); // Start with ADC disabled to save power
// Configure ADC
analogReadResolution(12);
analogSetPinAttenuation(BATTERY_PIN, ADC_11db);
}
void loop() {
// Read battery voltage
float voltage = readBatteryVoltage();
// Print the results
Serial.print("Battery Voltage: ");
Serial.print(voltage, 2); // Print with 2 decimal places
Serial.println("V");
// Determine battery level
String batteryStatus;
if (voltage >= 4.0) {
batteryStatus = "Full";
} else if (voltage >= 3.7) {
batteryStatus = "Good";
} else if (voltage >= 3.5) {
batteryStatus = "Medium";
} else if (voltage >= 3.2) {
batteryStatus = "Low";
} else {
batteryStatus = "Critical";
}
Serial.print("Battery Status: ");
Serial.println(batteryStatus);
Serial.println();
// Wait for a while before the next reading
delay(5000); // 5 seconds
}
float readBatteryVoltage() {
// Enable ADC
digitalWrite(ADC_EN_PIN, HIGH);
delay(10); // Short delay to stabilize
// Read 30 times and average for more stable readings
long sum = 0;
for(int i = 0; i < 30; i++) {
sum += analogRead(BATTERY_PIN);
delayMicroseconds(100);
}
// Disable ADC to save power
digitalWrite(ADC_EN_PIN, LOW);
// Calculate voltage
float adc_avg = sum / 30.0;
float voltage = (adc_avg / 4095.0) * 3.6 * 2.0 * CALIBRATION_FACTOR;
return voltage;
}
Cómo Funciona el Código:
- Definimos dos pines importantes:
-
BATTERY_PIN
(GPIO1/A0): Conectado al divisor de voltaje de la batería -
ADC_EN_PIN
(GPIO6/A5): Controla la alimentación del circuito de medición ADC
-
Definimos un
CALIBRATION_FACTOR
(0.968) para ajustar finamente la precisión de la lectura de voltaje. -
En la función
setup()
:
-
Inicializamos la comunicación serie
-
Configuramos el pin ADC_EN como salida y lo establecemos en LOW (deshabilitado) para ahorrar energía
-
Establecemos la resolución del ADC a 12 bits (0-4095)
-
Configuramos la atenuación adecuada para el pin de la batería
- En la función
loop()
:
-
Llamamos a
readBatteryVoltage()
para obtener el voltaje actual de la batería -
Imprimimos el voltaje en el Monitor Serie
-
Determinamos y mostramos el estado de la batería basado en umbrales de voltaje
-
Esperamos 5 segundos antes de tomar la siguiente lectura
- La función
readBatteryVoltage()
:
-
Habilita el circuito ADC estableciendo ADC_EN_PIN en HIGH
-
Espera brevemente para que el circuito se estabilice
-
Toma 30 lecturas y las promedia para obtener resultados más estables
-
Deshabilita el circuito ADC para ahorrar energía
-
Calcula el voltaje real de la batería usando:
- La lectura ADC promedio
- La resolución del ADC (4095)
- Voltaje de referencia (3.6V)
- Factor del divisor de voltaje (2.0)
- Factor de calibración (0.968)

Diseño de Ahorro de Energía:
Una característica clave de esta implementación es la capacidad de deshabilitar el circuito de medición de batería cuando no está en uso. El Kit DIY TRMNL está diseñado para bajo consumo de energía, y este enfoque ayuda a extender la vida de la batería alimentando el circuito divisor de voltaje solo cuando se necesita una medición real.
El factor de calibración (0.968) compensa las tolerancias de los componentes en el divisor de voltaje y ayuda a asegurar lecturas precisas. Este valor puede necesitar un ligero ajuste para tu placa específica si encuentras que las lecturas están consistentemente desviadas comparadas con una medición de multímetro.
Tomar múltiples lecturas y promediarlas ayuda a reducir el ruido y proporciona mediciones de voltaje más estables, lo cual es especialmente importante para el monitoreo de batería donde pequeños cambios de voltaje pueden ser significativos para determinar la capacidad restante.
Pantalla ePaper
El Kit DIY TRMNL 7.5" (OG) cuenta con una hermosa pantalla ePaper de 7.5 pulgadas en blanco y negro que proporciona visibilidad clara en varias condiciones de iluminación y consumo de energía ultra bajo. En esta sección, exploraremos cómo configurar y controlar la pantalla ePaper usando Arduino.
Configuración de Hardware
Antes de comenzar a programar, asegurémonos de que la pantalla ePaper esté correctamente conectada a la placa TRMNL:
Paso 1. Conecta la pantalla ePaper al conector de 24 pines en la placa controladora. El conector soporta inserción ciega, por lo que no puedes insertarlo incorrectamente.

Paso 2. Después de insertar el cable de cinta, asegúralo cerrando el mecanismo de bloqueo.
El cable de cinta es frágil y puede dañarse fácilmente. Evita doblarlo lateralmente tanto como sea posible.
Paso 3. Asegúrate de que el jumper conecte los pines 24Pin y GND en la placa.

Configuración de Software
Para controlar la pantalla ePaper, usaremos la biblioteca Seeed_GFX, que proporciona soporte integral para varios dispositivos de pantalla de Seeed Studio.
Paso 1. Descarga la biblioteca Seeed_GFX desde GitHub:
Paso 2. Instala la biblioteca agregando el archivo ZIP en Arduino IDE. Ve a Sketch > Include Library > Add .ZIP Library y selecciona el archivo ZIP descargado.
Si has instalado previamente la biblioteca TFT_eSPI, puede que necesites removerla temporalmente o renombrarla desde tu carpeta de bibliotecas de Arduino para evitar conflictos, ya que Seeed_GFX es un fork de TFT_eSPI con características adicionales.
Paso 3. Abre el sketch de ejemplo de la biblioteca Seeed_GFX: File > Seeed_GFX > Examples > ePaper > Basic > Clock
Paso 4. Crea un nuevo archivo llamado driver.h
en la misma carpeta que tu sketch de Arduino haciendo clic en la flecha junto a la pestaña del ejemplo y seleccionando "New Tab".
Paso 5. Nombra el nuevo archivo como driver.h
.

Paso 6. Ve a la Herramienta de Configuración Seeed GFX, y selecciona "TRMNL 7.5" (OG) DIY Kit" como se muestra en la imagen.

Paso 7. Copia el código generado y pégalo en el archivo driver.h
que creaste. El código debería verse así:
#define BOARD_SCREEN_COMBO 502 // 7.5 inch monochrome ePaper Screen (UC8179)
#define USE_XIAO_EPAPER_DISPLAY_BOARD_EE04
Paso 8. ¡Ahora puedes subir el ejemplo a tu Kit DIY TRMNL y ver la pantalla ePaper en acción!

Ejemplo Básico de Pantalla ePaper
Exploremos un ejemplo simple de reloj analógico que demuestra cómo dibujar gráficos en la pantalla ePaper. Este ejemplo crea una esfera de reloj clásica con manecillas de hora, minuto y segundo.
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
#ifdef EPAPER_ENABLE // Only compile this code if the EPAPER_ENABLE is defined in User_Setup.h
EPaper epaper = EPaper(); // Invoke custom library
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers
float sdeg = 0, mdeg = 0, hdeg = 0;
uint16_t osx = 120, osy = 120, omx = 120, omy = 120, ohx = 120, ohy = 120; // Saved H, M, S x & y coords
uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0;
uint32_t targetTime = 0; // for next 1 second timeout
static uint8_t conv2d(const char *p); // Forward declaration needed for IDE 1.6.x
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
bool initial = 1;
#endif
void setup(void)
{
#ifdef EPAPER_ENABLE
epaper.begin();
epaper.setRotation(0);
epaper.fillScreen(TFT_WHITE);
epaper.setTextColor(TFT_BLACK, TFT_WHITE); // Adding a background colour erases previous text automatically
// Draw clock face
epaper.fillCircle(120, 120, 118, TFT_BLACK);
epaper.fillCircle(120, 120, 110, TFT_WHITE);
// Draw 12 lines
for (int i = 0; i < 360; i += 30)
{
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 114 + 120;
yy0 = sy * 114 + 120;
x1 = sx * 100 + 120;
yy1 = sy * 100 + 120;
epaper.drawLine(x0, yy0, x1, yy1, TFT_BLACK);
}
// Draw 60 dots
for (int i = 0; i < 360; i += 6)
{
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 102 + 120;
yy0 = sy * 102 + 120;
// Draw minute markers
epaper.drawPixel(x0, yy0, TFT_BLACK);
// Draw main quadrant dots
if (i == 0 || i == 180)
epaper.fillCircle(x0, yy0, 2, TFT_BLACK);
if (i == 90 || i == 270)
epaper.fillCircle(x0, yy0, 2, TFT_BLACK);
}
epaper.fillCircle(120, 121, 3, TFT_BLACK);
// Draw text at position 120,260 using fonts 4
// Only font numbers 2,4,6,7 are valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : . - a p m
// Font 7 is a 7 segment font and only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : .
epaper.drawCentreString("Time flies", 120, 260, 4);
epaper.update();
targetTime = millis() + 1000;
#endif
}
void loop()
{
#ifdef EPAPER_ENABLE
if (targetTime < millis())
{
targetTime += 1000;
ss++; // Advance second
if (ss == 60)
{
ss = 0;
mm++; // Advance minute
if (mm > 59)
{
mm = 0;
hh++; // Advance hour
if (hh > 23)
{
hh = 0;
}
}
}
// Pre-compute hand degrees, x & y coords for a fast screen update
sdeg = ss * 6; // 0-59 -> 0-354
mdeg = mm * 6 + sdeg * 0.01666667; // 0-59 -> 0-360 - includes seconds
hdeg = hh * 30 + mdeg * 0.0833333; // 0-11 -> 0-360 - includes minutes and seconds
hx = cos((hdeg - 90) * 0.0174532925);
hy = sin((hdeg - 90) * 0.0174532925);
mx = cos((mdeg - 90) * 0.0174532925);
my = sin((mdeg - 90) * 0.0174532925);
sx = cos((sdeg - 90) * 0.0174532925);
sy = sin((sdeg - 90) * 0.0174532925);
if (ss == 0 || initial)
{
initial = 0;
// Erase hour and minute hand positions every minute
epaper.drawLine(ohx, ohy, 120, 121, TFT_WHITE);
ohx = hx * 62 + 121;
ohy = hy * 62 + 121;
epaper.drawLine(omx, omy, 120, 121, TFT_WHITE);
omx = mx * 84 + 120;
omy = my * 84 + 121;
}
// Redraw new hand positions, hour and minute hands not erased here to avoid flicker
epaper.drawLine(osx, osy, 120, 121, TFT_WHITE);
osx = sx * 90 + 121;
osy = sy * 90 + 121;
epaper.drawLine(osx, osy, 120, 121, TFT_BLACK);
epaper.drawLine(ohx, ohy, 120, 121, TFT_BLACK);
epaper.drawLine(omx, omy, 120, 121, TFT_BLACK);
epaper.drawLine(osx, osy, 120, 121, TFT_BLACK);
epaper.fillCircle(120, 121, 3, TFT_BLACK);
epaper.update();
}
#endif
}
#ifdef EPAPER_ENABLE
static uint8_t conv2d(const char *p)
{
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
#endif
Cómo Funciona el Ejemplo del Reloj:
Este elegante ejemplo crea un reloj analógico clásico en la pantalla ePaper. Vamos a desglosar cómo funciona:
-
Inicialización y Configuración:
- El código utiliza compilación condicional con
#ifdef EPAPER_ENABLE
para asegurar que solo se ejecute en hardware con soporte de pantalla e-paper. - Declaramos variables para rastrear las posiciones de las manecillas del reloj y sus posiciones anteriores.
- La hora inicial se establece basándose en el tiempo de compilación del sketch usando la macro
__TIME__
.
- El código utiliza compilación condicional con
-
Función Setup:
- Inicializamos la pantalla e-paper con
epaper.begin()
. - La pantalla se llena de blanco como fondo usando
epaper.fillScreen(TFT_WHITE)
. - Dibujamos la cara del reloj como un círculo negro con un interior blanco.
- Los marcadores de hora se dibujan como 12 líneas alrededor de la circunferencia.
- Los marcadores de minuto se dibujan como 60 puntos con énfasis especial en las posiciones de cuarto de hora.
- Se dibuja un pequeño círculo negro en el centro de la cara del reloj.
- El texto "Time flies" se añade en la parte inferior de la pantalla.
- Finalmente, se llama a
epaper.update()
para actualizar la pantalla física.
- Inicializamos la pantalla e-paper con
-
Función Loop:
- Cada segundo (cuando
millis()
excedetargetTime
), actualizamos las manecillas del reloj. - Incrementamos los segundos, minutos y horas según sea necesario.
- Calculamos los ángulos para cada manecilla basándose en la hora actual.
- Las posiciones de las manecillas se calculan usando funciones trigonométricas:
- Manecilla de horas: 30 grados por hora (más ajuste por minutos)
- Manecilla de minutos: 6 grados por minuto (más ajuste por segundos)
- Manecilla de segundos: 6 grados por segundo
- Para reducir actualizaciones innecesarias y extender la vida útil de la pantalla, solo borramos y redibujamos las manecillas de hora y minuto una vez por minuto (cuando segundos = 0).
- La manecilla de segundos se actualiza cada segundo borrando su posición anterior y dibujándola en la nueva posición.
- Después de dibujar todas las manecillas, refrescamos el punto central y llamamos a
epaper.update()
para actualizar la pantalla física.
- Cada segundo (cuando
-
Función Auxiliar:
- La función
conv2d
convierte una representación de cadena de un número a un valor entero, utilizada para analizar los valores de hora, minuto y segundo del tiempo de compilación.
- La función
Notas Importantes Sobre Este Ejemplo:
-
Actualizaciones de Pantalla: A diferencia de las pantallas LCD u OLED, las pantallas ePaper no están diseñadas para actualizaciones frecuentes. Este ejemplo actualiza la pantalla cada segundo, lo cual está bien para propósitos de demostración, pero en una aplicación del mundo real, podrías querer actualizar con menos frecuencia para extender la vida útil de la pantalla.
-
Actualizaciones Parciales: Este ejemplo demuestra actualizaciones parciales al solo borrar y redibujar las partes necesarias de la pantalla, lo cual es más eficiente que refrescar toda la pantalla.
-
Compilación Condicional: Las directivas
#ifdef EPAPER_ENABLE
aseguran que el código solo se compile y ejecute si la pantalla e-paper está configurada correctamente en el sistema. -
Funciones de Dibujo: El ejemplo muestra varias funciones de dibujo:
fillCircle()
para crear la cara del relojdrawLine()
para dibujar manecillas del reloj y marcadores de horadrawPixel()
yfillCircle()
para marcadores de minutodrawCentreString()
para texto centrado
Este ejemplo de reloj analógico proporciona un excelente punto de partida para crear tus propias aplicaciones gráficas en la pantalla ePaper del TRMNL 7.5" (OG) DIY Kit.
Funciones de Dibujo y Texto
La biblioteca Seeed_GFX proporciona muchas funciones para dibujar en la pantalla:
display.drawPixel(x, y, color)
: Dibuja un solo píxeldisplay.drawLine(x0, y0, x1, y1, color)
: Dibuja una líneadisplay.drawRect(x, y, w, h, color)
: Dibuja el contorno de un rectángulodisplay.fillRect(x, y, w, h, color)
: Dibuja un rectángulo rellenodisplay.drawCircle(x, y, r, color)
: Dibuja el contorno de un círculodisplay.fillCircle(x, y, r, color)
: Dibuja un círculo rellenodisplay.drawTriangle(x0, y0, x1, y1, x2, y2, color)
: Dibuja el contorno de un triángulodisplay.fillTriangle(x0, y0, x1, y1, x2, y2, color)
: Dibuja un triángulo rellenodisplay.setCursor(x, y)
: Establece la posición del cursor de textodisplay.setTextColor(color)
: Establece el color del textodisplay.setTextSize(size)
: Establece el tamaño del texto (1-6)display.print("text")
: Imprime texto en la posición del cursordisplay.println("text")
: Imprime texto con una nueva línea
Los colores disponibles para esta pantalla monocromática son:
GxEPD_BLACK
: Píxeles negrosGxEPD_WHITE
: Píxeles blancos
Recuerda llamar a display.update()
después de las operaciones de dibujo para actualizar la pantalla física.
Soporte Técnico y Discusión de Productos
¡Gracias por elegir nuestros productos! Estamos aquí para brindarte diferentes tipos de soporte para asegurar que tu experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para satisfacer diferentes preferencias y necesidades.