Problème de rafraichissement d'un écran tft

Bonjour,
J'ai pour projet de piloter un funiculaire (celui de Montmartre pour être précis) et de gérer les commandes via un écran TFT Elegoo tactile 320x240 connecté à une mega 2560 de chez AZ_Delivry.
Pour débuter, je veux faire une animation avec une ligne verticale sur laquelle se déplace un triangle pour représenter le mouvement du funiculaire. J'ai 2 boutons, un start qui lance le mouvement, un stop qui l'arrête. Le mouvement doit se répéter dans une boucle pour visualiser au mieux ce qui doit se passer en réalité.
Mon problème est que, même si la boucle s'effectue correctement (semble-t-il) l'affichage n'efface jamais le premier passage et donc on ne voit pas le mouvement se répéter. Je ne comprends pas ce qui dysfonctionne et comme je cherche depuis quelques heures, je pense que je ne vois pas ce qui pourrait vous paraître évident.
Merci pour votre aide
Cordialement.
Voici mon code, pour les branchements, l'écran est simplement placé sur la carte Mega

#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <TouchScreen.h>

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0

#define LCD_RESET A4

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF


#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//Touch For New ILI9341 TP
#define TS_MINX 150
#define TS_MAXX 920

#define TS_MINY 150
#define TS_MAXY 920

// We have a status line for like, is FONA working
//#define STATUS_X 10
//#define STATUS_Y 65
//#define SUPPORT_8347D
#define MINPRESSURE 10
#define MAXPRESSURE 1000



Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

boolean boutonstart = true;     //valeur du bouton start 
boolean boutonstop = false;     //valeur du bouton stop 
int j = 50;                     //compteur pour la boucle de la fleche descendante

void setup() {
  Serial.begin(9600);
  Serial.println("Starting...");

  tft.reset();
  uint16_t identifier = 0x9341;

  tft.begin(identifier);
  tft.setRotation(3);

  tft.fillScreen(BLACK); //ecrab noir debut

  tft.drawRect(0, 0, 319, 240, WHITE);  //dessin d'un rectangle général
  tft.fillRect(0, 0, 319, 240, BLACK);  //dessin d'un rectangle général
  //Print "Bienvenue" Text
  tft.setCursor(156, 30);         //position du texte
  tft.setTextColor(WHITE);        //couleur du texte
  tft.setTextSize(2);             //taille du texte
  tft.print("Bienvenue");         //texte affich
  bstartp();                      //dessin du bouton start
  bstopp();                       //dessin du bouton stop
}
  void bstartp() {
// bouton Start en bleu
      tft.fillRect(100, 50, 70, 25, BLUE);
      tft.drawRect(100, 50, 70, 25, WHITE);
      tft.setCursor(105, 55); //largeur, hauteur
      tft.setTextColor(WHITE);
      tft.setTextSize(2);
      tft.print("Start");
      delay(10);
  }
  void bstopp() {
// bouton Stop en rouge
      tft.fillRect(200, 50, 70, 25, RED);
      tft.drawRect(200, 50, 70, 25, WHITE);
      tft.setCursor(205, 55); //largeur, hauteur
      tft.setTextColor(BLACK);
      tft.setTextSize(2);
      tft.print("Stop");
      delay(10);
  }
  void fleb(int k){
// mouvement de la fleche descendante 
    Serial.println(" fleb efface");
    j = k;
    while (j<=80) {
    Serial.print(j);
    Serial.println(" fleb ");
      tft.fillRect(45, 50, 11, 100, BLACK);         // x,y,w,h
      tft.drawFastVLine(50,50,100,WHITE);           // x,y,h
      tft.drawTriangle(45,j,55,j,50,j+5,WHITE);  // x0,y0,x1,y1,x2,y2
      delay(10);
      j = j + 5;
    }
    Serial.println(" fin fleb ");
  }
  void flebs(){
      tft.fillRect(45, 50, 11, 100, BLACK);         // x,y,w,h
      tft.drawFastVLine(50,50,100,RED);           // x,y,h
      tft.drawTriangle(45,50,55,50,50,55,RED);  // x0,y0,x1,y1,x2,y2
  }

