Skip to Content

Interface TFT ILI9341 Touch Display com ESP32

Interface TFT ILI9341 Touch Display com ESP32

Neste tutorial, vais aprender a controlar um ecrã tátil TFT ILI9341 de 2,8 polegadas com resolução 240×320 usando um WEMOS Lolin32 lite (ESP32) e a biblioteca TFT_eSPI.

As instruções e o código funcionarão com algumas pequenas alterações para outros ESP32 e TFTs, desde que o ecrã utilize o ILI9341 driver do ecrã e o XPT2046 controlador tátil.

Peças Necessárias

Vais precisar de um ESP32 e de um ecrã tátil TFT de 2,8 polegadas com resolução de 240×320 pixels e um chip controlador de ecrã ILI9341. Alguns cabos e uma breadboard também podem ser úteis.

Ecrã Tátil TFT ILI9341 de 2,8 polegadas

ESP32 lite Lolin32

ESP32 lite

USB data cable

Cabo USB de Dados

Dupont wire set

Conjunto de Fios Dupont

Half_breadboard56a

Breadboard

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.

Módulo de Ecrã Tátil TFT ILI9341 de 2,8″

Existem algumas variações e clones deste módulo de ecrã de 2,8 polegadas, mas tendem a ser muito semelhantes e a maioria deve funcionar. O ecrã TFT tem resolução de 240×320 pixels com 65K cores RGB e é controlado via SPI usando o ILI9341 chip controlador do ecrã.

Além disso, o ecrã tem um ecrã tátil resistivo com um XPT2046 chip controlador tátil. Também há um soquete para cartão MicroSD na parte de trás, que podes usar para armazenar imagens, por exemplo. A imagem abaixo mostra a frente e o verso do módulo do ecrã.

Front and back of 2.8" TFT ILI9341 Touch Display Module
Frente e verso do Módulo de Ecrã Tátil TFT ILI9341 de 2,8″ (source)

O módulo do ecrã tem um regulador de tensão incorporado e podes alimentá-lo com 3,3V … 5V no VCC. No entanto, não há conversor de nível lógico, o que significa que não podes ligar diretamente um Arduino Uno que opera com lógica de 5V à interface SPI do módulo que opera a 3,3V!

Ligar o Módulo de Ecrã TFT ILI9341 ao Arduino

Se quiseres usar o ecrã com um Arduino, vais precisar de um conversor de nível. Podes usar divisores de tensão ou um level shifter module adequado. Como solução improvisada, Techtonics sugere adicionar resistores de 10k nas linhas SPI:

Connect Arduino Uno to TFT Display using 10K resistors
Ligar Arduino Uno ao Ecrã TFT usando resistores de 10K (source)

Isto provavelmente funcionará (não testei), mas usar um level shifter module adequado é uma solução mais fiável e segura. Alternativamente, usa um microcontrolador que opere a 3,3V, como o ESP32 que vamos usar aqui.

Fazer o Módulo de Ecrã Tátil TFT ILI9341 funcionar a 3,3V

Se sabes que vais usar o Módulo de Ecrã a 3,3V (VCC=3,3V), podes ignorar o regulador de tensão (U1) fechando (soldando) os pads jumper rotulados J1 na parte de trás do módulo. Vê a imagem abaixo:

Jumper J1 para ignorar o Regulador de Tensão

Isto pode tornar o ecrã mais estável, pois evitas a queda de tensão do regulador e também reduz ligeiramente o consumo de energia. Vê o esquema do regulador de tensão abaixo e como o jumper J1 afeta a ligação:

Schematic for Voltage Regulator and Bypass Jumper J1
Esquema do Regulador de Tensão e Jumper de Ignorar J1 (source)

Eu não fechei o J1 (deixei aberto como está) e o ecrã funcionou bem, mas se tiveres problemas de estabilidade, podes tentar fechar o J1.

No entanto, uma vez que soldes (feches) o J1, não podes fornecer 5V ao VCC! Deves usar 3,3V no VCC!

Pinout do Módulo de Ecrã Tátil TFT ILI9341

A imagem abaixo mostra a parte de trás do Módulo de Ecrã com os pinos do conector. Podes ver dois grupos: os pinos para o controlador tátil e os pinos SPI para o controlador do ecrã abaixo:

Pinout of TFT ILI9341 Touch Display Module
Pinout do Módulo de Ecrã Tátil TFT ILI9341

