Affichage ecran LCD + PROGMEM

Bonjour,
Je souhaite afficher un message ( 'uwu_0') qui défile sur un écran LCD. Cependant, le problème est que le message s'affiche en boucle alors qu'il se trouve dans la partie setup.
De plus je suis contrainte d'utiliser PROGMEM car les variables globales occupent trop d'espace en mémoire.
Pouvez-vous m'aider, svp ?"

#include <LiquidCrystal.h>
#include <String.h>
#include <Wire.h>
#include <HT16K33.h>
#include <avr/pgmspace.h>

#define LED 2
#define BUTTON A1


HT16K33 seg(0x70);              //Crée un objet
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);  //Pins où on va connecter l'écran (RS, E, D4, D5, D6, D7)

char temp_string[27];
const char uwu_0[] PROGMEM = {"   Jeu pour apprendre les departements francais. CONSIGNE: Vous avez 3 secondes pour deviner le nom du departement qui s'affiche. Appuyer sur le bouton de la LED verte pour commencer."};
const char *const chaines[] PROGMEM = {uwu_0};


int8_t longueurEcran = 16;


int8_t departement[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101};


int8_t tailleTableau = 102;

int8_t etatButton;
int8_t etatLED;

int8_t lastEtatButton;
int8_t lastEtatLED;
int count = 0;


boolean boucleInfini = true;

static int position = 0; // Position actuelle du défilement
static uint32_t lastScrollTime = 0; // Temps du dernier défilement


void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.clear();
  delay(1000);



  
    strcpy_P(temp_string, (char *)pgm_read_word(&(chaines[0])));
    while (position < strlen(temp_string) + longueurEcran  ) {
      

      if (millis() - lastScrollTime >= 250) { // Défiler toutes les 200 millisecondes (ajustez la vitesse selon vos besoins)
        lastScrollTime = millis();

        lcd.clear();

        // Déterminer la sous-chaîne à afficher sur une seule ligne
        uint8_t start = position;
        uint8_t end = min(position + longueurEcran, strlen(temp_string)); // Utiliser la longueur de la chaîne comme limite

        // Créer un tableau temporaire pour stocker la sous-chaîne
        char temp_substring[longueurEcran + 1]; // +1 pour le caractère de fin de chaîne '\0'
        strncpy(temp_substring, temp_string + start, end - start);
        temp_substring[end - start] = '\0'; // Ajouter le caractère de fin de chaîne

        // Afficher la sous-chaîne correspondante sur la première ligne de l'écran LCD
        lcd.setCursor(0, 0);
        lcd.print(temp_substring);

        // Augmenter la position
        position++;

        delay(250); // Attendre 200 millisecondes avant le prochain défilement
        
      }
     


    }
  

  lcd.clear();

}






void loop() {

  Serial.println("ok");

}


Bonjour,

Ici strcpy_P(temp_string, (char *)pgm_read_word(&(chaines[0]))); tu copies une chaine qui fait environ 180 octets dans un buffer de 27 octets. Ca déborde de tous les cotés et fait planter le programme.

Pourtant mon programme ne plante pas. Au début j'avais mis 200, mais j'ai diminué cette valeur de tel manière qu'elle soit la plus petite possible et que mon programme s'affiche bien (27 est la valeur limite). Que je mette 1000 ou 27 mon problème est toujours présent...le texte apparait en boucle.

Bien sur que ton programme plante car le message s'affiche en boucle.

Tu as un autre débordement (dans l'autre sens).
A la fin, end-start vaut -1, ce qui fait que tu ecris en dehors de ton buffer temp_substring.

je dois modifier quoi dans ce cas ?

Tu peux faire ça:

        if (end-start>0)
        {
          strncpy(temp_substring, temp_string + start, end - start);
          temp_substring[end - start] = '\0'; // Ajouter le caractère de fin de chaîne
        }

Mais ce n'est qu'un palliatif, il faudrait que tu vois pourquoi il arrive que start soit supérieur à end.

et n'oublie pas de dimensionner temp_string à 200

ok merci, mais du coup ce code je dois le mettre dans ma boucle while ?
start est supérieur a end peut être parce que ils sont de type uint8_t ?

oui, tu modifies ta boucle while pour ajouter le test.

Non ce n'est pas du au fait que ce soit des uint8_t

Le problème est ici
while (position < strlen(temp_string) + longueurEcran ) {

position ne peut être supérieur à strlen(temp_string) car c'est à partir de la que tu recopies la string

il faut faire
while (position < strlen(temp_string)) {

Ok, donc là en modifiant j'ai juste deux symboles qui s'affichent et disparaissent, mais c'est du au fait que start soit supérieur à end c'est ça?

Nos messages se sont croisés, voir ma réponse au dessus

En effet, mais en modifiant ce que tu m'as dit, il n'y a plus rien qui s'affiche sur mon écran mais il ne tourne pas en boucle car la partie loop s’exécute.

mets ton nouveau programme

#include <LiquidCrystal.h>
#include <String.h>
#include <Wire.h>
#include <HT16K33.h>
#include <avr/pgmspace.h>

#define LED 2
#define BUTTON A1


HT16K33 seg(0x70);              //Crée un objet
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);  //Pins où on va connecter l'écran (RS, E, D4, D5, D6, D7)

char temp_string[200];
const char uwu_0[] PROGMEM = {"   Jeu pour apprendre les departements francais. CONSIGNE: Vous avez 3 secondes pour deviner le nom du departement qui s'affiche. Appuyer sur le bouton de la LED verte pour commencer."};
const char *const chaines[] PROGMEM = {uwu_0};


int8_t longueurEcran = 16;


int8_t departement[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101};


int8_t tailleTableau = 102;

int8_t etatButton;
int8_t etatLED;

int8_t lastEtatButton;
int8_t lastEtatLED;
int count = 0;


boolean boucleInfini = true;

static int position = 0; // Position actuelle du défilement
static uint32_t lastScrollTime = 0; // Temps du dernier défilement


void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.clear();
  delay(1000);


  // Déterminer la sous-chaîne à afficher sur une seule ligne


  //strcpy_P(temp_string, (char *)pgm_read_word(&(chaines[0])));
  while (position < strlen(temp_string)) {


    if (millis() - lastScrollTime >= 250) { // Défiler toutes les 200 millisecondes (ajustez la vitesse selon vos besoins)
      lastScrollTime = millis();

      lcd.clear();

      uint8_t start = position;
      uint8_t end = min(position + longueurEcran, strlen(temp_string)); // Utiliser la longueur de la chaîne comme limite

      // Créer un tableau temporaire pour stocker la sous-chaîne
      char temp_substring[longueurEcran + 1]; // +1 pour le caractère de fin de chaîne '\0'
      if (end - start > 0)
      {
        strncpy(temp_substring, temp_string + start, end - start);
        temp_substring[end - start] = '\0'; // Ajouter le caractère de fin de chaîne
      }
      // Afficher la sous-chaîne correspondante sur la première ligne de l'écran LCD
      lcd.setCursor(0, 0);
      lcd.print(temp_substring);

      // Augmenter la position
      position++;

      delay(250); // Attendre 200 millisecondes avant le prochain défilement

    }



  }


  lcd.clear();

}






void loop() {

  Serial.println("ok");

}

Cette ligne est en commentaire?
//strcpy_P(temp_string, (char *)pgm_read_word(&(chaines[0])));

C'est bon ça fonctionne ! merci

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.