void loop()
{
  if (boutonstart == 1) {
    tft.fillRect(45, 50, 11, 100, WHITE);         // x,y,w,h
      delay(10);
    fleb(50);
  }
  if (boutonstart == 0) {
    flebs();
  }
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);
  if(p.z > MINPRESSURE && p.z < MAXPRESSURE)
  {                                  // touch press? 
//    X=p.x, Y=p.y;                                                       // analyse si appui dans la touche
    p.x = map(p.x, TS_MAXX, TS_MINX, 320, 0);
    p.y = map(p.y, TS_MAXY, TS_MINY, 240, 0);
//    Z = map(p.z, 0, 1000, 0, 10);
    Serial.print("Boutonstart = ");
    Serial.print(boutonstart);
    Serial.print(" large ");
    Serial.print(tft.width());
    Serial.print(" haut ");
    Serial.print(tft.height());
    Serial.print(" , X=");
    Serial.print(p.x);
    Serial.print(" , Y=");
    Serial.println(p.y);
    if (p.x >= 57 && p.x <= 100 && p.y >= 68 && p.y <= 100){
      boutonstop = false;
      boutonstart = true;
    Serial.println(" bstart ");
    }
    if (p.x >= 57 && p.x <= 100 && p.y >= 100 && p.y <= 200){
      boutonstart = false;
      boutonstop = true;
    Serial.println(" bstop ");
    }
    p.x = 0;
    p.y = 0;
  }
}

J'ai ajouté pinMode(YP, OUTPUT) et pinMode(XM, OUTPUT) après le TSPoint et ça marche mieux, mais ça clignote. Ne peut-on pas superposer un rectangle noir sur une zone de l'écran pour effacer ce qu'il y en a dessous sans faire ces pinMode ?

Les pinMode sont faits dans la bibliothèque, pas besoin de les mettre dans ton code.
Exemple :

Donc, je pense que la solution n'est pas là.

Lorsque tu veux déplacer un objet sur un écran, il faut l'effacer à son ancienne position, puis l'afficher à sa nouvelle position. Pour effacer, tu traces, par exemple, un rectangle englobant la forme, de la couleur du fond (s'il est homogène, ce qui est souvent le cas).

Merci lesept pour cette réponse. Mais, l'effacement par un sur-rectangle sans le pinmode ne fonctionne pas. Les lignes 100; 137 et 142 devraient effacer la ligne verticale et le bouton, mais ca ne fonctionne pas sans ces pinmode.
Soit cette syntaxe est obligatoire pour un réaffichage soit je me goure quelque part.
Re voici mon nouveau code :

#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <TouchScreen.h>

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0

#define LCD_RESET A4

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF


#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//Touch For New ILI9341 TP
#define TS_MINX 150
#define TS_MAXX 920

#define TS_MINY 150
#define TS_MAXY 920

// We have a status line for like, is FONA working
//#define STATUS_X 10
//#define STATUS_Y 65
//#define SUPPORT_8347D
#define MINPRESSURE 10
#define MAXPRESSURE 1000



Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

boolean boutonstart = true;     //valeur du bouton start 
boolean boutonstop = false;     //valeur du bouton stop 
int j = 50;                     //compteur pour la boucle de la fleche descendante
int X, Y;

void setup() {
  Serial.begin(9600);
  Serial.println("Starting...");

  tft.reset();
  uint16_t identifier = 0x9341;

  tft.begin(identifier);
  tft.setRotation(3);

  tft.fillScreen(BLACK); //ecrab noir debut

  tft.drawRect(0, 0, 319, 240, WHITE);  //dessin d'un rectangle général
  tft.fillRect(0, 0, 319, 240, BLACK);  //dessin d'un rectangle général
  //Print "Bienvenue" Text
  tft.setCursor(156, 30);         //position du texte
  tft.setTextColor(WHITE);        //couleur du texte
  tft.setTextSize(2);             //taille du texte
  tft.print("Bienvenue");         //texte affich
//  bstartp();                      //dessin du bouton start
//  bstopp();                       //dessin du bouton stop
    Serial.print(" large ");
    Serial.print(tft.width());
    Serial.print(" haut ");
    Serial.println(tft.height());
}
  void bstartp() {
// bouton Start en bleu
      tft.fillRect(100, 50, 70, 25, BLUE);
      tft.drawRect(100, 50, 70, 25, WHITE);
      tft.setCursor(105, 55); //largeur, hauteur
      tft.setTextColor(WHITE);
      tft.setTextSize(2);
      tft.print("Start");
//      delay(10);
  }
  void bstopp() {
// bouton Stop en rouge
      tft.fillRect(100, 50, 70, 25, RED);
      tft.drawRect(100, 50, 70, 25, WHITE);
      tft.setCursor(105, 55); //largeur, hauteur
      tft.setTextColor(BLACK);
      tft.setTextSize(2);
      tft.print("Stop");
  }
  void fleb(int k){
// mouvement de la fleche descendante 
    j = k;
    while (j<=120) {
      tft.fillRect(45, 50, 11, 100, BLACK);         // x,y,w,h
      tft.drawFastVLine(50,50,100,WHITE);           // x,y,h
      tft.drawTriangle(45,j,55,j,50,j+5,WHITE);  // x0,y0,x1,y1,x2,y2
      delay(10);
      j = j + 5;
    }
  }
  void flebs(){
      tft.fillRect(45, 50, 11, 100, BLACK);         // x,y,w,h
      tft.drawFastVLine(50,50,100,WHITE);           // x,y,h
      tft.drawTriangle(45,50,55,50,50,60,WHITE);  // x0,y0,x1,y1,x2,y2
  }

void loop()
{
  if (boutonstart == 1) {
    bstopp();
    fleb(50);
  }
  if (boutonstart == 0) {
    bstartp();
    flebs();
  }
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
//  pinMode(YP, OUTPUT);
//  pinMode(XM, OUTPUT);
  digitalWrite(13, LOW);
  if(p.z > MINPRESSURE && p.z < MAXPRESSURE)
  {                                  // touch press? 
    p.x = map(p.x, TS_MAXX, TS_MINX, 320, 0);
    p.y = map(p.y, TS_MAXY, TS_MINY, 240, 0);
    if (p.x >= 57 && p.x <= 100 && p.y >= 68 && p.y <= 100 && p.x != X && p.y != Y){
      X = p.x;
      Y = p.y;
      if(!boutonstart) {
        boutonstart = true;
        tft.fillRect(100, 50, 70, 25, BLACK);
        Serial.println(" bstop ");
      }
      else if(boutonstart){
        boutonstart = false;
        tft.fillRect(100, 50, 70, 25, BLACK);
        Serial.println(" bstart ");
      }
    }

    Serial.print("Boutonstart = ");
    Serial.print(boutonstart);
    Serial.print(" , X=");
    Serial.print(p.x);
    Serial.print(" , Y=");
    Serial.println(p.y);
    p.x = 0;
    p.y = 0;
    delay(10);
  }
}

Je persiste : les pinmode ne servent à rien. La preuve, il n'y en a aucun dans les exemples de la bibliothèque

Tu veux dire que sans pinmode, ça n'efface pas et avec pinmode ça efface (toutes choses égales par ailleurs) ?

Essaye de changer la couleur de tes fillRect, en utilisant une couleur que tu n'utilise nulle part ailleurs. Qu'est-ce que ça donne ?

Je confirme que même en mettant des couleurs inutilisées ailleurs, sans les pinmode aucun écrasement/effacement.
Dans de nombreux exemples glanés ici et là, et dans les exemples fournis par Elegoo avec la carte, les TSPoint est systématiquement suivi des pinmode.
C'est bien la librairie TouchScreen qui est utilisée pour ces opérations d'affichage sur l'écran ? Donc, elle est parfaitement standard et pas modifiée par le fabricant comme peuvent l'être les librairies Elegoo_GFX.h et Elegoo_TFTLCD.h.
J'en perds mon latin (qui est déjà d'un niveau extrêmement bas).
Merci pour ton aide en tous cas.

Je n'ai pas essayé avec une carte UNI R3. Je ferai ce test demain.

Non, cette bibliothèque sert à gérer l'écran tactile : elle vérifie que l'écran et touché et te fournit les coordonnées et la pression exercée.

C'est la combinaison de ces deux bibliothèques qui fait l'affichage. Elegoo_GFX fournit des primitives génériques, Elegoo_TFTLCD est spécifique aux écrans TFT.

Cette ligne déclare ton écran, pour l'affichage

Celle-ci déclare le tactile.

Peux-tu faire une code le plus simple possible, sans les pinmode, qui teste l'effacement ?

Par exemple, tu conserve uniquement l'affichage du message dans le setup et tu l'effaces au bout de 3 secondes.

#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <TouchScreen.h>

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0

#define LCD_RESET A4

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF


#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//Touch For New ILI9341 TP
#define TS_MINX 150
#define TS_MAXX 920

#define TS_MINY 150
#define TS_MAXY 920

#define MINPRESSURE 10
#define MAXPRESSURE 1000

Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

int X, Y;

void setup() {
  Serial.begin(9600);
  Serial.println("Starting...");

  tft.reset();
  uint16_t identifier = 0x9341;

  tft.begin(identifier);
  tft.setRotation(3);

  tft.fillScreen(BLACK); //ecran noir debut

  //Print "Bienvenue" Text
  tft.setCursor(156, 30);         //position du texte
  tft.setTextColor(WHITE);        //couleur du texte
  tft.setTextSize(2);             //taille du texte
  tft.print("Bienvenue");         //texte affich
  
  delay(3000);
  tft.fillRect(150, 30, 100, 30, BLACK);
}


void loop()
{
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
//  pinMode(YP, OUTPUT);
//  pinMode(XM, OUTPUT);
  digitalWrite(13, LOW);
  if(p.z > MINPRESSURE && p.z < MAXPRESSURE)
  {                                  // touch press? 
    p.x = map(p.x, TS_MAXX, TS_MINX, 320, 0);
    p.y = map(p.y, TS_MAXY, TS_MINY, 240, 0);
	
	tft.fillCircle(p.x, p.y, 3, RED);
	delay(2000);
	tft.fillCircle(p.x, p.y, 3, BLACK);
  }
}

Ce code va afficher un message d'accueil pendant 3 secondes, puis effacer un rectangle (j'ai mis les dimensions au hasard, donc pas sûr que ça efface le message entier). Puis il attend que tu appuies sur l'écran et trace un cercle rouge à l'endroit où tu as appuyé. Il l'efface au bout de 2 secondes.

Est-ce que ça marche (pas testé, bien sûr) ?

Oui mais en fait, c'est lié à l'utilisation de l'écran tactile. Il semblerait que D8 et D9 soient partagées entre le driver d'écran (bit 0 et 1 du bus de données) et l'écran tactile.

On trouve ces lignes dans le programme d'exemple nommé tftpaint qui justement utilise l'écran tactile

  // if sharing pins, you'll need to fix the directions of the touchscreen pins
  //pinMode(XP, OUTPUT);
  pinMode(XM, OUTPUT);
  pinMode(YP, OUTPUT);
  //pinMode(YM, OUTPUT);

Oui, j'avais vu ces lignes uniquement dans cet exemple, mais je ne voyais pas à quoi elles servaient

Je viens de faire cet essai simplifié, voici mes constatations, je vais essayer d'être clair :

  • Sans modification du programme, l'affichage du message est OK et son effacement partiel OK mais dès qu'il arrive sur la boucle, un écran blanc affichage du point rouge mais les x, y et z sont bien validés dans un print de contrôle.
  • J'ai ajouté dans la boucle générale, un nouveau message et nouvel effacement. Même constat.
  • J'ai enlevé les commentaires sur les pinmode et la boucle fonctionne, le print rend bien les x, y et z mais pas de point rouge sur l'écran.
  • J'enlève le reaffichage du message dans la boucle et là tout est OK sauf l'affichage du point rouge qui n'est pas placé là où j'ai appuyé. Ceci est un autre problème que je vais vérifier avant de revenir vers vous.

J'ai trouvé un topics sur le forum qui indique qu'il faut toujours faire le pinmode après un tspoint, voici le lien
Merci encore à vous deux

Alors quelle est la conclusion ?
On dirait que les pinmode ne doivent pas être exécutés.

Deux choses étranges :

  • Ecran blanc dans la loop
  • La différence entre les deux derniers points est bizarre.

Conclusion partielle.
Je pense que les pi mode sont obligatoires des qu’il y a « touch ».
Pour le positionnement je cherche et j’avance à petits pas surtout quand il y a rotation de l’affichage. Je vous tiens au courant de mes résultats quand je les maîtriserai.

C'est cette instruction pour gérer la rotation de l'affichage

Le problème est que la rotation agit correctement sur l'affichage, mais ne réagit pas correctement sur les pressions. Il faut donc trouver une configuration de l'écran et du mappage qui puisse fonctionner pour chaque position de rotation. Je m'occupe de cela cet après-midi et vous tiens au courant.