A tabela seguinte, retirada de lcdwiki, lista os pinos individuais e as suas funções:

NúmeroEtiqueta do PinoDescrição
1VCCEntrada de alimentação 5V/3,3V
2GNDTerra
3CSSinal de seleção do chip LCD, ativo em nível baixo
4RESETSinal de reset do LCD, reset ativo em nível baixo
5DC/RSSinal de seleção de registo/dados do LCD, nível alto: registo, nível baixo: dados
6SDI(MOSI)Sinal de escrita de dados no barramento SPI
7SCKSinal de relógio do barramento SPI
8LEDControlo da luz de fundo, se não for controlada, ligar a 3,3V
9SDO(MISO)Sinal de leitura de dados do barramento SPI, se não precisares da função de leitura, não ligues
10T_CLKSinal de relógio SPI do toque
11T_CSSinal de seleção do chip do ecrã tátil, ativo em nível baixo
12T_DINEntrada SPI do toque
13T_DOSaída SPI do toque
14T_IRQSinal de interrupção do ecrã tátil, nível baixo quando o toque é detetado

Ligação do Ecrã Tátil TFT ILI9341 ao ESP32

A imagem seguinte mostra como ligar o módulo do ecrã tátil a um WEMOS Lolin32 lite (ESP32):

Connecting the TFT ILI9341 Touch Display to ESP32
Ligação do Ecrã Tátil TFT ILI9341 ao ESP32

Há bastantes ligações a fazer e a tabela seguinte deve ajudar. Note que as linhas SDI(MOSI) e SCK da interface SPI são partilhadas entre o controlador do toque e o controlador do ecrã TFT:

ESP32TFTToque
5CS
4T_CS
17RESET
16DC
23SDI(MOSI)T_DIN
18SCKT_CLK
19T_DO
22LED

Poderias ligar o pino 19 do ESP32 ao SDO(MISO) também, mas como não lemos dados do controlador do ecrã TFT, não é necessário e há relatos de que em alguns casos isso causa problemas. Eu não liguei o pino 19 ao SDO(MISO) e o ecrã funcionou bem.

Note que também deixamos o T_IRQ do módulo do ecrã desligado. Este pino sinaliza se foi detetado um toque no ecrã e poderias usá-lo para acordar o ESP32 do deep-sleep, por exemplo. Contudo, neste tutorial não implementamos essa funcionalidade.

A ligação é bastante complexa e eu liguei duas breadboards para colocar o ESP32 e o ecrã TFT nelas. A boa notícia é que, exceto pelo terra (GND), todas as ligações estão de um lado do ESP32, o que simplifica um pouco a fiação. A imagem abaixo mostra a minha configuração:

Wiring of TFT ILI9341 Touch Display with ESP32 on breadboard
Fiação do Ecrã Tátil TFT ILI9341 com ESP32 na breadboard

Controlo da Luz de Fundo para o Ecrã Tátil TFT ILI9341

Note que o LED da luz de fundo do módulo é comutado via um transistor e, portanto, podemos controlá-lo diretamente via um GPIO; no nosso caso, usamos o pino 22 do ESP32. Vê o esquema do circuito de controlo do LED abaixo:

Schematic for LED backlight
Esquema para controlo do LED da luz de fundo (source)

Controlador Tátil para o Ecrã Tátil TFT ILI9341

Como mencionado antes, o controlador tátil do módulo do ecrã é um XPT2046. O esquema abaixo mostra como o controlador está ligado dentro do módulo do ecrã.

Schematic for Touch Controller
Esquema do Controlador Tátil (source)

Soquete para Cartão SD para o Ecrã Tátil TFT ILI9341

Finalmente, o módulo do ecrã tem um soquete para cartão SD. A imagem abaixo mostra o esquema deste soquete. Internamente está apenas ligado a VCC e GND.

Schematic for SD Card Socket
Esquema do Soquete para Cartão SD (source)

A interface SPI (SD_CS, SD_MOSI, SD_CLK) é acessível através dos pinos externos na parte de trás do módulo. Mas note que SD_MISO não está ligado:

Pinos SPI para o Soquete do Cartão SD

No entanto, não vamos usar o soquete do cartão SD neste tutorial.

Código para o Ecrã Tátil TFT ILI9341 com a Biblioteca TFT_eSPI

Nesta secção, vamos usar a TFT_eSPI library para controlar o ecrã e a interface tátil. Para install esta biblioteca, abre o Library Manager, procura por “TFT_eSPI” e clica em “INSTALL”. Após uma instalação bem-sucedida, deverá ficar assim:

TFT_eSPI library in Library Manager
Biblioteca TFT_eSPI no Library Manager

De seguida, precisamos criar a estrutura correta da pasta do projeto. Abre o Arduino IDE e cria um projeto “tft_test” e guarda-o (Guardar Como …). Isto criará uma pasta “tft_test” com o ficheiro “tft_test.ino” dentro. Nesta pasta, cria outro ficheiro chamado “tft_setup.h“. A pasta do teu projeto deverá ficar assim

Project Folder Structure
tft_test

Se quiseres aprender mais sobre esta configuração e outras opções para configurar um ecrã TFT para a biblioteca TFT_eSPI, dá uma vista de olhos ao tutorial How to configure TFT_eSPI Library for TFT display.

tft_setup.h para o Ecrã Tátil TFT ILI9341

Depois de criar a pasta do projeto com os dois ficheiros, copia o seguinte código de configuração para o ecrã TFT no ficheiro tft_setup.h:

// tft_setup.h
// 2.8" TFT Touch Display
// 240x 320, Driver: ILI9341 

#define ILI9341_DRIVER      
//#define ILI9341_2_DRIVER  

#define TFT_WIDTH  240
#define TFT_HEIGHT 320
#define TFT_RGB_ORDER TFT_BGR  

// WEMOLS Lolin32 lite
#define TFT_CS    5   
#define TFT_RST   17  
#define TFT_DC    16   
#define TFT_MOSI  23  // SDA // HW MOSI
#define TFT_SCLK  18  // SCL // HW SCLK
#define TFT_MISO  19  // HW MISO
#define TFT_BL    22  // LED back-light
#define TFT_BACKLIGHT_ON HIGH

#define TOUCH_CS 4 
#define TOUCH_CLK TFT_SCLK
#define TOUCH_DIN TFT_MOSI
#define TOUCH_DO TFT_MISO

#define LOAD_GLCD   
#define LOAD_FONT2  
#define LOAD_FONT4  
#define LOAD_FONT6  
#define LOAD_FONT7  
#define LOAD_FONT8  
#define LOAD_GFXFF
#define SMOOTH_FONT 

#define SPI_FREQUENCY  27000000
#define SPI_READ_FREQUENCY  20000000
#define SPI_TOUCH_FREQUENCY  2500000

A parte mais importante deste ficheiro de configuração é selecionar o driver correto do ecrã. No nosso caso, é o ILI9341. Note que existe uma definição alternativa:

#define ILI9341_DRIVER      
//#define ILI9341_2_DRIVER  

Se tiveres problemas com o teu ecrã, experimenta o ILI9341_2_DRIVER em vez do ILI9341_DRIVER.

Também são importantes as constantes para a largura e altura do ecrã e a ordem dos canais de cor.

#define TFT_WIDTH  240
#define TFT_HEIGHT 320
#define TFT_RGB_ORDER TFT_BGR  

Se o conteúdo aparecer cortado ou as cores estiverem erradas, certifica-te que tens as dimensões (TFT_WIDTH, TFT_HEIGHT) e a TFT_RGB_ORDER corretas. A TFT_RGB_ORDER pode ser TFT_BGR ou TFT_RGB.

