Skip to Content

CrowPanel E-Paper de 4.2 polegadas com GxEPD2

CrowPanel E-Paper de 4.2 polegadas com GxEPD2

Neste blog mostro como pode usar a biblioteca GxEPD2 para desenhar num E-Paper CrowPanel de 4,2 polegadas.

Os E-Papers CrowPanel da Elecrow vêm com algum código de exemplo que demonstra como desenhar no ecrã. No entanto, a funcionalidade desse código é bastante limitada. Seria muito melhor se pudéssemos usar a mais capaz GxEPD2 Libary. Infelizmente, em dezembro de 2024 não existe suporte direto para nenhum dos ecrãs E-Paper CrowPanel na biblioteca GxEPD2 (veja GxEPD2_display_selection_new_style.h).

No entanto, com um pequeno ajuste podemos fazer a biblioteca GxEPD2 funcionar no E-Paper CrowPanel de 4,2 polegadas e nas secções seguintes vou mostrar como isso é feito.

Peças Necessárias

Vai precisar de um E-Paper CrowPanel. Neste tutorial foco-me na versão de 4,2 polegadas, que é a que deve adquirir. Existem outros tamanhos de ecrã e os exemplos de código devem funcionar em grande parte, mas terá de fazer alterações devido à diferença na resolução e no driver do ecrã.

E-Paper CrowPanel de 4,2 polegadas

Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.

E-Paper CrowPanel de 4,2 polegadas

O E-Paper de 4,2 polegadas da CrowPanel é um ecrã a preto e branco, com resolução de 400×300 pixels. Vem como um módulo integrado que contém um chip ESP32-S3, vários botões para controlar o ecrã e mais. A imagem seguinte mostra a frente do ecrã com três botões de controlo ao lado:

Front of CrowPanel 4.2-inch E-Paper Display
Frente do E-Paper CrowPanel de 4,2 polegadas (source)

Botões

Os botões MENU e EXIT são botões simples de pressão, enquanto o Rotary Switch suporta funções de cima, baixo e confirmar/OK. Os botões são totalmente programáveis. A tabela seguinte mostra quais os pinos GPIO ligados a cada botão:

BotãoGPIO
MENUIO2
Rotary Switch DownIO4
Rotary Switch UpIO6
Rotary Switch CONFIO5
EXITIO1

Características

Além disso, o módulo do ecrã contém um slot para cartão TF, uma interface para bateria LiPo (SH1.0-2Pin) com capacidade de carregamento e uma interface GPIO. A programação (e alimentação) é feita via uma porta USB-C.

Interna of CrowPanel 4.2-inch E-Paper Display
Interior do E-Paper CrowPanel de 4,2 polegadas (source)

GPIO

Para GPIO estão disponíveis os seguintes pinos: IO3; IO9; IO15; IO17; IO19; IO21; IO8; IO14; IO16; IO18; IO20; IO38 e o pinout da porta GPIO pode ser encontrado na serigrafia mas também na parte de trás do módulo:

Pinout of GPIO port
Pinout da porta GPIO (source)

Reset e Boot

Na parte de trás do módulo estão os botões Boot e Reset. Infelizmente, eles sobressaem para além da caixa e são facilmente pressionados acidentalmente ao colocar o módulo numa mesa. Sugiro que os corte um pouco (com um alicate) para evitar isso.

Back of CrowPanel 4.2-inch E-Paper Display
Parte de trás do E-Paper CrowPanel de 4,2 polegadas (source)

Outros E-Papers CrowPanel

O ecrã de 4,2 polegadas é um de uma série inteira de ecrãs E-Paper semelhantes mas com diferentes resoluções, chips ESP32 e drivers. Veja a tabela abaixo para uma visão geral:

CrowPanel E-Paper Displays
E-Papers CrowPanel (source)

Para este tutorial, usei o ecrã de 4,2 polegadas, mas a maior parte do código provavelmente funciona para os outros tamanhos também. No entanto, terá de encontrar um driver correspondente na biblioteca GxEPD2. Mais sobre isso na próxima secção.

Biblioteca GxEPD2

A GxEPD2 Libary é uma biblioteca Arduino/ESP32 para ecrãs E-Paper SPI. Como mencionado antes, suporta muitos ecrãs E-Paper diferentes, mas até agora não suporta diretamente os ecrãs E-Paper CrowPanel.

