SD + récupération de données

Bonjour a tous,

Voilà j'essaye de faire évoluer mon projet de Station Température en voulant enregistrer en plus des données actuelles les mini et maxi sur la carte SD de l'émetteur qui est une carte Seeduino Stalker.

Pourquoi sur la carte SD? Parce que l'eeprom n'a pas une durée de vie assez importante (je fait un échantillon toutes les 15s, ce qui fait que l'eeprom serait morte au bout de 17/18 jours environ).

Donc comme je sauvegarde sur la SD avec des données qui ressemble à ça:

date;temp;temp_min;temp_max

Les données brutes sont celles ci:

13/04/2014;02:26:45;24.50;24.50;24.50 13/04/2014;02:26:59;24.50;24.50;24.50

Alors lors de l'initialisation je souhaite récupérer les valeurs max et min de la dernière ligne du fichier inscrit sur la carte SD et les placer dans les variables temp_min et temp_max.

Le problème qui se pose c'est que mes variables de températures peuvent prendre la forme: Soit 4 caractères du type X.XX Par exemple: 13/04/2014;02:26:45;24.50;4.50;24.50 Ici la temp_min est à 4.50 Soit 5 caractères du type XX.XX Par exemple: 13/04/2014;02:26:45;5.50;4.50;6.50 Ici la temp est à 5.50

Donc la longueur d'une ligne est variable ce qui fait que ma routine de récupération de données ne fonctionne pas. Mon principe c'est que j'ouvre le fichier sur la carte SD. Je me place à la fin du fichier Je me déplace de X caractères en arrière pour me placer juste avant la température mini

file.seek(file.size()-(nombreLigneVoulues * (set_cursor + 2)));

Je lis le fichier en récupérant les données jusq'à la fin du fichier de la SD:

int j=0;
    char chaine2[20]="TT.TT;TT.TT";
    while(file.available())
    {
    chaine2[j] = file.read();
    Serial.print(chaine[i]);
    j++;
    }

Puis je découpe ma chaine pour la mettre dans deux variables différentes.

// Start conversion
     int k=0;
     int l=0;
     while (chaine2[k]!=';'){
     buf1[l] = chaine2[k];
     k++;
     l++;
     }
     buf1[l]='\0';
     k++;
     l=0;
     while (chaine2[k]!='\0'){
     buf2[l] = chaine2[k];
     k++;
     l++;
     }
    
    temp_min=atof(buf1);
    temp_max=atof(buf2);

Le problème c'est que comme ma chaine de référence inscrite dans le fichier SD change de longueur je ne peux pas correctement récupérer mes valeurs.

Y-a-t'il un moyen de forcer à mettre un 0 avant les valeurs qui sont à 1 chiffre avant la virgule? Ou bien y a t'il une autre méthode plus simple et efficace pour récupérer correctement mes données?

Le but étant par la suite de les envoyer par XBee

Tu testes si la valeur de ta variable est inférieure à 10, si c'est le cas avant de l'envoyer, tu envoie une "0". Ensuite tu récupères tes valeurs comme si elle étaient toutes supérieures à 10.

Ok donc en fait comme j’ai fait pour l’heure:

if (nowDST.second()< 10) //si inferieur à 10 alors
        { file.print('0'); } //afficher un 0
        file.print(nowDST.second(), DEC);

Mais pour mes températures?

J’étais pas bien réveillé hier moi :grin:

Tu peux faire pour les températures comme pour l’heure.
Si temp<10.0 alors ajouter un zéro en tête.

L’autre solution c’est à la lecture de partir de la fin du fichier et de remonter caractère par caractère jusqu’au \0 qui termine l’avant dernière mesure et ensuite de lire la dernière mesure complète et de traiter la ligne normalement en cherchant les “;”

john_lenfr: Mais pour mes températures?

Pareille... non ? :grin:

john_lenfr: J'étais pas bien réveillé hier moi :grin:

Aujourd'hui aussi XD

Bon j'ai réglé le problème du formatage de fichier parc contre j'ai un autre problème sur cette fonction:

Le but est de créer le fichier s'il n'existe pas. S'il existe déjà on le lit et je récupère les infos.

Mais apparemment je ne dois pas bien utiliser SD.exists car cela ne fonctionne pas ou ajoute un problème car je rentre pas en lecture dans le fichier et les file.seek ne fonctionne pas.

En faisant un test avant la boucle SD.exists renvoie bien vrai, mais une fois à l'intérieur du IF les file.XXXX ne fonctionnent pas.

Il faut réinitialiser qqch après avoir fait un SD.exists ?

void init_SD(){

  // Init  
  Serial.println("-----------------"); 
    if (!SD.begin(10)) {
      Serial.println("Init failed!");
      return;
    }
    else
    {
      Serial.println("Init OK");
    }
    
  Serial.println(SD.exists(file_name));
  delay(10);
    file.close();
    delay(10);
  
  if (!(SD.exists(file_name)))  
  { 
    // if the file does'nt exists no opening and create file
    Serial.print("file ");
    Serial.print(file_name);
    Serial.println(" don't exists. No file to read.");
    Serial.println("Creating file...");
    
    file = SD.open(file_name, FILE_WRITE);
   
    delay(10);
    file.close();
    delay(10);
    
    // checks if the file has been created
      if (SD.exists(file_name)) {
      Serial.print(file_name);
      Serial.println(" now exists.");
      }
      else {
      Serial.println("The file can't be created");  
      }
  } 
  
  else   //if exists read file and restore max min temp
  {
     
    digitalWrite(PIN_RED_LED, HIGH); //power ON led on the board when printing on SD Card
    file = SD.open(file_name, FILE_READ);
    if (file) Serial.println("fichier ouvert");
    
    //start reading
    file.seek(file.size()-(nombreLigneVoulues * (longueurLigne + 2)));
    
      Serial.println(file.size());
      Serial.println(file.position());
      int i=0;
      char chaine[38]="DD/MM/YYYY;HH:MM:SS;TT.TT;TT.TT;TT.TT";
      while(file.available())
      {
      chaine[i] = file.read();
      Serial.print(chaine[i]);
      i++;
      }
      
      Serial.print("Derniere ligne du fichier lue: ");
      Serial.println(chaine);
    
    
    file.seek(file.size()-(nombreLigneVoulues * (set_cursor + 2)));
    int j=0;
    char chaine2[12]="TT.TT;TT.TT";
    while(file.available())
    {
    chaine2[j] = file.read();
    Serial.print(chaine[i]);
    j++;
    }
    
    
    Serial.print("fin chaine lue: ");
    Serial.println(chaine2);
    
    
    // Start conversion
     int k=0;
     int l=0;
     while (chaine2[k]!=';'){
     buf1[l] = chaine2[k];
     k++;
     l++;
     }
     buf1[l]='\0';
     k++;
     l=0;
     while (chaine2[k]!='\0'){
     buf2[l] = chaine2[k];
     k++;
     l++;
     }
    
    temp_min=atof(buf1);
    temp_max=atof(buf2);
    
    if (temp_min==0) temp_min = 99;
    if (temp_max==0) temp_max = -99;
   
    Serial.print("max temp SD: ");
    Serial.println(temp_max);
    Serial.print("min temp SD: ");
    Serial.println(temp_min);
    
    //end reading
    digitalWrite(PIN_RED_LED, LOW); //power OFF led on the board when ENDING printing on SD Card
    delay(10);
    file.close();
    delay(10);
   }

  Serial.println("-----------------");
  
}

Et voici le retour:


Init OK 1 0 4294967295 Derniere ligne du fichier lue: DD/MM/YYYY;HH:MM:SS;TT.TT;TT.TT;TT.TT fin chaine lue: TT.TT;TT.TT max temp SD: -99.00

min temp SD: 99.00

Free RAM : 352

EDIT: je viens d'essayer avec un switch (SD.exists(file_name)){ case.... mais pareil

Je précise que les données s’inscrivent bien sur la carte SD, le fichier n'est pas vide.

Normalement après avoir créé le fichier le test ne devrait pas être ainsi

    file = SD.open(file_name, FILE_WRITE);
   
    delay(10);
    file.close();
    delay(10);
    
    // checks if the file has been created
      if (SD.exists(file_name)) {

mais comme cela d'après les exemples de la librairie

    file = SD.open(file_name, FILE_WRITE);
   
    delay(10);
    file.close();
    delay(10);
    
    // checks if the file has been created
      if (file) {                             // test que file est ouvert

autrement là

  Serial.println(SD.exists(file_name));
  delay(10);
    file.close();
    delay(10);

Je ne vois pas l’intérêt du close étant donné que rien n'a encore été ouvert.

fdufnews: mais comme cela d'après les exemples de la librairie

    file = SD.open(file_name, FILE_WRITE);
   
    delay(10);
    file.close();
    delay(10);
    
    // checks if the file has been created
      if (file) {                             // test que file est ouvert

Le problème de réaliser cette méthode c'est que mon code de création de fichier n'est plus utile dans ce cas. Car en FILE_WRITE si le fichier n'existe pas il le crée:

If the file is opened for writing, it will be created if it doesn't already exist

Donc si je suis ce résonnement, je suis bloqué car ma routine de récupération de données ne doit se lancer que si des données existent déjà sur la carte. Or utiliser le test sur SD.open fait que je lance ma routine même si le fichier est vide, car par défaut s'il n'existe pas il va le créer.

C'est pour cela que le test SD.exists(filename) me plaisait bien car ma procédure était fonctionnelle: Si fichier n'existe pas alors on le crée et on sort de l'init Si le fichier existe alors on récupère les données et on sort de l'init

A moins que je mette un pti drapal pour résoudre mon problème de test avec une autre condition?

Je crois que tu te mélanges grave.
Le test dont nous parlons est placé après la création du fichier.

  Serial.println(SD.exists(file_name));
  delay(10);
    file.close();
    delay(10);
  
  if (!(SD.exists(file_name)))  
  { 
    // if the file does'nt exists no opening and create file
    Serial.print("file ");
    Serial.print(file_name);
    Serial.println(" don't exists. No file to read.");
    Serial.println("Creating file...");
    
    file = SD.open(file_name, FILE_WRITE);
   
    delay(10);
    file.close();
    delay(10);
    
    // checks if the file has been created
      if (SD.exists(file_name)) {    <<<<<------------ je parle de ce test

Le fichier doit avoir été créé par l’open juste au-dessus. Le test dont je parle sert à vérifier qu’il a pu être créé et cela se fait en testant file qui est NULL si le fichier n’a pas pu être créé. Les 2 delay et le close sont absolument inutile dans ce contexte.

Ok, de toute façon j'ai supprimé tout ce code inutile.

Mais je n'arrive toujours pas à mes fins. Maintenant c'est le file qui est à false alors que le fichier existe bien sur la carte :roll_eyes:

Bon alors voila le code avec réaction mystère:

Avec ce code Serial.println(file); vaut bien 1

void init_SD(){

  // Init  
  Serial.println("-----start init SD-----"); 
    if (!SD.begin()) {
      Serial.println("Init failed!");
      return;
    }
    else
    {
      Serial.println("Init OK");
    }
    
  //Serial.println(SD.exists(file_name));
  //delay(500);
  
  file = SD.open(file_name, FILE_READ);
  Serial.println(file);

  if(file){
   while(1);
  }
  else //if exists read file and restore max min temp
  {  
   
   // if the file does'nt exists do nothing it will
   // be create by the first main loop
    Serial.println("no existing file");
    Serial.println("will be created by");
    Serial.println("the first main loop");
    
    
   }
   
  // end of init
  Serial.println("-----end init SD-----");
  
}

Mais avec celui ci file prend la valeur NULL alors que le fichier exste bien sur la carte.

void init_SD(){

  // Init  
  Serial.println("-----start init SD-----"); 
    if (!SD.begin()) {
      Serial.println("Init failed!");
      return;
    }
    else
    {
      Serial.println("Init OK");
    }
    
  //Serial.println(SD.exists(file_name));
  //delay(500);
  
  file = SD.open(file_name, FILE_READ);
  Serial.println(file);

  if(file){
    
      digitalWrite(PIN_RED_LED, HIGH); //power ON led on the board when printing on SD Card
      //file = SD.open(file_name, FILE_WRITE);
      //if (file) Serial.println("fichier ouvert");
    
      //start reading
      file.seek(file.size()-(nombreLigneVoulues * (longueurLigne + 2)));
    
      //Serial.println(file.size());
      //Serial.println(file.position());
      int i=0;
      char chaine[38]="YYY/MM/DD;HH:MM:SS;TT.TT;TT.TT;TT.TT";
      while(file.available())
      {
      chaine[i] = file.read();
      //Serial.print(chaine[i]);
      i++;
      }
      
      Serial.print("Derniere ligne du fichier lue: ");
      Serial.println(chaine);
    
    
    file.seek(file.size()-(nombreLigneVoulues * (set_cursor + 2)));
    int j=0;
    char chaine2[12]="TT.TT;TT.TT";
    while(file.available())
    {
    chaine2[j] = file.read();
    //Serial.print(chaine[i]);
    j++;
    }
    
    
    Serial.print("fin chaine lue: ");
    Serial.println(chaine2);
    
    
    // Start conversion
     int k=0;
     int l=0;
     while (chaine2[k]!=';'){
     buf1[l] = chaine2[k];
     k++;
     l++;
     }
     buf1[l]='\0';
     k++;
     l=0;
     while (chaine2[k]!='\0'){
     buf2[l] = chaine2[k];
     k++;
     l++;
     }
    
    temp_min=atof(buf1);
    temp_max=atof(buf2);
    
    if (temp_min==0){ temp_min = 99;}
    if (temp_max==0){ temp_max = -99;}
   
    Serial.print("max temp SD: ");
    Serial.println(temp_max);
    Serial.print("min temp SD: ");
    Serial.println(temp_min);
    
    //end reading
    digitalWrite(PIN_RED_LED, LOW); //power OFF led on the board when ENDING printing on SD Card
    delay(10);
    file.close();
    delay(10);
    
  }
  else //if exists read file and restore max min temp
  {  
   
   // if the file does'nt exists do nothing it will
   // be create by the first main loop
    Serial.println("no existing file");
    Serial.println("will be created by");
    Serial.println("the first main loop");
    
    
   }
   
  // end of init
  Serial.println("-----end init SD-----");
  
}

Vous comprenez pourquoi?

quelle est la valeur de file_name ?

char file_name[] = "DATALOG.CSV";

Tu serais pas à court de RAM par hasard? Parce que la librairie SD elle est gourmande la bougresse.

Ben je me suis posé la même question donc j’ai inséré un petit freeRAM() avant/après et je tourne autour des 300/400 de dispo.
Le test sur SD.open ne fonctionnait pas car j’avais un dépassement de variable tableau char donc ça faisait reset à chaque fois, je ne dépassais pas la phase du setup.

J’ai finalement résolu le problème en faisant d’abord un SD.open en LECTURE ce qui fait que s’il ne trouve pas le fichier il passe à la suite (le fichier étant créé par la première boucle dans le main loop à la suite), s’il trouve un fichier il récupère les données et continue.

Je n’ai gardé que le strict nécessaire au niveau des manipulations de chaines:

oid init_SD(){

  // Init  
  //Serial.println("-----start init SD-----"); 
    if (!SD.begin()) {
      Serial.println("Init failed!");
      return;
    }
    else
    {
      Serial.println("Init OK");
    }
  
  file = SD.open(file_name, FILE_READ);
  //Serial.println(file);

  if(file){
    digitalWrite(PIN_RED_LED, HIGH); //power ON led on the board when printing on SD Card
    file.seek(file.size()-(nombreLigneVoulues * (set_cursor + 2)));
    int j=0;
    char chaine2[12]="TT.TT;TT.TT";
    while(file.available() && j<=11)
    {
    chaine2[j] = file.read();
    //Serial.print(chaine[i]);
    j++;
    }
    chaine2[j] = '\0';
    
    //Serial.print("fin chaine lue: ");
    //Serial.println(chaine2);
    
    
    // Start conversion
     int k=0;
     int l=0;
     while (chaine2[k]!=';'){
     buf1[l] = chaine2[k];
     k++;
     l++;
     }
     buf1[l]='\0';
     k++;
     l=0;
     while (chaine2[k]!='\0'){
     buf2[l] = chaine2[k];
     k++;
     l++;
     }
    
    temp_min=atof(buf1);
    temp_max=atof(buf2);
 
    if (temp_min==0){ temp_min = 99;}
    if (temp_max==0){ temp_max = -99;}
   
    //Serial.print("max temp SD: ");
    //Serial.println(temp_max);
    //Serial.print("min temp SD: ");
    //Serial.println(temp_min);
    
    //end reading
    digitalWrite(PIN_RED_LED, LOW); //power OFF led on the board when ENDING printing on SD Card
    file.close();
    delay(10);
    
  }
  else //if exists read file and restore max min temp
  {  
   
   // if the file does'nt exists do nothing it will
   // be create by the first main loop
    Serial.println("no existing file");
    Serial.println("will be created by");
    Serial.println("the first main loop");
    
    
   }
   
  // end of init
  //Serial.println("-----end init SD-----");
  
}

Maintenant il faut que je m’occupe de la partie réception et là c’est pas gagné :smiley: