Introdução ao Kit DIY TRMNL 7.5" (OG) com Arduino
Introdução
O Kit DIY TRMNL 7.5" (OG) é uma plataforma de desenvolvimento versátil que apresenta o poderoso XIAO ESP32-S3 Plus como seu cérebro. Este Kit DIY combina o poder de processamento do ESP32-S3 com uma bela tela ePaper de 7,5 polegadas, criando a base perfeita para projetos de exibição de informações de baixo consumo de energia. Este guia se concentra em programar o Kit DIY TRMNL usando o framework Arduino, fornecendo o conhecimento essencial para utilizar seus vários recursos de hardware.
Primeiros Passos
Antes de mergulharmos nos recursos específicos, vamos configurar nosso ambiente de desenvolvimento para o Kit DIY TRMNL 7.5" (OG).
Instalação do Equipamento
Passo 1. Conectar a Tela à Placa Controladora
Alinhe o cabo FPC com o conector na Placa de Display ePaper XIAO e, em seguida, prenda a trava para garantir uma conexão firme.
O lado metálico do cabo FPC deve ficar voltado para cima, caso contrário, nenhum conteúdo será exibido.
Siga o tutorial de instalação abaixo; muitas pessoas fazem isso de forma incorreta.

Passo 2. Conectar a Bateria
Conecte o cabo da bateria ao conector JST na placa controladora, garantindo a polaridade correta (fio vermelho em +, preto em -).

Passo 3. Montagem do Gabinete (Opcional)
Observe que o cabo flexível da tela é muito frágil. Tenha cuidado ao manuseá-lo. Se ele for danificado, toda a tela deixará de funcionar.
Imprima as partes de gabinete open-source a partir da Resource part e monte os componentes no interior.

Primeiro, monte a placa controladora e a bateria.
Teste o kit TRMNL para verificar se ele funciona bem.
Coloque a tela dentro do gabinete e deixe o FPC sair.
Conecte o cabo de extensão FPC e monte todo o gabinete.
O gabinete em formato de L é muito semelhante.
Se o seu kit TRMNL estiver muito longe do seu roteador, você pode mover a antena para fora do gabinete. Isso proporcionará um desempenho melhor.
Preparação do Ambiente
Para programar o Kit DIY TRMNL com Arduino, você precisará configurar a IDE Arduino com suporte para ESP32.
Se esta é a sua primeira vez usando Arduino, recomendamos fortemente que consulte Primeiros Passos com Arduino.
Passo 1. Baixe e instale a IDE Arduino e inicie o aplicativo Arduino.

Passo 2. Adicione o suporte à placa ESP32 na IDE Arduino.
Na IDE Arduino, vá em File > Preferences e adicione a seguinte URL no campo "Additional Boards Manager URLs":
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Passo 3. Instale o pacote de placas ESP32.
Navegue até Tools > Board > Boards Manager, pesquise por "esp32" e instale o pacote ESP32 da Espressif Systems.
Passo 4. Selecione a placa correta.
Vá em Tools > Board > ESP32 Arduino e selecione "XIAO_ESP32S3_PLUS".
Passo 5. Conecte seu Kit DIY TRMNL ao computador usando um cabo USB-C.
Passo 6. Selecione a porta correta em Tools > Port.
Exemplos em Arduino
Agora vamos explorar os principais recursos do Kit DIY TRMNL com exemplos de código em Arduino.
Botões de Usuário
O Kit DIY TRMNL possui três botões programáveis pelo usuário (D1, D2, D4) e um botão de reset. Vamos criar um exemplo simples para detectar pressionamentos de botão.
Exemplo de Teste de Botões
Este exemplo irá ler o estado dos três botões de usuário e imprimir seu status no Monitor Serial.
// 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);
}
}
Como o Código Funciona:
-
Definimos constantes de pinos para os três botões de usuário (D1, D2, D4).
-
Na função
setup(), inicializamos a comunicação serial e configuramos os pinos dos botões como entradas com resistores de pull-up internos. -
Na função
loop(), lemos o estado de cada botão. Como estamos usando resistores de pull-up, os pinos leem LOW quando os botões são pressionados. -
Invertemos as leituras (com o operador
!) para quetruesignifique "pressionado" efalsesignifique "solto". -
Se qualquer botão for pressionado, imprimimos o estado de todos os botões no Monitor Serial.
-
Um pequeno atraso evita leituras repetidas rápidas quando um botão é mantido pressionado.

Monitoramento da Tensão da Bateria
O Kit DIY TRMNL 7.5" (OG) inclui um circuito para monitoramento da tensão da bateria conectado ao pino D0 (GPIO1). Um recurso importante desse projeto é que ele também inclui um pino de controle (GPIO6) para habilitar/desabilitar a alimentação do ADC, o que ajuda a economizar bateria quando não estiver medindo ativamente.
Exemplo de Monitoramento da Tensão da Bateria
// 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;
}
Como o Código Funciona:
- Definimos dois pinos importantes:
-
BATTERY_PIN(GPIO1/A0): Conectado ao divisor de tensão da bateria -
ADC_EN_PIN(GPIO6/A5): Controla a alimentação do circuito de medição do ADC
-
Definimos um
CALIBRATION_FACTOR(0.968) para ajustar finamente a precisão da leitura de tensão. -
Na função
setup():
-
Inicializamos a comunicação serial
-
Configuramos o pino ADC_EN como saída e o definimos como LOW (desativado) para economizar energia
-
Definimos a resolução do ADC para 12 bits (0-4095)
-
Configuramos a atenuação apropriada para o pino da bateria
- Na função
loop():
-
Chamamos
readBatteryVoltage()para obter a tensão atual da bateria -
Imprimimos a tensão no Monitor Serial
-
Determinamos e exibimos o status da bateria com base em limites de tensão
-
Aguardamos 5 segundos antes de fazer a próxima leitura
- A função
readBatteryVoltage():
-
Habilita o circuito do ADC definindo ADC_EN_PIN como HIGH
-
Aguarda brevemente para o circuito estabilizar
-
Faz 30 leituras e calcula a média para obter resultados mais estáveis
-
Desativa o circuito do ADC para economizar energia
-
Calcula a tensão real da bateria usando:
- A leitura média do ADC
- A resolução do ADC (4095)
- Tensão de referência (3.6V)
- Fator do divisor de tensão (2.0)
- Fator de calibração (0.968)

Design de Economia de Energia:
Um recurso importante desta implementação é a capacidade de desativar o circuito de medição da bateria quando não está em uso. O TRMNL DIY Kit é projetado para baixo consumo de energia, e essa abordagem ajuda a estender a vida útil da bateria, alimentando o circuito divisor de tensão apenas quando uma medição real é necessária.
O fator de calibração (0.968) compensa as tolerâncias dos componentes no divisor de tensão e ajuda a garantir leituras precisas. Esse valor pode precisar de um pequeno ajuste para a sua placa específica se você notar que as leituras estão consistentemente fora em comparação com a medição de um multímetro.
Realizar várias leituras e calcular a média ajuda a reduzir o ruído e fornece medições de tensão mais estáveis, o que é especialmente importante para o monitoramento de bateria, onde pequenas variações de tensão podem ser significativas para determinar a capacidade restante.
Display ePaper
O TRMNL 7.5" (OG) DIY Kit possui um belo display ePaper preto e branco de 7,5 polegadas que oferece visibilidade clara em várias condições de iluminação e consumo de energia ultrabaixo. Nesta seção, vamos explorar como configurar e controlar o display ePaper usando Arduino.
Configuração de Hardware
Antes de começarmos a programar, vamos garantir que o display ePaper esteja devidamente conectado à placa TRMNL:
Passo 1. Conecte o display ePaper ao conector de 24 pinos na placa controladora. O conector suporta inserção cega, então você não consegue inseri-lo de forma incorreta.