No entanto, comparada com o código demo que vem com os ecrãs CrowPanel, a GxEPD2 Libary é preferível. Tem mais functions e melhor documentação, pois deriva da Adafruit-GFX-Library, e pode ser instalada e usada facilmente.

O mais importante é que pode (re)usar código escrito com a GxEPD2 Libary numa vasta gama de ecrãs E-Paper diferentes, sem ter de reescrevê-lo para ecrãs específicos.

Carregar Código para o E-Paper CrowPanel

Carregar código para o módulo E-Paper via Arduino IDE é fácil. Basta ligar o cabo USB e selecionar a placa “ESP32S3 Dev Module”:

Selecting ESP32S3 Dev Module
Selecionar ESP32S3 Dev Module

Em “Tools” selecione preferencialmente “Huge App” para o Partition Scheme e “OPI PSRAM” para as definições PSRAM. Embora não seja essencial para o código deste tutorial, parecem ser as definições recomendadas.

Board settings for CrowPanel E-Paper display
Definições da placa para o E-Paper CrowPanel

Código para usar a biblioteca GxEPD2 com o E-Paper CrowPanel

Nesta secção mostro como fazer a biblioteca GxEPD2 funcionar com o E-Paper CrowPanel. Há dois passos importantes. Primeiro, precisamos encontrar um driver GxEPD2 que tenha a mesma resolução e suporte o mesmo chip driver que o ecrã CrowPanel.

O ecrã de 4,2 polegadas usa o chip driver SSD1683 e tem resolução de 400×300 pixels. Se procurar na lista de drivers suportados em GxEPD2_display_selection_new_style.h encontrará duas correspondências:

//#define GxEPD2_DRIVER_CLASS GxEPD2_420_GDEY042T81 // GDEY042T81 400x300, SSD1683 (no inking)
//#define GxEPD2_DRIVER_CLASS GxEPD2_420_GYE042A87  // GYE042A87, 400x300, SSD1683 (HINK-E042-A07-FPC-A1)  

No entanto, se tentar esses drivers, só verá uma imagem muito fraca do que desenhar no ecrã. Analisei melhor o demo code e descobri que também tem de ligar a alimentação do ecrã. Isto é feito definindo a saída no GPIO7 para HIGH.

O exemplo seguinte imprime o texto “Makerguides” no centro do ecrã E-Paper de 4,2 polegadas. Dê uma vista de olhos rápida e depois discutimos os detalhes:

#include "GxEPD2_BW.h"

#define PWR 7
#define BUSY 48
#define RES 47
#define DC 46
#define CS 45

GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> epd(GxEPD2_420_GYE042A87(CS, DC, RES, BUSY));

void epdPower(int state) { 
  pinMode(PWR, OUTPUT);  
  digitalWrite(PWR, state);  
}

void epdInit() {  
  epd.init(115200, true, 50, false);
  epd.setRotation(0);
  epd.setTextColor(GxEPD_BLACK);
  epd.setTextSize(4);
  epd.setFullWindow();
}

void setup() {
  epdPower(HIGH);
  epdInit();
  epd.fillScreen(GxEPD_WHITE);
  epd.drawRect(0, 0, 400, 300, GxEPD_BLACK);
  epd.setCursor(70, 130);
  epd.print("Makerguides");
  epd.display();
  epd.hibernate(); 
  epdPower(LOW);
}

void loop() {}

Incluir

Primeiro, incluímos a GxEPD2 Libary e, como estamos a usar um E-Paper a preto e branco, incluímos “GxEPD2_BW.h”:

#include "GxEPD2_BW.h"

Se ainda não instalou a GxEPD2 Libary, terá de o fazer para que este código funcione. Também vai precisar da biblioteca Adafruit_GFX. Basta install the libraries da forma habitual. Após a instalação, elas devem aparecer no Library Manager da seguinte forma.

Adafruit_GFX and GxEPD2 libraries in Library Manager
Bibliotecas Adafruit_GFX e GxEPD2 no Library Manager

Não precisa de nenhuma das demo code que vêm com os ecrãs CrowPanel.

Definições dos Pinos

De seguida, precisamos definir os pinos SPI que o ecrã usa para comunicar com o ESP32.

#define PWR 7
#define BUSY 48
#define RES 47
#define DC 46
#define CS 45

Encontrei estes pinos ao olhar para o Schematics of the CrowPanel 4.2-inch E-Paper display. Aqui está a secção relevante dos esquemas que descreve a ligação ao E-Paper:

Schematics of the CrowPanel 4.2-inch E-Paper display
Esquema do E-Paper CrowPanel de 4,2 polegadas (source)

Objeto do Ecrã

Como mencionado antes, não há suporte direto para o E-Paper CrowPanel de 4,2 polegadas na GxEPD2 Libary. Portanto, usamos uma correspondência próxima para criar o objeto epd que representa o nosso ecrã E-Paper:

GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> epd(GxEPD2_420_GYE042A87(CS, DC, RES, BUSY));

Alternativamente, pode também usar a classe GxEPD2_420_GDEY042T81. Ambas parecem funcionar, mas no código seguinte usei a classe GxEPD2_420_GYE042A87.

Função epdPower

A função epdPower() é crítica e especial. Para outros ecrãs E-Paper não é necessária, mas para o CrowPanel E-Paper é. Define o GPIO7 como alto ou baixo e assim ativa ou desativa o ecrã E-Paper.

void epdPower(int state) { 
  pinMode(PWR, OUTPUT);  
  digitalWrite(PWR, state);  
}

Note que pode desativar o E-Paper (epdPower(LOW)) depois de desenhar nele. Ele continuará a mostrar a imagem, mesmo sem alimentação.

Função epdInit

A função epdInit() realiza a configuração inicial habitual para os gráficos, como rotação do ecrã, cor do texto, tamanho do texto e modo de atualização.

void epdInit() {  
  epd.init(115200, true, 50, false);
  epd.setRotation(0);
  epd.setTextColor(GxEPD_BLACK);
  epd.setTextSize(4);
  epd.setFullWindow();
}

Função setup

Na função setup(), ligamos o ecrã, preenchemos o ecrã de branco, desenhamos um quadro, imprimimos o texto “Makerguides”, mostramos-no e depois desligamos o ecrã novamente.

void setup() {
  epdPower(HIGH);
  epdInit();
  epd.fillScreen(GxEPD_WHITE);
  epd.drawRect(0, 0, 400, 300, GxEPD_BLACK);
  epd.setCursor(70, 130);
  epd.print("Makerguides");
  epd.display();
  epd.hibernate(); 
  epdPower(LOW);
}

Se carregar e executar este código, deverá ver a seguinte saída no ecrã E-Paper:

Saída de teste no E-Paper CrowPanel de 4,2 polegadas

Assim, com a adição da função epdPower() pode usar a GxEPD2 Libary normalmente para desenhar e escrever no E-Paper CrowPanel de 4,2 polegadas. Na próxima secção testamos a atualização parcial.

Atualização parcial do E-Paper CrowPanel

No código acima realizámos uma atualização completa do conteúdo do E-Paper. Esta atualização completa é ocasionalmente necessária para remover imagens residuais, mas é lenta (vários segundos) e faz o E-Paper piscar bastante.

Para a maioria das aplicações, quer atualizar apenas uma parte do ecrã, sem piscar e muito mais rápido. Por exemplo, para mostrar os dígitos de um relógio em funcionamento. Uma atualização parcial permite isso. Para mais detalhes, veja o tutorial Partial Refresh of e-Paper Display.

O código seguinte é essencialmente o mesmo usado nesse tutorial. Primeiro realiza uma atualização completa para limpar o ecrã e imprime o texto “msec:”. Depois realiza continuamente uma atualização parcial e atualiza os milissegundos em execução. Abaixo está uma captura de ecrã da saída do ecrã:

Display output for full- and partial refresh
Saída do ecrã para atualização completa e parcial

Aqui está o código completo para este teste. A única diferença para o do Partial Refresh of e-Paper Display é que precisamos usar novamente a função epdPower() para ligar o ecrã. E claro, o driver do ecrã é diferente.

#include "GxEPD2_BW.h"

#define PWR 7
#define BUSY 48
#define RES 47
#define DC 46
#define CS 45

GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> epd(GxEPD2_420_GYE042A87(CS, DC, RES, BUSY));

void epdPower(int state) { 
  pinMode(PWR, OUTPUT);  
  digitalWrite(PWR, state);  
}

void drawFull(const void* pv) {
  epd.setFullWindow();
  epd.setCursor(40, 60);
  epd.print("msec: ");
}

void drawPartial(const void* pv) {
  uint16_t x = 120, y = 50, w = 130, h = 34;
  epd.setPartialWindow(x, y, w, h);
  epd.setCursor(x + 30, y + 10);
  epd.print(millis());
  epd.drawRect(x, y, w, h, GxEPD_BLACK);
}