Note que também existe uma definição para inverter preto e branco (#define TFT_INVERSION_ON), caso encontres esse problema. Para todas as definições possíveis, vê o ficheiro User_Setup.h.

De seguida temos as definições dos pinos. Estou a usar um WEMOS Lolin32 lite (ESP32) e os pinos para Hardware SPI são (MOSI=23, MSIO=19, SCK=18):

#define TFT_CS    5   
#define TFT_RST   17  
#define TFT_DC    16   
#define TFT_MOSI  23  // SDA // HW MOSI
#define TFT_SCLK  18  // SCL // HW SCLK
#define TFT_MISO  19  // HW MISO
#define TFT_BL    22  // LED back-light
#define TFT_BACKLIGHT_ON HIGH

#define TOUCH_CS 4 
#define TOUCH_CLK TFT_SCLK
#define TOUCH_DIN TFT_MOSI
#define TOUCH_DO TFT_MISO

Dependendo do teu microcontrolador, estes pinos podem ser diferentes. Deves encontrar e usar os pinos para Hardware SPI, pois permitem uma comunicação mais rápida e, portanto, um ecrã mais rápido. Os outros pinos podes escolher livremente.

As constantes para as fontes normalmente não precisas de alterar. No entanto, se ficares sem memória, podes remover fontes não usadas da lista.

#define LOAD_GLCD   
...
#define SMOOTH_FONT 

As constantes para SPI_FREQUENCY e SPI_TOUCH_FREQUENCY são algo críticas. Se forem muito altas, verás conteúdo distorcido e o reconhecimento do toque será instável. Os valores aqui funcionaram para mim, mas para outro microcontrolador ou ecrã podes ter de os reduzir.

#define SPI_FREQUENCY  27000000
#define SPI_READ_FREQUENCY  20000000
#define SPI_TOUCH_FREQUENCY  2500000

Código de teste para o Ecrã Tátil TFT ILI9341

Nesta secção, vou mostrar-te um código de teste que podes usar para experimentar o ecrã e a deteção de toque. Basta copiar o seguinte código para o ficheiro tft_test.ino:

// tft_test.ino
#include "tft_setup.h"
#include "TFT_eSPI.h"

TFT_eSPI tft = TFT_eSPI();
uint16_t cal[5] = { 0, 0, 0, 0, 0 };

void calibrate_touch() {
  if (!cal[1]) {
    tft.fillScreen(TFT_BLACK);
    tft.calibrateTouch(cal, TFT_YELLOW, TFT_BLACK, 20);
    Serial.printf("cal[5] = {%d, %d, %d, %d, %d};\n",
                  cal[0], cal[1], cal[2], cal[3], cal[4]);
  }
}

void setup(void) {
  Serial.begin(115200);

  tft.init();
  tft.setRotation(1);
  calibrate_touch();
  tft.setTouch(cal);

  tft.fillScreen(TFT_BLACK);
  tft.setTextFont(1);
  tft.setTextSize(2);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextDatum(CC_DATUM);
  tft.drawString("Makerguides", TFT_HEIGHT / 2, TFT_WIDTH / 2);
}

void loop() {
  uint16_t x, y;
  if (tft.getTouch(&x, &y)) {
    Serial.printf("%d %d\n", x, y);
    tft.fillCircle(x, y, 2, TFT_YELLOW);
  }
}

O código começa por incluir a biblioteca necessária e o ficheiro de configuração.

#include "tft_setup.h"
#include "TFT_eSPI.h"

De seguida, criamos o objeto do ecrã TFT e um array para guardar os parâmetros de calibração do ecrã tátil:

TFT_eSPI tft = TFT_eSPI();
uint16_t cal[5] = { 0, 0, 0, 0, 0 };

Função calibrate_touch

Inicialmente, os parâmetros de calibração estão definidos a zero, mas vamos preenchê-los mais tarde. A função calibrate_touch() é usada para obter estes parâmetros de calibração:

void calibrate_touch() {
  if (!cal[1]) {
    tft.fillScreen(TFT_BLACK);
    tft.calibrateTouch(cal, TFT_YELLOW, TFT_BLACK, 20);
    Serial.printf("cal[5] = {%d, %d, %d, %d, %d};\n",
                  cal[0], cal[1], cal[2], cal[3], cal[4]);
  }
}

Se ainda não estiverem definidos (!cal[1]), a função limpa o ecrã e depois chama tft.calibrateTouch(), que preenche o array cal. Esta função desenha setas (a amarelo com fundo preto e tamanho de 20 pixels) nos cantos do ecrã e o utilizador tem de tocar nos cantos para calibrar o ecrã. Falaremos mais sobre isto depois. Quando tivermos os parâmetros cal, imprimimos-nos no Monitor Serial.

Função setup

Na função setup() inicializamos o Monitor Serial e o ecrã TFT, calibramos o ecrã tátil se necessário e depois imprimimos o texto “Makerguides” no ecrã:

void setup(void) {
  Serial.begin(115200);

  tft.init();
  tft.setRotation(1);
  calibrate_touch();
  tft.setTouch(cal);

  tft.fillScreen(TFT_BLACK);
  ...
  tft.drawString("Makerguides", TFT_HEIGHT / 2, TFT_WIDTH / 2);
}

Função loop

Na função loop() chamamos getTouch para verificar se foi detetado toque. Se sim, imprimimos as coordenadas do toque no Monitor Serial e desenhamos um pequeno círculo amarelo no ponto do toque:

void loop() {
  uint16_t x, y;
  if (tft.getTouch(&x, &y)) {
    Serial.printf("%d %d\n", x, y);
    tft.fillCircle(x, y, 2, TFT_YELLOW);
  }
}

Controlo da Luz de Fundo

Finalmente, se quiseres desligar o LED da luz de fundo do ecrã para reduzir o consumo de energia quando o ecrã não estiver a ser usado, podes definir o pino TFT_BL para LOW:

pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, LOW);    // Switch off Backlight  