Ca pourrait expliquer qu'il n'y a pas toujours de point rouge, si la coordonnée est supérieure à la valeur max (240)

Regarde ici si ça t'apporte une solution :
https://forums.adafruit.com/viewtopic.php?t=112504

En effet ça explique totalement.
Le lien que tu proposes semble très intéressant. Je vais essayer d’ici la fin de l’après midi et je te tiens au courant

Voilà le résultat de mes tests, sur la rotation de l'affichage et le mappage qu'il faut associer pour avoir la bonne position du pointeur. Avec les inversions X et Y.

#include <Elegoo_GFX.h>
#include <Elegoo_TFTLCD.h>
#include <TouchScreen.h>

#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0

#define LCD_RESET A4

#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF


#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 9   // can be a digital pin
#define XP 8   // can be a digital pin

//Touch For New ILI9341 TP
#define TS_MINX 120
#define TS_MAXX 940

#define TS_MINY 75
#define TS_MAXY 920

#define MINPRESSURE 10
#define MAXPRESSURE 1000

Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

int x, y;
int minX = 1023, maxX = 0, minY = 1023, maxY = 0;
byte rotation = 2; //(0->3)

void setup() {
  Serial.begin(9600);
  Serial.println("Starting...");

  tft.reset();
  uint16_t identifier = 0x9341;

  tft.begin(identifier);
  tft.setRotation(rotation);
    Serial.print(" large ");
    Serial.print(tft.width());
    Serial.print(" haut ");
    Serial.println(tft.height());

  tft.fillScreen(BLACK); //ecran noir debut

  tft.setCursor(10, 30);         //position du texte
  tft.setTextColor(WHITE);        //couleur du texte
  tft.setTextSize(2);             //taille du texte
  tft.print("rotation ");         //texte affich
  tft.println(rotation);         //texte affich
  tft.print(" largeur ");         //texte affich
  tft.print(tft.width());         //texte affich
  tft.print(" hauteur ");         //texte affich
  tft.print(tft.height());         //texte affich
}


void loop()
{
  x = 0;
  y = 0;
  digitalWrite(13, HIGH);
  TSPoint p = ts.getPoint();
  digitalWrite(13, LOW);
  pinMode(YP, OUTPUT);
  pinMode(XM, OUTPUT);

  if(p.z > MINPRESSURE && p.z < MAXPRESSURE)
  {                                  // touch press? 
 switch (rotation){
  case 0:
    x = (tft.width()-map(p.x, TS_MINX, TS_MAXX, tft.width(), 0));
    y = map(p.y, TS_MINY, TS_MAXY, tft.height(), 0);
  break;
 case 1:
    x = (map(p.y, TS_MINY, TS_MAXY, tft.width(), 0));
    y = (map(p.x, TS_MINX, TS_MAXX, tft.height(), 0));
   break;
 case 2:
    x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
    y = (tft.height()-map(p.y, TS_MINY, TS_MAXY, tft.height(), 0));
  break;
 case 3:
 //  p.x, p.y reversed //
    y = (tft.height()-map(p.x, TS_MINX, TS_MAXX, tft.height(), 0));
    x = (tft.width()-map(p.y, TS_MINY, TS_MAXY, tft.width(), 0));
  break;
 }
  Serial.print("z = ");
  Serial.print(p.z);
  Serial.print("  x = ");
  Serial.print(x);
  Serial.print("  y = ");
  Serial.println(y);
  Serial.print("  p.x = ");
  Serial.print(p.x);
  Serial.print("  p.y = ");
  Serial.println(p.y);
	
	  tft.fillCircle(x, y, 3, RED);
	  delay(1000);
	  tft.fillCircle(x, y, 3, BLACK);
  }
}

Description du matériel :

  • Carte TFT Elegoo 320*240
  • Arduino MEGA 2560

Ce ne sont pas tout à fait les codes présentés dans le lien proposé ci-dessus et ce ne sont pas les mêmes librairies. Mais ceci fonctionne avec mon matériel.
J'espère que cela pourra servir à quelqu'un.
Merci encore à ceux qui m'ont aidé sur ce sujet.

Merci pour le partage. Les pinMode peuvent aller dans le setup.