void setup() {
  epdPower(HIGH);
  epd.init(115200, true, 50, false);
  epd.setRotation(0);
  epd.setTextSize(2);
  epd.setTextColor(GxEPD_BLACK);
  epd.drawPaged(drawFull, 0);  
}

void loop() {
  epd.drawPaged(drawPartial, 0);
  epd.hibernate();
}

Se carregar e executar este código, deverá ver a seguinte saída. Note que os milissegundos são atualizados em menos de 0,5 segundos e que quase não há piscar (apenas um pouco à volta do quadro):

Partial refresh on CrowPanel 4.2-inch E-Paper
Atualização parcial no E-Paper CrowPanel de 4,2 polegadas

Assim, as atualizações completas e parciais funcionam bem no E-Paper CrowPanel de 4,2 polegadas com o driver GxEPD2 escolhido GxEPD2_420_GYE042A87.

Na próxima e última secção, mostro como usar a atualização parcial e os botões do ecrã CrowPanel para implementar um menu simples que controla três LEDs.

Controlar GPIO via Menu no E-Paper CrowPanel

Um dos demos para o ecrã CrowPanel mostra um menu simples com itens que podem ser ativados ou desativados através de pressionar botões.

Aqui vamos construir algo semelhante. Mas vamos usar a biblioteca GxEPD2 e os nossos botões vão controlar três LEDs. A captura de ecrã abaixo mostra como o menu vai parecer:

Menu de seleção de LED no ecrã CrowPanel

Vamos poder navegar no menu com os botões para cima e para baixo do rotary switch e selecionar um item do menu com o botão de confirmação. Se um item estiver selecionado, um LED da cor correspondente ligado ao GPIO será ligado, por exemplo, selecionar “Red” liga um LED vermelho:

Red LED selected in Menu
LED vermelho selecionado no menu

Diagrama de Ligações

O diagrama de ligações abaixo mostra como ligar os três LEDs à porta GPIO do ecrã CrowPanel. O cátodo de cada LED está ligado ao terra (GND). O ânodo do LED vermelho está ligado ao GPIO3, o LED verde ao GPIO9 e o azul ao GPIO15. Usei um resistor limitador de corrente de 220Ω para cada LED:

Connecting three LEDs to CrowPanel Display
Ligação de três LEDs ao ecrã CrowPanel

Código para navegar no menu e controlar os LEDs

Abaixo encontra o código para navegar no menu, selecionar e desselecionar itens e controlar os LEDs em conformidade:

#include "GxEPD2_BW.h"
#include <Fonts/FreeMonoBold24pt7b.h>

#define PWR 7
#define BUSY 48
#define RES 47
#define DC 46
#define CS 45
#define W 400
#define H 300

#define HOME_KEY 2
#define EXIT_KEY 1
#define PREV_KEY 6
#define NEXT_KEY 4
#define OK_KEY 5

int cursor = 0;
const int xoff = 70;
const int n_items = 3;
const char* items[] = { "Red", "Green", "Blue" };
const int pins[] = { 3, 9, 15 };
bool states[] = { false, false, false };
const int ypos[] = { 100, 100 + 60, 100 + 2 * 60 };

GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> epd(GxEPD2_420_GYE042A87(CS, DC, RES, BUSY));


void epdPower(int state) { 
  pinMode(PWR, OUTPUT);  
  digitalWrite(PWR, state);  
}

void drawCursor() {
  int16_t s = 12;
  int16_t x0 = xoff - s;
  int16_t y0 = ypos[cursor] - 12;
  int16_t x1 = x0 - s;
  int16_t y1 = y0 - s;
  int16_t x2 = x0 - s;
  int16_t y2 = y0 + s;
  epd.fillTriangle(x0, y0, x1, y1, x2, y2, GxEPD_BLACK);
}

void updateCursor(const void* pv) {
  epd.setPartialWindow(0, 0, xoff, 300);
  drawCursor();
}

void drawItem(int index) {
  int16_t xb, yb;
  uint16_t wb, hb;
  epd.setCursor(xoff + 5, ypos[index]);
  epd.getTextBounds(items[index], xoff + 5, ypos[index], &xb, &yb, &wb, &hb);
  if (states[index]) {
    epd.setTextColor(GxEPD_WHITE);
    epd.fillRect(xb - 5, yb - 3, W - 2 * xoff, hb + 6, GxEPD_BLACK);
  } else {
    epd.setTextColor(GxEPD_BLACK);
    epd.fillRect(xb - 5, yb - 3, W - 2 * xoff, hb + 6, GxEPD_WHITE);
  }
  epd.print(items[index]);
}