Não uso isto neste código, mas funciona. Pode ser útil para poupar energia ao colocar o ESP32 em deep-sleep e só acordar quando for detetado um toque.

Na próxima secção, vamos aprender a calibrar o ecrã tátil.

Calibração do Ecrã Tátil TFT ILI9341

Se carregares e executares o código, o ecrã iniciará em modo de calibração. Isto é necessário para calibrar o ecrã tátil para que a função tft.getTouch(&x, &y) retorne as coordenadas corretas do ecrã para um toque.

No modo de calibração, o ecrã mostra primeiro uma seta amarela no canto superior esquerdo. Usa a caneta e toca no ecrã no canto para onde a seta aponta. Nota que, se quiseres setas maiores/menores, ou de cor ou fundo diferente, podes alterar os parâmetros da função tft.calibrateTouch():

tft.calibrateTouch(cal, TFT_YELLOW, TFT_BLACK, 20);

Se o toque for registado com sucesso, o ecrã mostra uma seta no canto superior direito. Toca nesse canto e repete o processo até que os quatro cantos tenham sido tocados. A imagem abaixo mostra as quatro setas durante as quatro etapas do processo de calibração:

Calibração do Ecrã Tátil TFT ILI9341

Após o quarto toque, o ecrã mostrará o texto “Makerguides” no centro (sem setas):


End of calibration of TFT ILI9341 Touch Display
Fim da calibração do Ecrã Tátil TFT ILI9341

Mais importante, o código também imprime os parâmetros de calibração cal no Monitor Serial. Deverás ver uma impressão semelhante à seguinte:

cal[5] = {397, 3495, 294, 3495, 7};

Copia estes valores e substitui os parâmetros de calibração zero da constante cal (cal[5] = { 0, 0, 0, 0, 0 }) no sketch tft_test.ino pelos valores que viste no Monitor Serial:

// tft_test.ino

...

uint16_t cal[5] = {397, 3495, 294, 3495, 7};

void calibrate_touch() {
...

Depois compila e carrega o código novamente.

Detetar toques com o Ecrã Tátil TFT ILI9341

Quando os parâmetros cal estiverem definidos, o código vai saltar a etapa de calibração, imprimir diretamente “Makerguides” e estará pronto para detetar toques. Usa a tua caneta e um ponto amarelo deverá aparecer onde quer que toques no ecrã. Abaixo uma foto do ecrã enquanto experimento os toques:

Touch input on TFT ILI9341 Touch Display
Toque no Ecrã Tátil TFT ILI9341

Se os pontos amarelos aparecerem deslocados do local onde tocaste, a calibração está incorreta. Podes refazer a calibração definindo os parâmetros cal de volta a zero (cal[5] = { 0, 0, 0, 0, 0 }).

Note que o Monitor Serial imprime as coordenadas do toque detetado assim que a calibração está concluída. Podes usar isto para verificar a calibração ou para adicionar botões que respondam ao toque, por exemplo.

241 51
240 54
240 53
241 47
243 46
...

Vê o tutorial Digital Clock with CrowPanel 3.5″ ESP32 Display para um exemplo.

Conclusões

Neste tutorial aprendeste a controlar um ecrã tátil TFT ILI9341 de 2,8 polegadas com resolução 240×320 usando um WEMOS Lolin32 lite (ESP32) e a biblioteca TFT_eSPI.

Se tiveres dificuldades com a biblioteca TFT_eSPI, o nosso How to configure TFT_eSPI Library for TFT display pode ajudar. Existe também uma longa discussão here sobre problemas com este ecrã específico.

Se tiveres um ecrã diferente com um driver ST7735 ou quiseres aprender a usar a Biblioteca Adafruit, o Interface TFT ST7735 Display with ESP32 tutorial pode ser útil para ti.

E para ecrãs TFT redondos, dá uma vista de olhos ao tutorial Digital Clock on CrowPanel 1.28″ Round Display.

Se tiveres algum comentário, sente-te à vontade para deixar na secção de comentários.

Boas experiências a criar ; )