Passo 2. Depois de inserir o cabo flat, fixe-o fechando o mecanismo de travamento.
O cabo flat é frágil e pode ser facilmente danificado. Evite dobrá-lo lateralmente tanto quanto possível.
Passo 3. Certifique-se de que o jumper conecte os pinos 24Pin e GND na placa.

Configuração de Software
Para controlar o display ePaper, usaremos a biblioteca Seeed_GFX, que oferece suporte abrangente para vários dispositivos de display da Seeed Studio.
Passo 1. Baixe a biblioteca Seeed_GFX do GitHub:
Passo 2. Instale a biblioteca adicionando o arquivo ZIP na Arduino IDE. Vá em Sketch > Include Library > Add .ZIP Library e selecione o arquivo ZIP baixado.
Se você tiver instalado anteriormente a biblioteca TFT_eSPI, talvez seja necessário removê-la temporariamente ou renomeá-la na pasta de bibliotecas do Arduino para evitar conflitos, pois a Seeed_GFX é um fork da TFT_eSPI com recursos adicionais.
Passo 3. Abra o exemplo da biblioteca Seeed_GFX: File > Seeed_GFX > Examples > ePaper > Basic > Clock
Passo 4. Crie um novo arquivo chamado driver.h na mesma pasta do seu sketch Arduino clicando na seta ao lado da aba do exemplo e selecionando "New Tab".
Passo 5. Dê ao novo arquivo o nome driver.h.

Passo 6. Acesse a Seeed GFX Configuration Tool e selecione "TRMNL 7.5" (OG) DIY Kit" como mostrado na imagem.

Passo 7. Copie o código gerado e cole-o no arquivo driver.h que você criou. O código deve se parecer com isto:
#define BOARD_SCREEN_COMBO 502 // 7.5 inch monochrome ePaper Screen (UC8179)
#define USE_XIAO_EPAPER_DISPLAY_BOARD_EE04
Passo 8. Agora você pode enviar o exemplo para o seu TRMNL DIY Kit e ver o display ePaper em ação!

Exemplo Básico de Display ePaper
Vamos explorar um simples exemplo de relógio analógico que demonstra como desenhar gráficos no display ePaper. Este exemplo cria um mostrador de relógio clássico com ponteiros de horas, minutos e segundos.
#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
Como o Exemplo do Relógio Funciona:
Este exemplo elegante cria um relógio analógico clássico no display de ePaper. Vamos entender como ele funciona:
-
Inicialização e Configuração:
- O código usa compilação condicional com
#ifdef EPAPER_ENABLEpara garantir que ele só seja executado em hardware com suporte a display e-paper. - Declaramos variáveis para rastrear as posições dos ponteiros do relógio e suas posições anteriores.
- A hora inicial é definida com base no horário de compilação do sketch usando a macro
__TIME__.
- O código usa compilação condicional com
-
Função Setup:
- Inicializamos o display de e-paper com
epaper.begin(). - O display é preenchido com branco como plano de fundo usando
epaper.fillScreen(TFT_WHITE). - Desenhamos o mostrador do relógio como um círculo preto com interior branco.
- Os marcadores de hora são desenhados como 12 linhas ao redor da circunferência.
- Os marcadores de minuto são desenhados como 60 pontos com ênfase especial nas posições de quarto de hora.
- Um pequeno círculo preto é desenhado no centro do mostrador do relógio.
- O texto "Time flies" é adicionado na parte inferior do display.
- Por fim,
epaper.update()é chamado para atualizar o display físico.
- Inicializamos o display de e-paper com
-
Função Loop:
- A cada segundo (quando
millis()ultrapassatargetTime), atualizamos os ponteiros do relógio. - Incrementamos os segundos, minutos e horas conforme necessário.
- Calculamos os ângulos para cada ponteiro com base na hora atual.
- As posições dos ponteiros são calculadas usando funções trigonométricas:
- Ponteiro das horas: 30 graus por hora (mais o ajuste pelos minutos)
- Ponteiro dos minutos: 6 graus por minuto (mais o ajuste pelos segundos)
- Ponteiro dos segundos: 6 graus por segundo
- Para reduzir atualizações desnecessárias e aumentar a vida útil do display, apagamos e redesenhamos os ponteiros de horas e minutos apenas uma vez por minuto (quando seconds = 0).
- O ponteiro de segundos é atualizado a cada segundo apagando sua posição anterior e desenhando-o na nova posição.
- Depois de desenhar todos os ponteiros, renovamos o ponto central e chamamos
epaper.update()para atualizar o display físico.
- A cada segundo (quando
-
Função Auxiliar:
- A função
conv2dconverte uma representação em string de um número em um valor inteiro, usada para analisar os valores de hora, minuto e segundo do horário de compilação.
- A função
Notas Importantes Sobre Este Exemplo:
-
Atualizações do Display: Diferente de displays LCD ou OLED, displays ePaper não são projetados para atualizações frequentes. Este exemplo atualiza o display a cada segundo, o que é aceitável para fins de demonstração, mas em uma aplicação real você provavelmente vai querer atualizar com menos frequência para aumentar a vida útil do display.
-
Atualizações Parciais: Este exemplo demonstra atualizações parciais apagando e redesenhando apenas as partes necessárias do display, o que é mais eficiente do que atualizar a tela inteira.
-
Compilação Condicional: As diretivas
#ifdef EPAPER_ENABLEgarantem que o código só seja compilado e executado se o display de e-paper estiver devidamente configurado no sistema. -
Funções de Desenho: O exemplo demonstra várias funções de desenho:
fillCircle()para criar o mostrador do relógiodrawLine()para desenhar os ponteiros do relógio e os marcadores de horadrawPixel()efillCircle()para marcadores de minutodrawCentreString()para texto centralizado
Este exemplo de relógio analógico fornece um ótimo ponto de partida para criar suas próprias aplicações gráficas no display de ePaper do TRMNL 7.5" (OG) DIY Kit.
Funções de Desenho e Texto
A biblioteca Seeed_GFX oferece muitas funções para desenhar no display:
display.drawPixel(x, y, color): Desenha um único pixeldisplay.drawLine(x0, y0, x1, y1, color): Desenha uma linhadisplay.drawRect(x, y, w, h, color): Desenha o contorno de um retângulodisplay.fillRect(x, y, w, h, color): Desenha um retângulo preenchidodisplay.drawCircle(x, y, r, color): Desenha o contorno de um círculodisplay.fillCircle(x, y, r, color): Desenha um círculo preenchidodisplay.drawTriangle(x0, y0, x1, y1, x2, y2, color): Desenha o contorno de um triângulodisplay.fillTriangle(x0, y0, x1, y1, x2, y2, color): Desenha um triângulo preenchidodisplay.setCursor(x, y): Define a posição do cursor de textodisplay.setTextColor(color): Define a cor do textodisplay.setTextSize(size): Define o tamanho do texto (1-6)display.print("text"): Imprime texto na posição do cursordisplay.println("text"): Imprime texto com uma nova linha
As cores disponíveis para este display monocromático são:
GxEPD_BLACK: Pixels pretosGxEPD_WHITE: Pixels brancos
Lembre-se de chamar display.update() após as operações de desenho para atualizar o display físico.
Suporte Técnico e Discussão de Produtos
Obrigado por escolher nossos produtos! Estamos aqui para oferecer diferentes tipos de suporte para garantir que sua experiência com nossos produtos seja o mais tranquila possível. Oferecemos vários canais de comunicação para atender a diferentes preferências e necessidades.