void updateItems(const void* pv) {
  epd.setPartialWindow(xoff, 0, W - xoff, 300);
  drawItems();
}

void drawItems() {
  for (int i = 0; i < n_items; i++) {
    drawItem(i);
  }
}

void initEPD() {
  epdPower(HIGH);
  epd.init(115200, true, 50, false);
  epd.setRotation(0);
  epd.setTextColor(GxEPD_BLACK);
  epd.setFont(&FreeMonoBold24pt7b);
  epd.setFullWindow();
  epd.fillScreen(GxEPD_WHITE);
}

void initButtons() {
  pinMode(HOME_KEY, INPUT);
  pinMode(EXIT_KEY, INPUT);
  pinMode(PREV_KEY, INPUT);
  pinMode(NEXT_KEY, INPUT);
  pinMode(OK_KEY, INPUT);
}

void initPins() {
  for (int i = 0; i < n_items; i++) {
      pinMode(pins[i], OUTPUT);
  }    
}

void setup() {
  initEPD();
  initButtons();
  initPins();
  drawItems();
  drawCursor();
  epd.display();
}

void loop() {
  if (!digitalRead(PREV_KEY)) {
    cursor = --cursor < 0 ? n_items - 1 : cursor;
    epd.drawPaged(updateCursor, 0);
  }
  if (!digitalRead(NEXT_KEY)) {
    cursor = ++cursor >= n_items ? 0 : cursor;
    epd.drawPaged(updateCursor, 0);
  }
  if (!digitalRead(OK_KEY)) {
    states[cursor] = !states[cursor];
    epd.drawPaged(updateItems, 0);
    digitalWrite(pins[cursor], states[cursor] ? HIGH : LOW);
  }
  if (!digitalRead(HOME_KEY)) {
    cursor = 0;
    epd.drawPaged(updateCursor, 0);
  }  
  if (!digitalRead(EXIT_KEY)) {
    for (int i = 0; i < n_items; i++) {
      states[i] = false;
      digitalWrite(pins[i], LOW);  
    }      
    epd.drawPaged(updateItems, 0);
  }
  delay(100);
}

Vamos decompor o código nos seus componentes para melhor compreensão.

Bibliotecas e Constantes

Começamos por incluir as bibliotecas necessárias para o ecrã E-Paper e fonts. As constantes definem os pinos usados para o ecrã e botões, bem como as dimensões do ecrã.

#include "GxEPD2_BW.h"
#include <Fonts/FreeMonoBold24pt7b.h>

#define PWR 7
#define BUSY 48
#define RES 47
#define DC 46
#define CS 45
#define W 400
#define H 300

Definições dos Botões

Definimos os pinos para os botões que serão usados para navegar no menu. Cada botão é atribuído a uma função específica: HOME, EXIT, PREV, NEXT e OK.

#define HOME_KEY 2
#define EXIT_KEY 1
#define PREV_KEY 6
#define NEXT_KEY 4
#define OK_KEY 5

Variáveis

São declaradas várias variáveis para gerir o estado do menu. cursor acompanha a seleção atual, items contém os nomes dos LEDs, e states indica se cada LED está ligado ou desligado. ypos especifica onde os itens do menu estão localizados no ecrã.

int cursor = 0;
const char* items[] = { "Red", "Green", "Blue" };
const int pins[] = { 3, 9, 15 };
bool states[] = { false, false, false };
const int ypos[] = { 100, 160, 220 };

Objeto do E-Paper

Como antes, o objeto do ecrã E-Paper é criado usando a classe GxEPD2_BW. Isto configura o ecrã com os pinos especificados. Se tiver um ecrã CrowPanel diferente, terá de alterar esta linha.

GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> epd(GxEPD2_420_GYE042A87(CS, DC, RES, BUSY));

Função de Controlo de Energia

A função epdPower() controla a energia para o ecrã E-Paper. Define o pino de energia como saída e escreve o estado especificado (HIGH ou LOW).

void epdPower(int state) { 
  pinMode(PWR, OUTPUT);  
  digitalWrite(PWR, state);  
}

Função de Desenho do Cursor

A função drawCursor() representa visualmente a seleção atual no menu desenhando um triângulo na posição correspondente.

