dimanche 16 mai 2021

Utilisation d'un écran tactile TFT SPI 240 X 320 (ILI9341) avec un ESP32

Dans ce tuto, nous branchons à un ESP32 un écran tactile SPI 240 X 320 comportant le contrôleur ILI9341. L'ESP32 sera programmé au moyen de l'IDE Arduino.


Connexions de l'écran à l'ESP32

Mon écran est muni d'un lecteur de carte SD que je n'utiliserai pas pour l'instant. Ça nous laisse tout de même 18 broches qui servent à l'alimentation, à l'affichage et au capteur tactile.


Voici comment j'ai branché l'écran à mon module ESP32:

  • Broche VCC de l'écran: sortie 3,3 V de l'ESP32
  • Broche GND de l'écran: broche GND de l'ESP32
  • Broche CS de l'écran: broche D15 de l'ESP32
  • Broche Reset de l'écran: broche D4 de l'ESP32
  • Broche DC de l'écran: broche D5 de l'ESP32
  • Broche SDI (MOSI) de l'écran: broche D23 de l'ESP32
  • Broche SCK de l'écran: broche D18 de l'ESP32
  • Broche LED de l'écran: sortie 3,3 V de l'ESP32
  • Broche CDCK (MISO) de l'écran: broche D19 de l'ESP32
  • Broche T_CLK de l'écran: broche D18 de l'ESP32
  • Broche T_CS de l'écran: broche D21 de l'ESP32
  • Broche T_DIN de l'écran: broche D23 de l'ESP32
  • Broche T_DO de l'écran: broche D19 de l'ESP32
  • Broche T_IRQ de l'écran: pas branchée

Installation de la bibliothèque TFT_eSPI

La bibliothèque TFT_eSPI de Bodmer peut être installée au moyen du gestionnaire de bibliothèques de l'IDE Arduino.


Configuration de la bibliothèque TFT_eSPI (fichier User_Setup)

Puisque la bibliothèque TFT_eSPI est compatible avec un grand nombre d'écrans TFT et avec plusieurs microcontrôleurs, il est nécessaire de régler certaines informations dans un fichier de démarrage avant de pouvoir l'utiliser.  Un grand nombre de fichiers prêts à l'emploi se trouvent dans le dossier "User_Setups", qui se trouve lui-même à l'intérieur du dossier de la bibliothèque TFT_eSPI (dans votre Sketchbook Arduino). 

Malheureusement, le dossier ne comporte pas de fichier conçu pour l'utilisation d'un ILI9341 avec un ESP32, et j'en ai donc écrit un (voir ci-dessous). Ce fichier devrait être enregistré dans le dossier User_Setups sous le nom "Setup_ILI9341_ESP32.h"

-
/*******************************************************************
Fichier "user_setup" pour l'utilisation d'un écran tactile ILI9341
avec un ESP32, avec la bibliothèque TFT_eSPI de Bodmer.
*******************************************************************/
#define ILI9341_DRIVER
#define TFT_CS 15 // Chip select broche D15
#define TFT_DC 5 // Data Command broche D5
#define TFT_RST 4 // Reset broche D4
#define TFT_MOSI 23 // SPI MOSI broche D23
#define TFT_SCLK 18 // SPI SCLK broche D18
#define TOUCH_CS 19 // Touch Screen Chip select pin broche D19
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:.
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
#define SMOOTH_FONT
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 20000000
#define SPI_TOUCH_FREQUENCY 2500000
-

Après avoir copié le fichier ci-dessous dans le dossier User_Setups sous le nom "Setup_ILI9341_ESP32.h" , il faut également ouvrir le fichier User_Setup_Select.h, commenter la ligne 22 (pour la désactiver), et ajouter cette directive:

#include <User_Setup/Setup_ILI9341_ESP32.h>


Si plus tard vous désirez utiliser la bibliothèque TFT_eSPI avec un autre écran ou avec un autre microcontrôleur, il s'agira d'utiliser un fichier de configuration différent.

Sketch #1: Deux boutons

Je vous présente ici les deux mêmes sketches que j'avais utilisés avec un ESP8266 et un STM32. Dans ce premier exemple, l'écran affiche deux boutons: un premier bouton fait apparaître un rectangle, alors que l'autre fait apparaître un cercle. En  plus d'illustrer la gestion des boutons, cet exemple montre comment tracer à l'écran des formes géométriques simples.


-
/*
Démonstration d'écran tactile à deux "boutons"
TFT SPI 2.4" 320 X 240 pixels
Plus d'infos:
https://electroniqueamateur.blogspot.com/2021/04/utilisation-dun-ecran-tactile-tft-spi.html
*/
#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI(); // https://github.com/Bodmer/TFT_eSPI
// Création de 2 objets boutons
#define NOMBRE_BOUTONS 2
TFT_eSPI_Button bouton[NOMBRE_BOUTONS];
void setup() {
tft.init();
tft.setRotation(3); // portrait: 0 ou 2, paysage: 1 ou 3.
touch_calibrate(); // procédure de calibration de l'écran tactile
// affichage d'un message à l'écran:
tft.fillScreen(TFT_BLACK); // on efface tout (fond noir)
tft.setFreeFont(&FreeSansOblique12pt7b); // police de caractère
tft.setCursor(20, 70); // position du début du message
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println("Choisissez la forme desiree");
// création de deux boutons
// premier bouton: son centre est positionné à x = 80 et y = 200, largeur 120,
// hauteur 50, contour en noir, remplissage rouge, texte en blanc, taille de texte 1.
bouton[0].initButton(&tft, 80, 200, 120, 50, TFT_BLACK, TFT_RED, TFT_WHITE, "rectangle", 1);
bouton[0].drawButton();
// deuxième bouton: son centre est positionné à x = 250 et y = 200, largeur 120,
// hauteur 50, contour en noir, remplissage vert, texte en noir, taille de texte 1.
bouton[1].initButton(&tft, 250, 200, 120, 50, TFT_BLACK, TFT_GREEN, TFT_BLACK, "cercle", 1);
bouton[1].drawButton();
}
//------------------------------------------------------------------------------------------
void loop(void) {
uint16_t t_x = 0, t_y = 0; // coordonnées touchées par l'utilisateur
boolean pressed = tft.getTouch(&t_x, &t_y); // vrai si contact avec l'écran
// On vérifie si la position du contact correspond à celle d'un bouton
for (uint8_t numero = 0; numero < NOMBRE_BOUTONS; numero++) {
if (pressed && bouton[numero].contains(t_x, t_y)) {
bouton[numero].press(true);
} else {
bouton[numero].press(false);
}
}
// Vérifions maintenant si l'état d'un des boutons a changé
for (uint8_t numero = 0; numero < NOMBRE_BOUTONS; numero++) {
// si le bouton vient d'être relâché, on le redessine avec sa forme normale
if (bouton[numero].justReleased()) {
bouton[numero].drawButton();
}
// si le bouton vient d'être pressé...
if (bouton[numero].justPressed()) {
bouton[numero].drawButton(true); // on le redessine avec les couleurs inversées
// ...puis on fait ce que l'utilisateur a demandé:
switch (numero) {
case 0: // premier bouton
tft.fillRect(0, 0, 320, 160, TFT_BLACK); // pour effacer le dessin précédent
tft.fillRect(60, 30, 200, 100, TFT_CYAN); // rectangle 200 de largeur et 100 de hauteur
break;
case 1: // deuxième bouton
tft.fillRect(0, 0, 320, 160, TFT_BLACK); // pour effacer le dessin précédent
tft.fillCircle(160, 80, 50, TFT_YELLOW); // cercle centré à x = 160 et y = 80
break;
}
delay(10); // anti-rebond
}
}
}
// procédure de calibration de l'écran tactile
void touch_calibrate()
{
uint16_t calData[5];
uint8_t calDataOK = 0;
tft.fillScreen(TFT_BLACK);
tft.setCursor(25, 70);
tft.setTextFont(2);
tft.setTextSize(2);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println("Touchez l'ecran a ");
tft.setCursor(15, 110);
tft.println("chaque coin indique.");
tft.setTextFont(1);
tft.println();
tft.calibrateTouch(calData, TFT_YELLOW, TFT_BLACK, 20);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.println("Calibration terminee!");
}
-

Sketch #2: Bouton coulissant

Dans ce deuxième exemple, l'écran affiche un bouton coulissant qui contrôle une valeur numérique située entre 0 et 100. Ça pourrait être utilisé pour contrôler la vitesse d'un moteur, la luminosité d'une LED, etc.


-
/***************************************************************************
Bouton coulissant sur un écran tactile TFT SPI 2.4" 320 X 240 pixels
Pour plus d'infos:
https://electroniqueamateur.blogspot.com/2021/04/utilisation-dun-ecran-tactile-tft-spi_25.html
******************************************************************************/
#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI(); // https://github.com/Bodmer/TFT_eSPI
#define VALEUR_MAX 100 // valeur affichée quand le bouton est poussé à l'extrême droite
#define LARGEUR 20 // largeur du bouton
#define HAUTEUR 40 // hauteur du bouton
#define POSY 150 // position verticale du bouton coulissant
#define LIMITE_GAUCHE 30 // extrémité gauche au 20e pixel
#define LIMITE_DROITE 290 // extrémité droite au 100e pixel
uint16_t x_precedent = 160 ; // position horizontale précédemment touchée (160 est le centre de l'écran)
// routine qui redessine le contenu de l'écran
void dessineContenu(uint16_t posx) {
uint16_t postxt;
// on ne permet pas que le bouton dépasse les limites établies
if (posx < LIMITE_GAUCHE) {
posx = LIMITE_GAUCHE;
}
if (posx > LIMITE_DROITE) {
posx = LIMITE_DROITE;
}
// on efface le bouton, là où il se trouvait précédemment
tft.fillRect(x_precedent - LARGEUR / 2, POSY - HAUTEUR / 2 - 2 , LARGEUR, HAUTEUR + 4, TFT_BLACK);
// on dessine la ligne horizontale
tft.drawLine(LIMITE_GAUCHE, POSY, LIMITE_DROITE, POSY, TFT_WHITE);
// on dessine le bouton à sa nouvelle position
tft.fillRect(posx - LARGEUR / 2, POSY - HAUTEUR / 2, LARGEUR, HAUTEUR, TFT_YELLOW);
// on efface l'ancienne valeur numérique
postxt = 90;
tft.setTextColor(TFT_BLACK);
postxt += tft.drawFloat(calcule_valeur(x_precedent), 1, postxt, 50, 4);
// on écrit la nouvelle valeur numérique
postxt = 90;
tft.setTextColor(TFT_GREEN);
postxt += tft.drawFloat(calcule_valeur(posx), 1, postxt, 50, 4);
x_precedent = posx;
}
// routine qui calcule la valeur numérique qui correspond à la position du bouton coulissant
float calcule_valeur (uint16_t valeur_brute) {
float valeur_convertie;
valeur_convertie = 1.0 * (valeur_brute - LIMITE_GAUCHE) / ( LIMITE_DROITE - LIMITE_GAUCHE) * VALEUR_MAX;
return valeur_convertie;
}
void setup() {
tft.init();
tft.setRotation(3); // portrait: 0 ou 2, paysage: 1 ou 3.
touch_calibrate(); // procédure de calibration de l'écran tactile
tft.fillScreen(TFT_BLACK); // on efface tout (fond noir)
dessineContenu(160);
}
void loop(void) {
uint16_t t_x = 0, t_y = 0; // coordonnées touchées par l'utilisateur
boolean pressed = tft.getTouch(&t_x, &t_y); // vrai si contact avec l'écran
if (pressed) { // si on touche l'écran
if (t_x != x_precedent) { // si on a changé de position
dessineContenu(t_x);
}
}
}
// procédure de calibration de l'écran tactile
void touch_calibrate()
{
uint16_t calData[5];
uint8_t calDataOK = 0;
tft.fillScreen(TFT_BLACK);
tft.setCursor(25, 70);
tft.setTextFont(2);
tft.setTextSize(2);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println("Touchez l'ecran a ");
tft.setCursor(15, 110);
tft.println("chaque coin indique.");
tft.setTextFont(1);
tft.println();
tft.calibrateTouch(calData, TFT_YELLOW, TFT_BLACK, 20);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.println("Calibration terminee!");
}
-

Bien entendu, de nombreux autres exemples sont inclus avec la bibliothèque TFT_eSPI.


À lire également

Yves Pelletier (Facebook)


6 commentaires:

  1. Merci pour ce tutoriel. J'avais quelques soucis avec la partie tactile. J'ai modifié dans le User Setup
    TOUCH_CS 21 et non pas 19 (19 c'est MISO)
    puis car ça ne fonctionnait toujours pas
    #define SPI_FREQUENCY 5000000
    #define SPI_READ_FREQUENCY 5000000

    5000000 au lieu de 40000000
    Maintenant ça fonctionne en tout cas sur ESP-WROOM-32

    RépondreSupprimer
    Réponses
    1. Merci. Grâce à votre commentaire, j'ai également réussi à faire fonctionner la partie tactile.

      Supprimer
  2. class TFT_eSPI' has no member named 'getTouch. Des messages en cascade s'enchaînent. Il serait peut-être utile de détailler la manipulation de la modification de la bibliothèque.

    RépondreSupprimer
  3. Bonjour, j'ai un lecteur TFT SPFD5408 qui est similaire au votre mais je ne sais pas comment le câbler au ESP32 car les branches n'ont simplement pas le même nom. Pouvez vous m'aider ? Si vous ne voyez pas bien à quoi il ressemble voici une ref :https://www.azde.ly/fr/products/2-4-tft-lcd-touch-display

    RépondreSupprimer
    Réponses
    1. slt j'ai le même probleme j'essai de relier mon ecrans au esp32 flasher avec marauder pour mon flipper zero, mais les broches n'ont pas toutes le même nom, mais si on va dans la logique, tu remplace LED (du tuto) par BL_EN (sur le tiens) et SCK par SCL
      moi c'est comme ca... mais je ne parviens tout de même pas a afficher le programme dedans (marauder)

      Supprimer
  4. Bonjour, comment commander par les boutons le Brightness du ILI9341 ? Merci pour votre reponse

    RépondreSupprimer