Variable qui se réinitialise toute seule

Bonjour à toutes et à tous,

Dans mon projet de routeur photovoltaïque, j'ai une variable energQuot qui se réinitialise toute seule, à des moments qui ne me semblent pas en rapport avec un évènement dans cette boucle de calcul.

Cette variable représente l'énergie consommée. Elle est mise à jour toutes les secondes et normalement remise à zéro au passage au jour suivant. Cela se situe dans void loop(){...}. Voilà le morceau de code concerné :

void loop() {
  ArduinoOTA.handle();
  etatNouv = digitalRead(pin_DetSinus);
  if (etatNouv == HIGH && etatPrec == LOW) { // Il n'y a changement d'état que si le réseau est présent
    t1 = 0; // Réinitialisation du compteur de défaut
    pb = false; // Si on passe dans cette boucle, c'est que le réseau est présent
    statut0 = "Normal";
    digitalWrite(ledPB, LOW); // on éteint la LED de défaut
    noMesure ++;
    if (noMesure >= nbP50Hz) {
      noMesure = 0;
    }
    pAonde = Infos_UIP(pin_Commun, pin_Tension, pin_Courant, 0.784, 0.06, nbPt, ptsV, ptsI, &vRMS, &iRMS); // Mesure toutes les 20 mS
    sumPA += pAonde;
    if (noMesure == 0) { // Commencement de la série de nbP50Hz mesures
      infUIoK = false;
      pActif = sumPA/nbP50Hz;
      energQuot += pActif*jTokWh;
      infUI = "";
      for (uint8_t i = 0; i < nbPt; i++) {
        infUI += String(ptsV[i])+","+String(ptsI[i])+"\n";
        ptsV[i] = 0;
        ptsI[i] = 0;
      }
      infUIoK = true;
      Vu = !Vu;
      digitalWrite(ledOK, Vu);
      if (Vu)
        teta0 = sensors.getTempC(sonde0, 0); // Comme la mesure prend 12 ms, on alterne la mesure entre les deux sondes
      else
        teta1 = sensors.getTempC(sonde1, 0); // Comme la mesure prend 12 ms, on alterne la mesure entre les deux sondes
      forceWiFi = String(WiFi.RSSI());
      getLocalTime(&timeinfo);
      strftime(info_DH, 24, "%d/%m/%Y %H:%M:%S,", &timeinfo); // Mise en forme de la date : JJ/MM/AAA HH:MM:SS
      sprintf(info_UIP, "%.1f,%.1f,%.1f,%.4f\n", pActif, vRMS, iRMS, energQuot); // Représente 28 octets au maximum
      if (timeinfo.tm_sec % 30 == 0) { // Enregistrement toutes les 30 secondes
        appendFile2(LittleFS, fchHisto, info_DH, info_UIP, 115200); // Enregistrement d'une nouvelle ligne de données
        affOLED(0);
        if(timeinfo.tm_yday != jourPrec) { // MàJ de l'heure à chaque changement de jour et ...
          configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);  // On configure le seveur NTP
          energQuot = 0; // Remise à zéro du cumul de l'énergie quotidienne
          fchHisto = remplaceFchHisto(); // ... remplace l'ancien fichier "fchHisto" portant sur le même jour de la semaine
          jourPrec = timeinfo.tm_yday;
        }   
      }
      if (pActif < 0) // Si il y a surplus de production
        nbP_CmdTriac += 1+50*pActif/pMaxSurplus;
      else 
        nbP_CmdTriac -= 1+50*pActif/pMaxSurplus;
      nbP_CmdTriac = constrain(nbP_CmdTriac, 0, 49);
      sumPA = 0; // Remise à zéro de la puissance moyenne toutes les nbP50Hz périodes
      if (nbP_CmdTriac == 0)
        digitalWrite(pin_CmdTriac, LOW);
      else  
        digitalWrite(pin_CmdTriac, HIGH);
      modeFonctionnement(); // Modifie la gestion du surplus de production. Fonction vide pour l'instant
      sensors.requestTemperatures(); // Initialisation de la mesure sur toutes les sondes de température DS18B20
      Serial.print("Nb = "+String(nbP_CmdTriac)+"  ");  
      Serial.print(info_DH);
      Serial.print("  ");
      Serial.print(info_UIP);
    }
  }
  if (nbP_CmdTriac < noMesure) // Remise à zéro de la commande du triac
    digitalWrite(pin_CmdTriac, LOW); // Attention, cette commande doit arriver avant le front montant de la tension EDF
  etatPrec = etatNouv;
  t1++;
  pb = statut();
}

Quelques variables concernées :

const uint8_t nbP50Hz = 50; // Intervalle de temps entre chaque mesure en nombre de périodes de 50 Hz
char nom_Fch[24]; // Chaîne de caractères pour le nom du fichier de données historiques
char info_DH[24]; // Chaîne de caractères pour l'écriture de la date-heure
float pAonde; // Valeur de la puissance active sur une période de 50 Hz
float sumPA; // Somme partielle de pAonde
float vRMS, iRMS; // Valeur efficace pour la tension et le courant
float energQuot; // valeur du cumul de l'énergie quotidienne
char info_UIP[32]; // Chaîne de caractères pour l'écriture des données

La requête faite par le client :

  server.on("/histoUIP", HTTP_GET, [](AsyncWebServerRequest *request) { // Envoi du fichier d'historique pour affichage
    uint32_t ti = millis();
    while (infUIoK == false && millis()-ti < 3000) {}
    request->send(LittleFS, fchHisto, String(), false);
  });

Le résultat de compilation :

Le croquis utilise 1159981 octets (88%) de l'espace de stockage de programmes. Le maximum est de 1310720 octets.
Les variables globales utilisent 52424 octets (15%) de mémoire dynamique, ce qui laisse 275256 octets pour les variables locales. Le maximum est de 327680 octets.

Le fichier transmis fait 100 ko au maximum. La réinitialisation de la variable se passe parfois alors que le fichier fait à peine 20 ko.

Si vous avez une idée, une piste de ce qui peut perturber cette variable.

Cordialement.

Pierre.

utilisez snprintf() ici (et partout ailleurs, pour tous les buffers) pour être sûr de ne pas déborder du buffer

je pense à celui là parce qu'il est déclaré juste à côté de votre variable

float energQuot; // valeur du cumul de l'énergie quotidienne
char info_UIP[32]; // Chaîne de caractères pour l'écriture des données

(une variable qui change de valeur subitement c'est souvent lié à un débordement mémoire d'une autre variable)

Je me doutais bien qu'il s'agissait d'un débordement de mémoire, mais je ne l'attendais pas là, la taille de mon buffer était telle (32 octets) qu'il ne devait jamais déborder avec la donnée suivante : -pppp.p,uuu.u,-ii.i,-www.ww/n, ce qui représente 29 octets, zéro final compris et si on considère que /n n'est qu'un seul caractère.

Par ailleurs, dans l'espace de temps où le problème est arrivé, l'analyse de mes données montre que je n'ai jamais dépassé 25 caractères.

Peut-être que la demande cyclique (toutes les deux secondes) de requête fichait la pagaille dans cet agencement.

J'ai donc remplacé (c'est le seul dans mon programme) :

      sprintf(info_UIP, "%.1f,%.1f,%.1f,%.2f\n", pActif, vRMS, iRMS, energQuot);

par :

      snprintf(info_UIP, 32, "%.1f,%.1f,%.1f,%.2f\n", pActif, vRMS, iRMS, energQuot);

Bien que le buffer soit de la même taille, depuis hier où j'ai fait la modif, le problème ne s'est pas reproduit. Je surveille ...

Joke : la prochaine fois que j'aurai un programme à réaliser, je vous donnerai le cahier des charges et vous me ferez le programme. Ça ira plus vite. :wink:

Cordialement.

Pierre.

LOL :slight_smile:

ce que vous pourriez faire c'est vérifier le résultat du snprintfsnprintf retourne le nombre total de caractères qui auraient été écrits si le buffer avait été assez grand (sans compter le caractère nul de fin.) Si la valeur retournée est supérieure ou égale à la taille du buffer fournie, cela signifie que la sortie a été tronqué et vous pourriez afficher un message d'erreur dans la console ou allumer une LED pour dire "il y aurait eu un bug ici".

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