void drawCursor() {
  int16_t s = 12;
  int16_t x0 = xoff - s;
  int16_t y0 = ypos[cursor] - 12;
  epd.fillTriangle(x0, y0, x1, y1, x2, y2, GxEPD_BLACK);
}

Note que a função updateCursor() correspondente realiza uma atualização parcial e só atualiza a secção do ecrã onde o cursor é mostrado. Será chamada quando os botões para cima ou para baixo forem pressionados, por exemplo.

void updateCursor(const void* pv) {
  epd.setPartialWindow(0, 0, xoff, 300);
  drawCursor();
}

Função de Desenho de Itens

A função drawItem() mostra um item no menu. Verifica o estado do LED e muda o fundo para preto se o item estiver selecionado.

void drawItem(int index) {
  epd.setCursor(xoff + 5, ypos[index]);
  if (states[index]) {
    epd.setTextColor(GxEPD_WHITE);
    epd.fillRect(...);
  } else {
    epd.setTextColor(GxEPD_BLACK);
    epd.fillRect(...);
  }
  epd.print(items[index]);
}

Para desenhar todos os itens do menu é usada a função drawItems():

void drawItems() {
  for (int i = 0; i < n_items; i++) {
    drawItem(i);
  }
}

E o estado de todos os itens é atualizado realizando uma atualização parcial do ecrã, onde os itens do menu estão localizados:

void updateItems(const void* pv) {
  epd.setPartialWindow(xoff, 0, W - xoff, 300);
  drawItems();
}

Funções de Inicialização

São definidas várias funções de inicialização: initEPD() inicializa o ecrã E-Paper, initButtons() define os pinos dos botões como entradas, e initPins() define os pinos dos LEDs como saídas.

void initEPD() {
  epdPower(HIGH);
  ...
}

void initButtons() {
  pinMode(HOME_KEY, INPUT);
  ...
}

void initPins() {
  for (int i = 0; i < n_items; i++) {
      pinMode(pins[i], OUTPUT);
  }    
}

Função Setup

A função setup() é chamada uma vez quando o programa começa. Inicializa o ecrã E-Paper, os botões e os pinos dos LEDs, e desenha os itens iniciais e o cursor no ecrã.

void setup() {
  initEPD();
  initButtons();
  initPins();
  drawItems();
  drawCursor();
  epd.display();
}

Função Loop

A função loop() corre continuamente. Verifica o estado dos botões e atualiza a posição do cursor ou alterna os estados dos LEDs com base na entrada do utilizador. O ecrã é atualizado em conformidade usando um redesenho paginado com atualização parcial.

void loop() {
  if (!digitalRead(PREV_KEY)) {
    ...
  }
  if (!digitalRead(NEXT_KEY)) {
    ...
  }
  if (!digitalRead(OK_KEY)) {
    ...
  }
  if (!digitalRead(HOME_KEY)) {
    ...
  }  
  if (!digitalRead(EXIT_KEY)) {
    ...
  }
  delay(100);
}

O botão PREV_KEY move o cursor um item do menu para cima e o NEXT_KEY move-o um item para baixo. Se chegar ao fim ou ao início do menu, o cursor volta ao início ou ao fim.

Com o botão OK_KEY pode alternar o estado de um item. O botão HOME_KEY move o cursor para o primeiro item do menu e o EXIT_KEY desseleciona todos os itens.

Demonstração do Código

Em resumo, este código fornece uma interface de utilizador num ecrã E-Paper para controlar três LEDs. O utilizador pode navegar pelas opções e ligar ou desligar os LEDs usando botões físicos. O vídeo curto seguinte mostra como é:

Controlar LEDs com Menu no ecrã E-Paper

Conclusões

Neste tutorial aprendeu como usar a biblioteca GxEPD2 para desenhar e escrever num E-Paper CrowPanel de 4,2 polegadas.

Se precisar de mais informações sobre ecrãs E-Paper, veja o Interfacing Arduino with E-ink Display e o tutorial Partial Refresh of e-Paper Display.

Além disso, se procura outras aplicações, os tutoriais Weather Station on e-Paper Display, Temperature Plotter on e-Paper Display, Digital Clock on e-Paper Display e Analog Clock on e-Paper Display podem ser do seu interesse.

Se tiver alguma dúvida, sinta-se à vontade para perguntar na secção de comentários. Boas experiências ; )

Links

Abaixo alguns links sobre o E-Paper CrowPanel de 4,2 polegadas que achei úteis ao escrever este tutorial: