Écriture sur carte SD

Bonjour,
Je souhaite écrire des informations relatives à des données GPS sur une carte micro SD. Je dispose donc d’un module GPS et d’un module SD.

Mon algo ressemble à cela :

tant que (je boucle){
si (c’est le premier tour de boucle){
Écriture de “la date”;
Écriture de ‘\n’;
premier tour de boucle = false;
}
si (la balise GPS est en mouvement){
Écriture de “moving”;
sinon
Écriture de “no move”;}
}
}

L’idée est d’avoir la date une seule fois (sur la première ligne). Et d’avoir “moving” ou “no move” sur les lignes suivantes.

Voici une version abrégée de mon code, comportant uniquement les éléments en cause dans ma problématique :

boolean IsFirstRound = true;
#include <SD.h>
File logfile;
char report[255];
#define chipSelect 78
//Le type de trame GPS ( 1 pour RMC et 2 pour GGA)
int frametype;
String FileContant;
char CharToRead;

void setup() {
  Serial.begin(115200); while (!Serial);
  pinMode(chipSelect, OUTPUT);
  createLogFile(); // je commence par créer un fichier sur ma carte SD.. (RAS).
}

void loop() {
switch (state) {
case cas1 : //Rien d'important ici..
  //traitement cas1..
  state = cas2;
  break;
case cas2 : //J'initialise le GPS et j'écris la date.
  sendCommandToGps(); // je demande au module gps d'envoyer des trames.. (RAS).
  if(IsFirstRound == true){
        Serial.println("First, we print the date into the SD file.");
              while (1){
                readAndWriteData(); // voir plus bas.
                if(frametype == 1){
                  Serial.println("\nEnd of the RMC frame");
                  frametype = 0;
                  break;
                }else if (frametype == 2){
                  Serial.println("\nEnd of the GGA frame");
                  frametype = 0;
                  break;
                }
              }
}
        IsFirstRound = false;
  state = cas3;
  break;
case cas3 : //J'écris "moving" ou "no move" avec la fonction readAndWriteData().
  while (1){
    readAndWriteData();
    if(frametype == 1){
      Serial.println("\nEnd of the RMC frame");
      frametype = 0;
      break;
    }else if (frametype == 2){
      Serial.println("\nEnd of the GGA frame");
      frametype = 0;
      break;
    }
  } //fin du while
  state = cas4;
  break;
case cas4 : //J'affiche le contenu du fichier de la carte SD.
logfile = SD.open(filename);
      if (logfile) {
      while (logfile.available()) {
        CharToRead = logfile.read();
        FileContant += CharToRead;
        }
      logfile.close();
      }
      Serial.println("FileContant :");
      Serial.println(FileContant);
      state = cas1;
      break;
} //fin du switch
} //fin du void loop

