config.txt sur une sd card

Bonjours,

Je cherche a récupérer des variables sur une carte SD dans un fichier .TXT.

j'arrive a trouver la présence du fichier, mais impossible de sortir et enregistrer les variables dans l'arduino ethernet.

j'ai essayé une librairie fileinit qui ne marche pas ou que je n'arrive pas a utiliser.

pouvez vous m'aider?

merci

voici le fichier config
[heureON]
hON = 08

[heureOFF]
hOFF = 16

voici le programme

///////////////////////////// gestion du .INI///////////////////////////////////
 #include <SD.h>
   File myFile;
    //int heureON = (0);
   //int hON = (0);
   //char *hon[] ={ "hON"};
   //char myfile[10]; 
void setup()
{
 
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  pinMode(10, OUTPUT);
   
  if (!SD.begin(4)) 
     {
    Serial.println("initialization failed!");
    return;
      }
  Serial.println("initialization done.");
  myFile = SD.open("config.txt", FILE_READ);
 
    // lit le fichier config
    while (myFile.available())
    {
       Serial.write(myFile.read());
    // extaits les valeurs du fichiers config
       
      // if (strcmp(myFile,hon) == 0) {
      // Serial.println("trouvé");
        
    }
    // ferme le fichier:
    myFile.close();
  } 


void loop()
{
	// nothing happens after setup
}

Salut, strcmp() te dit si tes 2 chaines sont identiques.

Tu devrais plutôt utiliser strstr() qui te donne la position de la première occurrence de ta chaine1 dans chaine2.

Ensuite y a un autre problème, il faudra savoir comment se comporte exactement ce code :

    while (myFile.available())
    {
       Serial.write(myFile.read());
       ....

Parce qu'en C, normalement, selon la taille du fichier, il ne le lit pas en entier, et peut te parcourir le fichier en plusieurs voir, ou ligne par ligne ?
Ca une importance, car s'il lisait le fichier, avec une coupure en pleine ligne, il serait possible qu'un mot que tu cherches sur cette ligne soit coupé en 2, et que tu ne puisses dont pas le trouver.

De plus, sur microcontroleur, on a pas de mémoire pour charger en ram tout le fichier.
Donc pour cette question, faut attendre la réponse de quelqu'un d'autre.

EDIT :

Il y a aussi myFile.seek() qui éviterai le problème du dessus.
Il sert à te positionner dans le fichier. Donc tu parcours dans une première boucle ton fichier caractère par caractère, et à chaque caractères, tu vérifies ensuite si le char sur lequel tu es = le 1er de ta chaine, si le char actuel +1 = le 2ème de ta chaine, etc... jusqu'au '\0' de ta chaine.

salut, tout devrais fonctionné vue tes config et le nom du fichier qui respect bien les 8 caractères + extension, après je pense que tu devrai faire simple, déja, SD.read ne te donne que le prochaine octet du fichier donc fait plutôt:

string lecture;

lecture += myfile.read();

et après tu l'envoie sur Serial.print tu à moins de risque de voir des problème apparaître.

Skizo !

merci je vais essayer sur cette base,
j'ai reassayé la librairie fileinit mais elle ne marche pas dommage

salut il y a quelque temps j'avais le me souci que toi pour mon projet , je ne suis pas une bon programeur j'ai donc bidouiller ça si cela peut t'aider
le code de sauve garde sur la SD:

void saugardeConfig(){

  //---- efface l'ancien fichier  au préalable ---
  test=SD.remove("save.txt"); // efface fichier et mémorise résultat opération  
  if (test==true) {
    lcd.drawText(5,5,"Ancien fichier efface",1,COLOR_BLACK,couleur_fond );//Serial.println("Fichier efface");
  }; // affiche message si fichier bien effacé
  file = SD.open("save.txt", FILE_WRITE); // ouvre le fichier en écriture// NB : le fichier est créé si il n'existe pas !

  //---- test si fichier dispo en écriture 
  if (file==false) {
    lcd.drawText(5,20,"Erreur ouverture fichier !",1,COLOR_BLACK,couleur_fond );//Serial.println ("Erreur ouverture fichier !")
    ;
  } // si fichier pas dispo
  else {
    lcd.drawText(5,30,"Nouveau fichier pret pour ecriture !",1,COLOR_BLACK,couleur_fond ); //Serial.println ("Fichier pret pour ecriture !");// si le fichier existe et est ouvert
    // premiere ligne du fichier CSV - entete avec liste des champs
    //Serial.println ("ecriture A");

    file.print("TCH_chauffage_Piece=");
    file.print(TCH_chauffage_Piece);
    file.println(";");
//pour le cas ou la variable n'est pas un float on convertie le int en float
 file.print("B=");
    file.print(float(B));
    file.println(";");//

    lcd.drawText(5,60,"Fin enregistrement !",1,COLOR_BLACK,couleur_fond );//Serial.println("Fin enregistrement !");
    file.close(); // ferme le fichier  
    lcd.drawText(5,90,"Fermeture fichier !",1,COLOR_BLACK,couleur_fond );//Serial.println("Fermeture fichier !");
    delay(2000);
  };
  lcd.clear(couleur_fond);
  selecteurPage=1;
  return;
}

et pour la restoration des donné :

void restorConfig(){ 
  file = SD.open("save.txt", FILE_READ); // ouvre le fichier lecture
  if (file==false) {
    lcd.drawText(5,75,"Erreur ouverture fichier !",1,COLOR_BLACK,couleur_fond );//Serial.println ("Erreur ouverture fichier !");
  }// si fichier pas dispo
  else {
    // si le fichier existe et est ouvert 
    lcd.drawText(5,95,"Fichier pret pour lecture !",1,COLOR_BLACK,couleur_fond );//Serial.println ("Fichier pret pour lecture !");
    lcd.drawText(5,115,"Lecture fichier",1,COLOR_BLACK,couleur_fond );
    delay(1000);
    lcd.clear(couleur_fond);

    unsigned long i;
    float valeur;
    byte y=0;
    int a=0;
    for (i=0;i<=(file.size());i=(file.position()+1L)){
      file.seek(i);
      valeur=file.parseFloat ();
      a=a+1;
      lcd.printOptions(1, COLOR_BLACK, couleur_fond);
      lcd.printXY(0,y);
      switch(a){
      case 1:
        TCH_chauffage_Piece=valeur;
        lcd.print("TCH_chauffage_Piece");
        break;
      case 2:
         B=valeur;
        lcd.print("B");
        break;

      };
      lcd.print(" val:");
      lcd.print(valeur);
      lcd.print(" a:");
      lcd.print(a);
      y=y+15;
      if (y>220){
        lcd.clear(couleur_fond); 
        y=0;
      };
      delay(100);
    }

    lcd.clear(couleur_fond);
    lcd.drawText(5,105,"Fermeture fichier !",1,COLOR_BLACK,couleur_fond );//Serial.println("Fermeture fichier !");
    lcd.drawText(5,125,"Restauration terminer",1,COLOR_BLACK,COLOR_GREEN );//Serial.println("Fermeture fichier !");
    file.close();

  };
  delay(1000);
  lcd.clear(couleur_fond);
}

beaucoup de partie du code serve a afficher les valeur a l'ecrant

en esperant que sa te soit utile!

je vais essayer sur ces bases mais dommage qu'il n'existe pas une librarie qui fonctionne

Bonjour,

Je fait un morceau de code qui permet de lire un fichier de configuration au format texte.
Ça m'as pris une bonne heure mais il marche :wink:

Il y a 3 régles à respecter pour qu'il marche correctement :

  • fin de lignes au format UNIX (\n)
  • les lignes de commentaires ne doivent pas avoir d'espaces ou de tabulations avant le #
  • il faut impérative ajouter une ligne à la fin du fichier

Le code du programme de test + parser de fichier :

/* Includes */
#include <SPI.h>
#include <SD.h>

/* Buffer size */
const byte BUFFER_SIZE = 32;

/* User variables */
int toto = 0, tata = 0, titi = 0;

/* setup() */
void setup() {

  /* Declare global buffer and pair pointers */
  char buffer[BUFFER_SIZE], *key, *value;

  /* Declare iterator, buffer lenght and line counter */
  byte i, buffer_lenght, line_counter = 0;

  /* Initialize serial port */
  Serial.begin(9600);
  Serial.println("Config file parsing example");

  /* Initialize SD card */
  pinMode(10, OUTPUT);
  if (!SD.begin(4)) { // Handle error 
    Serial.println("SD card error !");
    for(;;);
  }

  /* Open configuration file */
  File config_file = SD.open("config.txt", FILE_READ);
  if(!config_file) { // Handle error
    Serial.println("Open file error !");
    for(;;);
  }

  /* While not end of file */
  while(config_file.available() > 0 ){

    /* Buffering one line */
    i = 0;
    while((buffer[i++] = config_file.read()) != '\n') {

      /* If line is longest than buffer size */
      if(i == BUFFER_SIZE) {

        /* Finish processing of line (without storing data) */
        while(config_file.read() != '\n');
        break; // Stop buffering
      }
    }

    /* Store number of char filled in buffer */
    buffer_lenght = i;

    /* Hnadle buffer overflow */
    if(i == BUFFER_SIZE) {
      Serial.print("Line overflow at line ");
      Serial.println(line_counter, DEC);
    }

    /* Finalize ASCIIZ string (and strip \n at end) */
    buffer[--i] = '\0';

    /* Increment line counter */
    ++line_counter;

    /* Skip empty line or comment line */
    if(buffer[0] == '\0' || buffer[0] == '#') continue;
      
    /* Process key field (skip tabs and spaces at start of string) */
    i = 0;
    while(buffer[i] == ' ' || buffer[i] == '\t') {
      if(++i == buffer_lenght) break; // Skip lines with just tabs and spaces
    }
    if(i == buffer_lenght) continue; // Handle lines with just tabs and spaces
    key = &buffer[i];

    /* Search fields separator = (skip tabs and spaces at start of string) */
    while(buffer[i] != '=') {

      /* Strip tabs and spaces */
      if(buffer[i] == ' ' || buffer[i] == '\t') buffer[i] = '\0';
        
      if(++i == buffer_lenght) {
        Serial.print("Parsing separator error at line ");
        Serial.println(line_counter, DEC);
        break; // Skip malformed lines
      }
    }
    if(i == buffer_lenght) continue; // Handle malformed lines

    /* Skip separator */
    buffer[i++] = '\0';

    /* Process value field (skip tabs and spaces at start of string) */
    while(buffer[i] == ' ' || buffer[i] == '\t') {
      if(++i == buffer_lenght) {
        Serial.print("Parsing value error at line ");
        Serial.println(line_counter, DEC);
        break; // Skip malformed lines
      }
    }
    if(i == buffer_lenght) continue; // Handle malformed lines
    value = &buffer[i];

    /* Compute and store key / value pair */
    if(strcmp(key, "toto") == 0) {
      toto = atoi(value);
    } 
    else if(strcmp(key, "tata") == 0) {
      tata = atoi(value);
    } 
    else if(strcmp(key, "titi") == 0) {
      titi = atoi(value);
    } 
    else { // Default 
      Serial.print("Unknown key ");
      Serial.println(key);
    }

  }

  /* Close configuration file */
  config_file.close();

  /* Print configuration result */
  Serial.print("toto = ");
  Serial.println(toto);
  Serial.print("tata = ");
  Serial.println(tata);
  Serial.print("titi = ");
  Serial.println(titi);
}

/* loop() */
void loop() {
  // Nothing to do here
}

Exemple de fichier de configuration (aussi en fichier joint) :

# Ceci est un commentaire

# Toto
toto = 42

   titi   =  1337
      	
tata=7

Et le résultat sur le serial monitor :

Config file parsing example
Parsing separator error at line 7
toto = 42
tata = 7
titi = 1337

(L'erreur ligne 7 est normal, j'ai volontairement ajouté une tabulation pour montrer que le programme continue en cas de ligne mal formé)

config.txt (78 Bytes)

la c'est bien plus rechercher que ce que j'avais fait va falloir que je regarde ça de prés aussi!! :smiley:

super cela me semble tres bien merci a tous pour votre travail je vais essayer d'integrer cela

Bonjour,

Je suis parti de l'exemple de [Arduino] Charger un fichier de configuration depuis une carte SD | Skyduino - Le DIY à la française pour parcer un fichier .conf.

Par contre je n'arrive pas à récupérer les chaines de caractères avec "strncpy", pouvez-vous m'aider svp?
pi:

  • je respecte bien les 3 règles comme dans l'exemple.
  • un "Serial.println(value);" dans chaque "if" affiche bien la bonne valeur

J'ai vraiment un pb pour l'enregistrement en variable...

Voici le résultat:

box_name = BOX_000127/10/2013 22:50:2
box_conf_update = 27/10/2013 22:50:2

fichier .conf

# Preferences
box_name = BOX_0001
box_conf_update = 27/10/2013 22:50:2

Code:

void boxIni()
{

  /* Déclare le buffer qui stockera une ligne du fichier, ainsi que les deux pointeurs key et value */
  char buffer[BUFFER_SIZE], *key, *value;
 
  /* Déclare l'itérateur et le compteur de lignes */
  byte i, buffer_lenght, line_counter = 0;

  // Preferences
char box_name[9];
  char box_conf_update[19];

  // Open file
  File config_file = SD.open(fileNameInit, FILE_READ);
  if(!config_file) { // Gère les erreurs
    Serial.println("Pas de fichier");
  }


  /* Tant que non fin de fichier */
  while(config_file.available() > 0 ){
 
    /* Récupère une ligne entière dans le buffer */
    i = 0;
    while((buffer[i++] = config_file.read()) != '\n') {
 
      /* Si la ligne dépasse la taille du buffer */
      if(i == BUFFER_SIZE) {
 
        /* On finit de lire la ligne mais sans stocker les données */
        while(config_file.read() != '\n');
        break; // Et on arrête la lecture de cette ligne
      }
    }
 
    /* On garde de côté le nombre de char stocké dans le buffer */
    buffer_lenght = i;
 
    /* Gestion des lignes trop grande */
    if(i == BUFFER_SIZE) {
      Serial.print("Ligne trop longue à la ligne ");
      Serial.println(line_counter, DEC);
    }
 
    /* Finalise la chaine de caractéres ASCIIZ en supprimant le \n au passage */
    buffer[--i] = '\0';
 
    /* Incrémente le compteur de lignes */
    ++line_counter;
 
    /* Ignore les lignes vides ou les lignes de commentaires */
    if(buffer[0] == '\0' || buffer[0] == '#') continue;
       
    /* Cherche l'emplacement de la clef en ignorant les espaces et les tabulations en début de ligne */
    i = 0;
    while(buffer[i] == ' ' || buffer[i] == '\t') {
      if(++i == buffer_lenght) break; // Ignore les lignes contenant uniquement des espaces et/ou des tabulations
    }
    if(i == buffer_lenght) continue; // Gère les lignes contenant uniquement des espaces et/ou des tabulations
    key = &buffer[i];
 
    /* Cherche l'emplacement du séparateur = en ignorant les espaces et les tabulations âpres la clef */
    while(buffer[i] != '=') {
 
      /* Ignore les espaces et les tabulations */
      if(buffer[i] == ' ' || buffer[i] == '\t') buffer[i] = '\0';
         
      if(++i == buffer_lenght) {
        Serial.print("Ligne mal forme a la ligne ");
        Serial.println(line_counter, DEC);
        break; // Ignore les lignes mal formé
      }
    }
    if(i == buffer_lenght) continue; // Gère les lignes mal formé
 
    /* Transforme le séparateur = en \0 et continue */
    buffer[i++] = '\0';
 
    /* Cherche l'emplacement de la valeur en ignorant les espaces et les tabulations âpres le séparateur */
    while(buffer[i] == ' ' || buffer[i] == '\t') {
      if(++i == buffer_lenght) {
        Serial.print("Ligne mal forme a la ligne ");
        Serial.println(line_counter, DEC);
        break; // Ignore les lignes mal formé
      }
    }
    if(i == buffer_lenght) continue; // Gère les lignes mal formé
    value = &buffer[i];
 
    /* Transforme les données texte en valeur utilisable */
    /* C'est ce morceaux de code qu'il vous faudra adapter pour votre application  */

   if(strcmp(key, "box_name") == 0) {
      int len = strlen(value) +1 ;
    strncpy (box_name, value, len);
    }

    else if(strcmp(key, "box_conf_update") == 0) {
       int len = strlen(value) ;
      strncpy (box_conf_update, value, len);
    }

    else { // Default 
      Serial.print("Clef inconnu ");
      Serial.println(key);
      }
 
  }
 
  /* Ferme le fichier de configuration */
  config_file.close();
 
  /* Affiche le résultat de la configuration */

  Serial.println("---------------------------------------------------");
  Serial.print("box_name = ");
  Serial.println(box_name);

  Serial.print("box_conf_update = ");
  Serial.println(box_conf_update);


} // end boxinit

Juste avant ta série de strcmp() ajoute une ligne pour afficher le contenu de "key" et "value".
Si le contenu de "value" est bon c'est que ton strncpy() est mauvais.

Ps: un simple strcpy (box_name, value); suffit, pas besoin de strncpy() surtout si tu ne fixes pas la taille max réelle de ta variable dans l'argument "size".

strcpy (box_name, value);
// ou
strncpy (box_name, value, sizeof(box_name));

skywodd:
Juste avant ta série de strcmp() ajoute une ligne pour afficher le contenu de "key" et "value".
Si le contenu de "value" est bon c'est que ton strncpy() est mauvais.

Ps: un simple strcpy (box_name, value); suffit, pas besoin de strncpy() surtout si tu ne fixes pas la taille max réelle de ta variable dans l'argument "size".

strcpy (box_name, value);

// ou
strncpy (box_name, value, sizeof(box_name));

Merci pour ton retour, j'ai trouvé la solution un peu par hasard en testant:

Pour stocker 8 caractères, il faut que je déclare un char de minimum 9 ==> box_name[9];

Puis pour récupérer la valeur dans ma variable je dois ajouter un '\0' à box_name[strlen(value)-1]:

   if(strcmp(key, "box_name") == 0) {
    strncpy(box_name,value,strlen(value));
    box_name[strlen(value)-1]='\0';
    }

Oui effectivement j'avais complétement oublié de le préciser, désolé.

Une chaine de caractère en C est toujours de type ASCIIZ (bien noter le Z à la fin).
Cela signifie que tout chaine de caractère se termine par un \0 qui délimite la fin de la chaine en mémoire.

Exemple :
"toto" = 4 caractères
En mémoire :
{ ''t, 'o', 't', 'o', '\0' } = 5 octets

NB: le \0 est une notation spécial qui signifie "caractère nul", soit = 0 (la valeur numérique).

Salut à Tous,
Je cherche a faire la même chose, mais j'utilise arduino Yun, Donc le code et un peu différent concernant l'accée à la carte SD.
Mon problème se situe au niveau de la recuperation des données depuis le fichier sur la SD.
Quelque soit le code que j'utilise,
Voici ce que j'ai dans mon fichier texte :

Detecteur[0]=Activer
Detecteur[1]=Activer
Detecteur[2]=Activer
Detecteur[3]=Activer
Detecteur[4]=Activer
Detecteur[5]=Activer
Detecteur[6]=Activer
Detecteur[7]=Activer
Detecteur[8]=Activer
Detecteur[9]=Activer
Detecteur[10]=Activer
Detecteur[11]=Activer
Detecteur[12]=Activer
Detecteur[13]=Activer
Detecteur[14]=Desactiver
Detecteur[15]=Desactiver
Temperature=Activer

Et voila ce que je recupere :

Detecteur[0]=Activer
Detecteur[1]=Activer
Detecteur[2]=Activer
etecteur[3]=Activer
Detecteur[4]=Activer
Detecteur[5]=Activer
Dtecteur[6]=Activer
Detecteur[7]=Activer
Detecteur[8]=Activer
Deecteur[9]=Activer
Detecteur[10]=Activer
Detecteur[11]=Activer
Dtecteur[12]=Activer
Detecteur[13]=Activer
Detecteur[14]=Desactier
Detecteur[15]=Desactiver
Temperature=Activer

Et la parti de code que j'ai utilisé pour faire un test :

String output;
  digitalWrite(led, LOW);
  while(!Serial);  // wait for Serial port to connect.
  File activationFile = FileSystem.open("/mnt/sd/arduino/www/maison/activati.txt");
  while (activationFile.available()) {
    output += (char)activationFile.read();
  }
  Serial.println(output);
  activationFile.close();

Les données que je recupere sont altérées, il manque des caractères, du coup c'est inexploitable.
Quelqu'un a t-il eu le même problème avec un arduino Yun ? et sinon, y a t-il un solution ?