Pular para o conteúdo principal

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.

dica

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)

dica

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.

dica

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.

dica

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:

  1. Definimos constantes de pinos para os três botões de usuário (D1, D2, D4).

  2. Na função setup(), inicializamos a comunicação serial e configuramos os pinos dos botões como entradas com resistores de pull-up internos.

  3. 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.

  4. Invertemos as leituras (com o operador !) para que true signifique "pressionado" e false signifique "solto".

  5. Se qualquer botão for pressionado, imprimimos o estado de todos os botões no Monitor Serial.

  6. 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:

  1. 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

  1. Definimos um CALIBRATION_FACTOR (0.968) para ajustar finamente a precisão da leitura de tensão.

  2. 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

  1. 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

  1. 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.

cuidado

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.

nota

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:

  1. Inicialização e Configuração:

    • O código usa compilação condicional com #ifdef EPAPER_ENABLE para 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__.
  2. 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.
  3. Função Loop:

    • A cada segundo (quando millis() ultrapassa targetTime), 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.
  4. Função Auxiliar:

    • A função conv2d converte 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.

Notas Importantes Sobre Este Exemplo:

  1. 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.

  2. 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.

  3. Compilação Condicional: As diretivas #ifdef EPAPER_ENABLE garantem que o código só seja compilado e executado se o display de e-paper estiver devidamente configurado no sistema.

  4. Funções de Desenho: O exemplo demonstra várias funções de desenho:

    • fillCircle() para criar o mostrador do relógio
    • drawLine() para desenhar os ponteiros do relógio e os marcadores de hora
    • drawPixel() e fillCircle() para marcadores de minuto
    • drawCentreString() 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 pixel
  • display.drawLine(x0, y0, x1, y1, color): Desenha uma linha
  • display.drawRect(x, y, w, h, color): Desenha o contorno de um retângulo
  • display.fillRect(x, y, w, h, color): Desenha um retângulo preenchido
  • display.drawCircle(x, y, r, color): Desenha o contorno de um círculo
  • display.fillCircle(x, y, r, color): Desenha um círculo preenchido
  • display.drawTriangle(x0, y0, x1, y1, x2, y2, color): Desenha o contorno de um triângulo
  • display.fillTriangle(x0, y0, x1, y1, x2, y2, color): Desenha um triângulo preenchido
  • display.setCursor(x, y): Define a posição do cursor de texto
  • display.setTextColor(color): Define a cor do texto
  • display.setTextSize(size): Define o tamanho do texto (1-6)
  • display.print("text"): Imprime texto na posição do cursor
  • display.println("text"): Imprime texto com uma nova linha

As cores disponíveis para este display monocromático são:

  • GxEPD_BLACK: Pixels pretos
  • GxEPD_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.

Loading Comments...