void readAndWriteData() {

//avant tout je récupère les données GPS dans un tableau de pointeur "NmeaFrameArrayPointer".. (RAS).

  if(IsFirstRound == true){
     // Besoin d'une trame RMC pour avoir la date, alors j'en attend une.
if (!strcmp(NmeaFrameArrayPointer[0], "\n$GPGGA")){
  return;
  }
if(nbPtr >= 10){
    frametype=1;
    Serial.println("---V---: PRINTING DATE ON SD CARD");
    AddLineToSdFile(12); // voir plus bas
    AddLineToSdFile(2);
    IsFirstRound = false;
    return;
    }else{
      Serial.println("Incomplete frame, can't print the date.");
    }
// Si ce n'est pas le premier tour on n'écrit pas la date. 
}else{

    char nomove[9] ={'n','o',' ','m','o','v','e','\n'};
    char moving[8] = {'m','o','v','i','n','g','\n'};

// If the first frame element is "\n$GPRMC"  we pick index [3] of the array (lattitude)
    if (!strcmp(NmeaFrameArrayPointer[0], "\n$GPRMC")) {
      // When the frame is complete.
      if(nbPtr >= 10){
        Serial.println(F("\nRecognized RMC frame !\n"));
        currentLat = degMinSecToDecimalDeg(NmeaFrameArrayPointer[3]);
        Movingornot = Compare(currentLat, lastLat); //Rien d'important, je compare les latitudes pour avoir un booléen qui m'indique si c'est en mouvement ou non (je sais que comparer les latitudes ne suffit pas toujours, mais pour le moment c'est suffisant, et ce n'est pas mon problème).
        lastLat = currentLat;
        // When the vehicule is moving.
        if(Movingornot ==1){
          for (int i=0; i < strlen(moving); i++){
          report[i] = moving[i];
          }
          AddLineToSdFile(3);
frametype = 1;
          return;
        // When the vehicule is moving.
        }else{
          for (int i=0; i < strlen(nomove); i++){
            report[i] = nomove[i];
          }
          AddLineToSdFile(3);
          frametype = 1;
          return;
        }
}else{
        Serial.println("But the frame is not complete...");
        AddLineToSdFile(5);
        frametype = 1;
        return;        
      }
// If the first frame element is "\n$GPGGA"  we pick index [2] of the array (lattitude)
    }else if (!strcmp(NmeaFrameArrayPointer[0], "\n$GPGGA")){
// C'est le même traitement que pour RMC, mais avec l'indice 2 tu tableau de pointeurs.
    }
    Serial.println("\n");
}
} //fin de la fonction readAndWriteData().

void AddLineToSdFile(int whatToPrint){
Serial.println("Writing on the SD file...");
if (whatToPrint == 2){
  // Open the file.
  logfile = SD.open(filename, FILE_WRITE);
  

  // If the file opened okay, write to it.
  if (logfile) {
    logfile.print('\n');
    // Close the file.
    logfile.close();
    return;
 } else {
  
  // If the file didn't open, print an error.
  Serial.println("error opening the file.");
  }
}else if (whatToPrint == 3){
  // Open the file.
  logfile = SD.open(filename, FILE_WRITE);
  

  // If the file opened okay, write to it.
  if (logfile) {
    for (int i =0; i <strlen(report); i++){ 
    logfile.print(report[i]);
    }
    // Close the file.
    logfile.close();
    return;
 } else {
  
  // If the file didn't open, print an error.
  Serial.println("error opening the file.");
  } 
}else if (whatToPrint == 5){
  // Open the file.
  logfile = SD.open(filename, FILE_WRITE);
  

  // If the file opened okay, write to it.
  if (logfile) {
    for (int i =0; i <strlen(incompleteRMC); i++){ 
    logfile.print(incompleteRMC[i]);
    }
    // Close the file.
    logfile.close();
    return;
 } else {
  
  // If the file didn't open, print an error.
  Serial.println("error opening the file.");
  } 
}else if (whatToPrint == 12){
  // Open the file.
  logfile = SD.open(filename, FILE_WRITE);
  

  // If the file opened okay, write to it.
  if (logfile) {
    logfile.println(NmeaFrameArrayPointer[8]);
    // Close the file.
    logfile.close();
    return;
 } else {
  
  // If the file didn't open, print an error.
  Serial.println("error opening the file.");
  } 
}
}//fin de la fonction AddLineToSdFile().

Et voici le retour du moniteur série lorsque j’affiche le contenu du fichier de la carte SD :

130717

moving //c'est normal, il n'y a pas de latitude précédente pour comparer
130717

moving
no move
130717

moving
no move
no move
130717

moving
no move
no move
no move
no move
130717

moving
no move
no move
no move
no move
no move
130717

moving
no move
no move
no move
no move
no move
no move
no move

C’est presque ça sauf que la date s’affiche un peu partout.

Une nouvelle donnée est écrite à chaque tour de boucle mais la donnée précédente aussi est réécrite. On le voir bien, ça fait des répétitions. Je ne comprend pas trop pourquoi. On dirait que je n’ai pas vidé la variable à écrire entre chaque tour de boucle ? Je suis largué :drooling_face:

Merci d’avance, votre aide est précieuse.

Bonjour,

Merci pepe !

J'ai aussi eu cette réflexion, c'est vrai que c'est plus logique.
Mais en réalité l'algo est plus compliqué, et c'est un choix que j'ai fait mettre la date dans la boucle, car elle est dans un cas INIT_GPS dans lequel on ne retourne normalement jamais.

En résumé j'ai un algo qui ressemble plutôt à cela :

tant que (je boucle){
selon cas{
cas INIT_GPS :
sendCommandToGps(); // initialisation
si (c'est le premier tour de boucle){ // et impression de la date.
Écriture de "la date";
Écriture de '\n';
premier tour de boucle = false;
}
cas = GET_RMC_GGA;
break;
cas GET_RMC_GGA : // j'écris "moving" ou "no move"
si (la balise GPS est en mouvement){
Écriture de "moving";
sinon
Écriture de "no move";}
}
cas = PRINT_FILE_CONTANT;.
break;
cas PRINT_FILE_CONTANT :
Lecture du fichier;
cas = GET_RMC_GGA; // On ne passe plus par INIT_GPS, même s'il est dans la boucle.
break;
} //fin switch
} // fin loop

Salut,
Je regardais ça un peu et je suis pas mal d'accord avec pepe, en plus dans ton algo ou dans ton code, on ne voit pas ou est-ce que tu change l'état de cas à part dans le switch lui même, ce qui est bizarre... non??

C'est vrai que dans mon algo on pourrait penser que l'utilisation d'un automate n'est pas justifiée mais en réalité mon code est bien plus vaste et comporte une dizaine d'états qui sont bel et bien nécessaires.

Il est possible de repasser par l'état INIT_GPS sous une condition qui n'est pas décrite dans mon post, lorsque que j'éteint le module GPS, est-ce vraiment important ?

Je cherche à comprendre pourquoi la date vient se print plusieurs fois sur mon fichier.

Merci à vous !

Oui, je sais, le code que je vous montre n'est pas mon code intégral, mais les éléments mis en cause dans mon problème sont présents, sont fonctionnement n'est donc pas différent, normalement. Le fait que j'utilise un automate ou non ne change rien. Le fait que vous élaguiez mon algo ne change rien non plus, c'est juste plus propre. Le fait que je vous présente uniquement 3 "case" ne change strictement rien, les autre case n'utilisent même pas le module GPS et le module SD. Je doute qu'il soit utile de poster 1500 lignes de code. J'ai passé 2 heures à éditer le topic en m'assurant que cette version réduite comporte l'ensemble des instructions liées à mon problème..

J'ai vérifié l'état de IsFirstRound, bien entendu. Il est à TRUE au premier tour, puis à FALSE le reste du temps.
Ma condition est valide, simplement j'ai l'impression qu'une partie de la donnée est réécrite, comme si la donnée à écrire n'était pas écrasée par la nouvelle donnée. Voici ce qui s'ajoute au fichier tours après tours :

1er tour :
130717 //ok

2eme tour :
moving //ok

3eme tour :
130717 //problème

moving //problème
no move // ok

4eme tour :
130717 //problème

moving //problème
no move // problème
no move //ok

etc..

Je peux éventuellement mettre les sources en pièce jointe, pour lever toute ambiguïté, qu'en pensez-vous.

Bonjour pepe,

Merci pour cette réponse détaillée :slight_smile:
Je pense avoir trouvé mon erreur, c'est tout bête (comme moi :D)

J'ai ajouté une ligne :

case cas4 : //J'affiche le contenu du fichier de la carte SD.
logfile = SD.open(filename);
      if (logfile) {
      while (logfile.available()) {
        CharToRead = logfile.read();
        FileContant += CharToRead;
        }
      logfile.close();
      }
      Serial.println("FileContant :");
      Serial.println(FileContant);
      FileContant ="";                  // LA LIGNE AJOUTÉE
      state = cas1;
      break;

C'est l'affichage qui n'était pas bon 8)