Arduino Forum

International => Français => Topic started by: Microbulle on Oct 26, 2012, 08:19 pm

Title: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Oct 26, 2012, 08:19 pm
Bonsoir,

Je m'interroge depuis quelques jours sur la possibilité de mémorisé des paramètres sur une carte SSD de type appareil photo.

Chaque modèle utilisé avec ma télécommande à sa propre programmation. Ainsi, en extérieur, je me crée un .txt qui contient des infos.

Quote
Modèle-01
Nom = Test1
Mixage_V1V2 = false
Mixage_V3V4 = false
Mixage_V1I1 = false
... Ainsi de suite


J'aimerais éviter de passer par une shield éthernet donc brancher en direct sur l'arduino. Que me conseilleriez-vous au niveau câblage simple pour utiliser la mémoire externe.

Sinon, la solution bis est de se servir de la mémoire interne à l'arduino. Je trouve qu'il serais plus pratique d'avoir une carte pour stocker ces infos. La compatibilité avec le pc en plus.

Merci pour les infos.
Title: Re: Quelle solution choisir ?
Post by: elriri on Oct 26, 2012, 08:53 pm
La carte SD semble une bonne solution avec pourquoi pas un stockage dans un fichier xml, mais ne compte pas stocker directement sur l'arduino trop peux de place...
Title: Re: Quelle solution choisir ?
Post by: Microbulle on Oct 27, 2012, 09:22 pm
Ok pour passé sur une SD.

J'ai un lecteur que je peux dessouder d'un appareil qui ne fonctionne plus et d'ont le lecteur (la pièce qui permet de plugger une micro sd) est récupérable. Par contre, si j'ai bien suivie les tutos que j'ai pu voir, deux écoles s'offre à moi. La solution SPI et la solution pin à partir de 53 sur la méga.

Je vais faire des essais sur une uno puis porter sur méga. Je pensait me servir du SPI. Par contre faut-il faire un raccordement direct SPI -> Lecteur ou il y a besoin d'une électronique d'interfaçage ?

Voila, pour le moment j'en suis là.

Ok pour le xml quoi que le parser j'en ai de très mauvais souvenir. Peut-être qu'avec un exemple sur la librairie SPI... ? Enfin je veux bien quelques sources pour me pencher dessus.

Je laisse tomber la carte éthernet car elle a beaucoup d'options qui ne seront pas mise en ouvre au final.
Title: Re: Quelle solution choisir ?
Post by: B@tto on Oct 28, 2012, 11:22 am
Pourquoi ne pas simplement utiliser la librairie faite pour ? http://arduino.cc/en/Reference/SD

:)
Title: Re: Quelle solution choisir ?
Post by: Microbulle on Oct 28, 2012, 11:36 am
Ok pour ça !

A ce moment là, comme je disait plus haut, comment passé de l'interface SPi à la carte SD (électroniquement parlant) ?

Si c'est jouable, bien sûr que je me baserais sur le code déjà écrit !
Title: Re: Carte SD - Câblage et programmation - Choix effectués - XML
Post by: SesechXP on Oct 28, 2012, 12:02 pm
Salut,

Il faut adapter les signaux 0-5V de l'Arduino vers des signaux 0-3,3V de la carte SD. Tu peux t'inspirer de shields existants : Arduino Wireless Shield (http://arduino.cc/en/Main/ArduinoWirelessShield),  Snootlab Mémoire (http://snootlab.com/shields-snootlab/86-memoire-fr.html), Adafruit Logger Shield (http://www.ladyada.net/make/logshield/design.html), etc...

++
Title: Re: Carte SD - Câblage et programmation - Choix effectués - XML
Post by: Microbulle on Oct 28, 2012, 12:33 pm
Ah wai ! Du 3.3V !

Alors, dans ce cas, peut-être que je devrais pour démystifier le principe de fonctionnement du SPI et de la carte SD, passé par le shield ethernet...

Ensuite, étudier un schéma pour s'affranchir du module et descendre sur 3.3V.

Ceci dit, je dispose aussi d'une sortie en 3.3V au niveau de la méga. Peut-être qu'en passant par cette tension, cela résoudrais le souci d'interfaçage.

Merci pour les liens, certain m'étais déjà connus et je pensait à tort que c'étais une liaison type fil à fil.
Title: Re: Carte SD - Câblage et programmation - Choix effectués - XML
Post by: Microbulle on Oct 29, 2012, 09:53 am
Bonjour,

J'ai de la chance, le module shield éthernet me permet quand même de me servir, sur ma méga 2560, de mes voies analogiques à priori. Je me sert de toutes les voies, c'est à dire de AN0 à AN15.

Je vais donc non seulement pouvoir stocher sur une carte SD 512Mo pour les test, mais plus tard, pourquoi pas 1 ou 2Go mes modèles.

Est-ce que se servir de l'ICSP bloque les voies analogiques ? Est-ce que ça risque de poser problème sur les voies type PWM et I2C ?

Enfin, dernière question, si je me base sur la librairie ICSP, SD et éthernet, je risque pas de voir des fonctions qui fonctionnent parfaitement poser problème ?

Pour info, mon programme doit resté dans les 80 à 90ms pour que la transmission entre la télécommande et le modèle soit bien prise en compte.

Merci beaucoup pour votre retour.
Title: Re: Carte SD - Câblage et programmation - Choix effectués - XML
Post by: barbudor on Oct 29, 2012, 11:16 am
Le shield Ethernet n'utilise que le bus SPI, les pins numériques 4 (CS de la SD) et 10 (CS de l'Ethernet)

Aucun conflit avec les analog et les PWM

Attention, sur une Mega, le bus SPI présent sur le connecteur ICSP se retrouve aussi sur les broches 52 à 54 de mémoire (vérifier).
Sur une UNO c'est les broches 11, 12 et 13.
Title: Re: Carte SD - Câblage et programmation - Choix effectués - XML
Post by: Microbulle on Oct 29, 2012, 02:19 pm
En effet, sur la méga, ça me prends 4 pins de plus  :smiley-eek:

Code: [Select]

/*
  Télécommande sur 433 Mhz bi-directionnelle
  ------------------------------------------

  Création : le 29 octobre 2012
  Version 1.0
  ------------------------------------------
 
            Pins utilisés
  TX1 -> Modem 433Mhz
  RX1 <- Modem 433Mhz
  SDA <-> Data I2C
  SCL <-> Horloge I2C
 
  SPI <-> Carte Ethernet / SD Card
  04 (PWM) -> Ethernet CS
 
  10 (PWM) -> Ethernet Librairie
  50 (Digit) -> Ethernet Librairie
  51 (Digit) -> Ethernet Librairie
  52 (Digit) -> Ethernet Librairie
  53 (Digit) -> Ethernet Librairie
 
  AN0 -> Voie 1
  AN1 -> Voie 2
  AN2 -> Voie 3
  AN3 -> Voie 4
 
  22 (Digit) -> Voie 5 = Btn On/Off/On 1
  23 (Digit) -> Voie 5 = Btn On/Off/On 1
  24 (Digit) -> Voie 6 = Btn On/Off/On 2
  25 (Digit) -> Voie 6 = Btn On/Off/On 2
 
  Pour infos:
  - Les voies analogiques sont reliée chacune à leur potar.
 
  - 22 et 23 Corresponde à un potar à 3 positions.
  - 00 = Milieu
  - 10 = Haut
  - 01 = Bas
 
  - 24 et 25 Corresponde à un potar à 3 positions.
  - 00 = Milieu
  - 10 = Haut
  - 01 = Bas
 
*/


Ceci dit, je pense m'orienter sur un fichier config.txt organisé comme suit :
Quote

MODELE-01,Nom,Type,Conf1,Conf2,Conf3,Conf4...
MODELE-02,Nom,Type,Conf1,Conf2,Conf3,Conf4...
MODELE-03,Nom,Type,Conf1,Conf2,Conf3,Conf4...


MODELE-01 à 99 : pour passer d'un modèle à un autre.
Nom : Nom à rappeler sur l'écran LCD
Type : Le type de modèle à rappeler sur l'écran LCD
Conf1, Conf2....Conf4 peuvent prendre consécutivement des chiffres(0, 1... 10, 100, 1000), des lettres (true, false) ou bien des caractères de personnalisation tel que (a,b,c...toto, tata...) et enfin des bytes (0x00 à 0xFF) voir même des binaires ou des exa (00000000 à 11111111  et 0 à 255). Bref tout ce qui doit concerner la personnalisation de mon programme.

A terme je devrais à la fois pouvoir lire les infos mais aussi modifier certaines valeurs. Il sera impossible de créer un modèle car ce sera fait de l'extérieur avec des données standards par défaut. En l'absence de carte, on se fie aux données de la télécommande. Remarque je peux aussi partir de ces données et créer un profil. Je commence par la lecture, je verrais l'écriture après :)
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 30, 2012, 10:14 am
J'avance un peu.

J'ai fait un bout de code qui me retourne un nomnre. Hélas, ce n'est pas le nombre de lignes comme je le supposait au départ mais je pense le nombre de caractère. Ou autre chose.

Mon fichier, pour le moment contient 3 lignes. Le code me retourne 39  :smiley-sweat:

Voila le bout de code que j'ai fait:
Code: [Select]

/* FONCTION qui retournera le nombre de ligne du fichier */
int lectureConf_NB() {
 
  int nb=0;
 
  while(myFile.read() != '\n') {
   
    nb++;
  }
  return nb;
}

/*  FONCTION qui retournera un tableau des valeurs contenus */


Je m'y suis peut-être mal pris !
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: SesechXP on Oct 30, 2012, 12:00 pm
Salut,

En effet, il y a une erreur de logique. Dans ce que tu as écrit ton compteur s'incrémente tant que le caractère lu est différent de '\n'.
Sauf que tu veux parcourir ton fichier jusqu'à la fin, c'est à dire tant que tu n'as pas trouvé le caractère nul '\0'. Et compter le nombre de '\n' rencontrés sur le parcours.

Je te laisse chercher un peu ;)
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 30, 2012, 12:55 pm
Merci SesechXP.

Grâce à ta piste je viens de trouver la solution.

En fait, je me suis souvenu avoir li que myFile.available() passé jusqu'au prochain caractère, sauf quand c'est un null. Ça tombe bien, c'est ce que je voulais faire !

Du coup, je n'ai plus eu à faire que:
Code: [Select]

/* FONCTION qui retournera le nombre de ligne du fichier */
int lectureConf_NB() {
 
 
  int nb=0;
 
  //Parcourir le fichier jusqu'à un caractère null
  while(myFile.available()) {
     
    //Si il est rencontrer un saut de ligne
    if(myFile.read() == '\n') {
       
      //Compter
      nb++;
    }
  }
 
  //Retourner le nombre de lignes parcouru
  return nb;
}


Bon, maintenant, je passe à la suite. La fonction qui va me retourné un tableau de String de la ligne spécifique.
Algorithmiquement parlant, je ferais ceci:
Code: [Select]

//lectureConf_LN(int ligne_a_lire)
  //aller à la ligne_a_lire
  //parcourir la ligne jusqu'au saut de ligne
    //Parser le contenu sur les ',' le dernier caractère étant le saut de ligne
    //Charger le tableau de string avec les valeurs parsés
//Fin de parcours
//Return tableau


Ensuite dans mon code, je dois me retrouver avec :
Quote
tableau[0]=MODELE-01
tableau[1]=Robot Go
tableau[2]=Robot
tableau[3]=true
tableau[4]=false
tableau[5]=false
tableau[6]=false


Il va de soit que je ne connais pas le nombre de variable à l'avance. Donc je pense limité à la seule ligne. Ensuite, je ne sait pas si par exemple, on peut faire cela:
Code: [Select]

boolean Mix_V1V2 = false;

//Charger la configuration
Mix_V1V2 = tableau[3];

//Si le mixage Voie 1 avec Voie 2 est activé
  if(Mix_V1V2) {
    //Mixage voie 1 et voie 2
    mixVoie1 = abs(voies[1] - (voies[2]-90));
    mixVoie2 = abs(voies[1] + (voies[2]-90));
   
    //Réécrire les voies avec le mixage
    voies[1] = mixVoie1;
    voies[2] = mixVoie2;
  }


Comme on va le voir, j'ai besoin de tester des cas sur du contenu de variable. Pas sûr que ça fonctionne.

Déjà, voyons pour récupérer les infos et éventuellement anticiper pour traiter ensuite les données.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 30, 2012, 05:41 pm
Bon et bien, j'ai changer d'avis ! Comme quoi, il faut parfois en arrivé à un stade pour re pensé la problématique.

Donc, au lieu de gérer des lignes, très lourd et obligeant à parcourir le fichier intégrale plusieurs fois, je me suis dit que ce serais mieux d'a voir la liste de plusieurs fichiers qui eux aurait la configuration d'un modèle.

Ainsi, actuellement la SD card à 4 fichiers. memo.txt, modele-001.txt, modele-002.txt et modele-003.txt.

Je cherche à lister les fichiers étant nommé modele-xxx.txt et à les placés dans un tableau.

Voila je galère à trouvé ça bien que j'ai quelques pistes que j'essaie. Rien de probant pour le moment.

<Edit: Microbulle>

Bon, j'ai trouver une piste sérieuse. Ici : http://www.mon-club-elec.fr/pmwiki_mon_club_elec/pmwiki.php?n=MAIN.ArduinoExpertMemorisationSDCardAfficheContenu

J'ai synthétisé pour faire mon code afin de garder que l'essentiel. Je n'aurais pas de répertoire à gérer donc pas autant besoin de tab. Bref le code que j'ai extrait et qui fonctionne pratiquement:

Code: [Select]

File myFile;

/* SETUP */
void setup() {
//Initialiser la carte SD
  if(initSD()) {
    //Lister les fichiers présent dans la carte SD
   
    myFile = SD.open("/");
   
    while(true) {
     
      File entry = myFile.openNextFile();
     
      if(!entry) {
        break;
      }
     
      String fichier = entry.name();
     
     
      Serial.println(fichier);
    }
   
  }
 
  //Fermer le fichier
  myFile.close();
}


Par contre voila ce que ça m'affiche:
Quote

TRASH-~1
MEMO.TXT
MODELE~1.TXT
MODELE~2.TXT
MODELE~3.TXT


Donc il me faut géré le problème des noms long et nom court. Ainsi que l'élimination de TRASH-~1 et MEMO.TXT.

Merci à ceux qui sauront m'aider.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: SesechXP on Oct 30, 2012, 06:29 pm
La bibliothèque SD (http://arduino.cc/en/Reference/SD) ne gère que les fichiers au nom court au format 8.3 : 8 caractères pour le nom, 3 pour l'extension.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 30, 2012, 06:39 pm
Ok, donc à moi de renommer en court :)

Ok et que faire pour trash ? Est-ce qu'il peut être retirer de la recherche ?

J'a réussi à virer TRASH et j'ai renommer les fichiers comme suit:
Quote
MEMO.TXT
MODEL001.TXT
MODEL002.TXT
MODEL003.TXT


Maintenant, je cherche à placer ça dans un tableau. J'espère y arrivé seul. Si je voie que je bloque je vous ferais signe. Mais déjà ça avance pas mal ;)
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 30, 2012, 07:01 pm
Bon, je suis arrivé à faire un quelque-chose. Pas propre pour le moment car je teste mais je m'en occupe juste après.
Code: [Select]

File myFile;
String tblNomFic[50];

/* SETUP */
void setup() {

  //Initialiser la carte SD
  if(initSD()) {
    //Lister les fichiers présent dans la carte SD
   
    myFile = SD.open("/");
   
    int i=0;
    while(true) {
     
     
      File entry = myFile.openNextFile();
     
      if(!entry) {
        break;
      }
     
      tblNomFic[i] = entry.name();
     
      i++;
    }
  }
 
  //Fermer le fichier
  myFile.close();
 
  //Compte le nombre de fichiers
  int nbFichiers = sizeof(tblNomFic);
 
 
  Serial.println(tblNomFic[0]);
  Serial.println(tblNomFic[1]);
  Serial.println(tblNomFic[2]);
  Serial.println(tblNomFic[3]);
  Serial.println("");
  Serial.println(nbFichiers);
}


Bon, j'ai pas volontairement virer le fichier MEMO, pour le moment. A la limite je saurais que c'est n-1 le nombre de modèle.

Par contre, comme on voie, le sizeof me retourne le tableau complet et non les seuls éléments qui composent le tableau.
C'est peut-être due à mon déclaratif ?
Quote
MEMO.TXT
MODEL001.TXT
MODEL002.TXT
MODEL003.TXT

350


Merci pour votre aide.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: SesechXP on Oct 30, 2012, 08:44 pm
sizeof(tblNomFic) te donne la taille de la variable tblNomFic et donc de tous les éléments qu'elle contient.

A priori tu peux connaître le nombre de fichiers dans ta boucle while. Pourquoi ne pas le faire ici ?
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 30, 2012, 09:02 pm
Oui effectivement, c'est ce que je fais à présent avec:
Code: [Select]

File myFile;  //Fichier
String tblNomFic[10];  //Le nom des fichiers
int nbFichier;  //Nombre de fichier

/* SETUP */
void setup() {
//Initialiser la carte SD
  if(initSD()) {
   
    //Lister les fichiers de configuration présent
    nbFichier = listeFichier("test");
  }
 
  //Fermer le fichier
  myFile.close();
 
 
  Serial.println(tblNomFic[0]);
  Serial.println(tblNomFic[1]);
  Serial.println(tblNomFic[2]);
  Serial.println(tblNomFic[3]);
  Serial.println("");
  Serial.println(nbFichier);
}

/* LOOP */
void loop() {
}

/* FONCTION listerFichier() */
int listeFichier(String path) {
 
  int count = 0;
 
  myFile = SD.open(path);  //Ouvre la racine
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Rentre le nom de fichier dans un tableau
    tblNomFic[count] = entry.name();
   
    count++; //Compter le nombre de fichier
  }
 
  //Retourner le nombre de fichier
  return count;
}


J'ai un petit souci pour transmettre mon chemin. J'en profite de la fonction pour prévoir pour le cas ou on choisirais volontairement un chemin différent. On ne sait jamais dans une autre application ça peut-être utile.

Là, si j'ai bien compris, ce qui ne va pas c'est l'arrivé en string pour aller sur un char*. Je cherche une solution à ce niveau.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: SesechXP on Oct 31, 2012, 09:30 am
Une piste : string.toCharArray() (http://arduino.cc/en/Reference/StringToCharArray) ;)
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 31, 2012, 09:53 am
Bonjour,

En effet, ça fonctionne ça:
Code: [Select]

/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
  int count = 0;
  char path[32];
 
  //Conversion du chemin
  chemin.toCharArray(path, 32);
 
  //Ouvre ce qui est défini par le chemin
  myFile = SD.open(path);
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Rentre le nom de fichier dans un tableau
    tblNomFic[count] = entry.name();
   
    count++; //Compter le nombre de fichier
  }
 
  //Retourner le nombre de fichier
  return count;
}


Maintenant je pense qu'il me faut créer un répertoire pour chaque choses. Ainsi, je chargerais divers tableau en fonction de.

Deux solutions s'opposes. L'une permet de sélectionner le type de tableau avec un case. Mais j'aime pas cette méthode. L'autre est de charger dans un tableau les fichier du répertoire 1 puis de copier le contenu du tableau dans un tableau de modèle. De passé au tableau de fichier de mémo, puis de faire la même dans un second tableau. Ainsi, je pense éviter de devoir à chaque fois re écrire un code spécifique pour chaque répertoire. Enfin, c'est ce que je pense.

Ou alors, je passe en paramètre le nom du tableau que l'on veut chargé. C'est peut-être plus simple non ?

Autre chose. Maintenant que j'ai mes fichiers de dispo, comment je vais faire pour créer un tableau de type clef=valeur ? Sachant que dans mon fichier c'est clef=valeur ?

Merci pour votre aide.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 31, 2012, 10:57 am
Bon j'ai fait une modif avec des if. Ça me correspond pas trop mal et surtout ça fonctionne !
Code: [Select]
/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
  int count = 0;
  char path[32];
 
  //Conversion du chemin
  chemin.toCharArray(path, 32);
 
  //Ouvre ce qui est défini par le chemin
  myFile = SD.open(path);
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Si c'est le répertoire /modeles/
    if(chemin == "/modeles/") {
   
        //Rentre le nom de fichier dans le tableau des noms de modèles
        tblFicMdle[count] = entry.name();
    }
   
    //Si c'est le répertoire /sauvegarde/
    if(chemin == "/svgde/") {
       
      //Rentre le nom de fichier dans le tableau des noms de sauvegarde
        tblFicSvg[count] = entry.name();
    }
   
    count++; //Compter le nombre de fichier
  }
 
  //Retourner le nombre de fichier
  return count;
}


Reste maintenant à charger les valeurs contenu dans les fichier.

Je commence avec la sauvegarde qui ira chercher les données d'un autre fichier sous /svgde/memo.txt.
Ce fichier memo.txt contient:
Quote
Modele = modele001


Vaut-il mieux faire un tableau à deux dimensions. Ainsi si j'appelle ma sauvegarde avec l'index Model, je saurais qu'il faut que j'aille chercher modele001.txt. ?
Sachant que d'autres valeurs viendrons par la suite.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Oct 31, 2012, 09:15 pm
Et bien, c'est tiré par les cheveux mais je suis arrivé à quelque-chose.

Donc au démarrage, on charge deux répertoire dans un tableau chacun.
Dans un des répertoire on a un fichier qui dit quel fichier était ouvert et qui doit directement donné les valeurs à chargé.

Bon, j'en suis à cette étape ou je charge bien le fichier de configuration, mais je dois maintenant choisir entre deux cas dans mon fichier:
Quote
Modele = modele001

OU
Quote
modele001 //le model


Dans un cas il faudra éliminer le commentaire mais c'est plus simple à gérer. ou bien, moi qui suis un vrai geek et surtout un poil dans la main, on demande la clef dans un tableau à deux dimensions et on a la valeur.

Je suis tenter par le cas 2 avec Modele = modele001.

A ce moment là, comment je puis modifier ma fonction en bas pour charger les données spécifique. Sachant que la même fonction va me servir pour charger et le fichier de conf type sauvegarde, et le fichier du modèle. Donc deux tableaux à rappelés.

Le code actuel:
Code: [Select]

#define SIZE_BUFFER 32  //Nombre de case du buffer

File myFile;  //Fichier
String tblFicMdle[10];  //Le tableau des noms des fichiers modèles
String tblFicSvg[10];  //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle;  //Nombre de fichier


  //Initialiser la carte SD
  if(initSD()) {
   
    //Lister les fichier de sauvegardes
    listeFichier("/svgde/");
   
    //Lister les fichiers de configuration modèle
    nbFichierMdle = listeFichier("/modeles/");
   
    //Ouvrir le fichier de sauvegarde memo.txt
    ouvrirFichier("/svgde/" + tblFicSvg[0]);
  }
  else {
     
    //Charger les valeurs par défaut de la radio
  }
 
  //Fermer le fichier
  //myFile.close();
 
 
  /*
  Serial.println("Modeles :");
  Serial.println(tblFicMdle[0]);
  Serial.println(tblFicMdle[1]);
  Serial.println(tblFicMdle[2]);
  Serial.println("");
  Serial.println(nbFichierMdle);
  Serial.println("");
  Serial.println("Sauvegarde :");
  Serial.println(tblFicSvg[0]);
  */


/* FONCTION initSD() */
boolean initSD() {
 
  clearLcd();  //Effacer l'écran
  ecrireLcd("Init SD Card...", 01);  //Ecrire
 
  //Si la carte n'est pas présente ou qu'elle est en défaut
  if(!SD.begin(4)) {
   
    //Afficher l'écran LCD
    clearLcd();  //Effacer l'écran
    ecrireLcd("Init SD Card failed", 01);  //Ecrire
    delay(1000);
    return false;
  }
 
  clearLcd();  //Effacer l'écran
  ecrireLcd("Init SD Card done", 01);  //Ecrire
 
  delay(1000);
  return true;
}

/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
  int count = 0;
  char path[SIZE_BUFFER];
 
  //Conversion du chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre ce qui est défini par le chemin
  myFile = SD.open(path);
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Si c'est le répertoire /modeles/
    if(chemin == "/modeles/") {
   
        //Rentre le nom de fichier dans le tableau des noms de modèles
        tblFicMdle[count] = entry.name();
    }
   
    //Si c'est le répertoire /sauvegarde/
    if(chemin == "/svgde/") {
       
      //Rentre le nom de fichier dans le tableau des noms de sauvegarde
        tblFicSvg[count] = entry.name();
    }
   
    count++; //Compter le nombre de fichier
  }
 
  //Fermer le fichier
  myFile.close();
 
  //Retourner le nombre de fichier
  return count;
}

/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin) {
 
  //Variables
  char path[SIZE_BUFFER];
 
  //Transforme le chemin en tableau de carractères
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre le fichier de configuration
  myFile = SD.open(path, FILE_READ);
 
  //Erreur d'ouverture du fichier
  if(!myFile) {
   
    clearLcd();  //Effacer l'écran
    ecrireLcd("Fichier failed", 01);  //Ecrire
    for(;;); //Boucle infini (peut tre remplacer par un bouton valider)
  }
 
  //Tant que ce n'est pas la fin du fichier
  while(myFile.available()) {
    Serial.write(myFile.read());
  }
 
  //Fermer le fichier
  myFile.close();
 
  delay(1000);
}


Pour le moment je me contente d'afficher le résultat:
Quote
Modele = modele001


Dernier point, j'aimerais tant que faire ce peu que ça soit pas trop compliqué à digéré de façon à m'y retrouver ensuite. :ccool:

Merci encore et me blâmer pas trop. J'essaie d'apprendre par al pratique.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Nov 01, 2012, 09:44 am
Bonjour,

J'avance un peu mais je me heurte à une boucle infini. En partant du sujet skyduino (http://skyduino.wordpress.com/2012/06/19/arduino-charger-un-fichier-de-configuration-depuis-une-carte-sd/#comment-1477) j'ai fait mon code comme suit:
Code: [Select]

#define SIZE_BUFFER 32  //Nombre de case du buffer

char bufferConf[SIZE_BUFFER];  //Le buffer des fichiers de conf
String tblConfSvg[clef][valeur];  //Tableau de configuration Sauvegarde
String tblConfMdle[clef][valeur];  //Tableau de configuration valeur

/* SETUP */
void setup() {
//Initialiser la carte SD
  if(initSD()) {
   
    //Lister les fichier de sauvegardes
    listeFichier("/svgde/");
   
    //Lister les fichiers de configuration modèle
    nbFichierMdle = listeFichier("/modeles/");
   
    //Ouvrir le fichier de sauvegarde memo.txt
    ouvrirFichier("/svgde/", tblFicSvg[0]);
  }
  else {
     
    //Charger les valeurs par défaut de la radio
  }
}

/* LOOP */
void loop() {
}

/* FONCTION initSD() */
boolean initSD() {
 
  clearLcd();  //Effacer l'écran
  ecrireLcd("Init SD Card...", 01);  //Ecrire
 
  //Si la carte n'est pas présente ou qu'elle est en défaut
  if(!SD.begin(4)) {
   
    //Afficher l'écran LCD
    clearLcd();  //Effacer l'écran
    ecrireLcd("Init SD Card failed", 01);  //Ecrire
    delay(1000);
    return false;
  }
 
  clearLcd();  //Effacer l'écran
  ecrireLcd("Init SD Card done", 01);  //Ecrire
 
  delay(1000);
  return true;
}

/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
  int count = 0;
  char path[SIZE_BUFFER];
 
  //Conversion du chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre ce qui est défini par le chemin
  myFile = SD.open(path);
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Si le nombre de fichier est plus important que le nombre de place en tableau
    if(count == nbFic) {
     
      break;  //Sortir de la boucle
    }
   
    //Si c'est le répertoire /modeles/
    if(chemin == "/modeles/") {
   
        //Rentre le nom de fichier dans le tableau des noms de modèles
        tblFicMdle[count] = entry.name();
    }
   
    //Si c'est le répertoire /sauvegarde/
    if(chemin == "/svgde/") {
       
      //Rentre le nom de fichier dans le tableau des noms de sauvegarde
        tblFicSvg[count] = entry.name();
    }
   
    count++; //Compter le nombre de fichier
  }
 
  //Fermer le fichier
  myFile.close();
 
  //Retourner le nombre de fichier
  return count;
}

/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
 
  /*
 
  String tblConfSvg[clef][valeur];  //Tableau de configuration Sauvegarde
String tblConfMdle[clef][valeur];  //Tableau de configuration valeur

*/
 
  //Variables
  char path[SIZE_BUFFER], *key, *val;
  int i, bufferLenght;
 
  //Re crée le chemin
  chemin = chemin + fic;
 
  //Transforme le chemin en tableau de carractères
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre le fichier de configuration
  myFile = SD.open(path, FILE_READ);
 
  //Erreur d'ouverture du fichier
  if(!myFile) {
   
    clearLcd();  //Effacer l'écran
    ecrireLcd("Fichier failed", 01);  //Ecrire
    for(;;); //Boucle infini (peut tre remplacer par un bouton valider)
  }
 
  //Tant que ce n'est pas la fin du fichier
  while(myFile.available()) {
   
    //Récupère la ligne
    i=0;
    while((bufferConf[i++] = myFile.read()) != '\n') {
     
      //Si la ligne dépasse le buffer
      if(i == SIZE_BUFFER) {
     
        //Finir la ligne et stopper la lecture
        while(myFile.read() != '\n') {
          break;
        }
      }
    }
   
    bufferLenght = i;  //Garder en mémoire le nombre de char
    bufferConf[--i] = '\0';  //Finalise la chaine en virant le \n
   
    //Ignore les lignes vides, les commentaires # et //
    if(bufferConf[0] == '\0' || bufferConf[0] == '#' || bufferConf[0] == '//') {
   
      continue;
    }
   
    //Cherche l'emplacement de la clef en ignorant les espaces et tabulations
    i = 0;
    while(bufferConf[i] = ' ' || bufferConf[i] == '\t') {
       
      //Ignore les lignes contenant uniquement des espaces ou des tabulations
      if(++i == bufferLenght) {
         
        break;
      }
       
      key = &bufferConf[i];
      /*
        Ici boucle inini ?
      */
      //Cherche l'emplacement du séparateur
      while(bufferConf[i] != '=') {
       
        //Ignore les espaces et tabulations
        if(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
           
          bufferConf[i] = '\0';
        }
       
        //Ignore les lignes mal formés
        if(++i == bufferLenght) {
          break;
        }
       
      }
     
      /*
      //Gère les lignes mal formés
      if(i == bufferLenght) {
        continue;
      }
       
      bufferConf[i++] = '\0'; //Transforme me séparateur = en \o et continue
       
      //Cherche l'emplacement de la valeur en ignorant espaces et tabulations
      while(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
         
        //Ignore les lignes contenant uniquement des espaces ou des tabulations
        if(++i == bufferLenght) {
          break;
        }
         
        //Gère les lignes mal formés
        if(i == bufferLenght) {
          continue;
        }
         
        val = &bufferConf[i];
         
        //Charger la clef et la valeur dans le tableau à deux dimension
        Serial.println(key);
        Serial.println(val);
      }
      */
      Serial.println(key);
    } 
    /*
   
    //Si c'est le répertoire /sauvegarde/
    if(chemin == "/svgde/") {
    }
   
    //Si c'est le répertoire /modeles/
    if(chemin == "/modeles/") {
    }
    */
   
    //Serial.write(myFile.read());
  }
 
  Serial.println("Fin fichier");
 
  //Fermer le fichier
  myFile.close();
 
  delay(1000);
}


A un endroit, je pose la question de la boucle infini. Un test m'a prouvé que l'on ne s'arrêtais pas sur le '=' et que 1 s'incrémentais sauvagement ! Si je vire le while en le mettant en commentaire, je vais bien jusqu'à la fin de fichier. Donc la condition n'arrive jamais. Je cherche pourquoi.

Pour rappel, mon fichier ne contient qu'une ligne étnant : Modele = modele001.

Merci.
Title: Re: Carte SD - programmation - Choix effectués - config.txt
Post by: Microbulle on Nov 01, 2012, 10:41 am
J'y suis arrivé, j'ai bien ma key et ma val. Quelques erreur dans l'indentation et saisie de code. Bref c'est corrigé.

Par contre, maintenant j'aimerais savoir comment liée une clef à sa valeur dans un tableau. Ainsi si j'appelle la clef, j'obtiendrais sa valeur.

Merci pour votre aide la dessus.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: barbudor on Nov 01, 2012, 11:23 am
Contrairement a d'autres langages comme PHP ou JavaScript, il n'est pas possible en C d'indéxer un tableau par une clé.

Il va falloir le faire "à la main"

Le plus simple est d'utiliser un tableau de structure :
Code: [Select]

#define NBKEY  20
#define KEYLEN 20
struct {
  char key[KEYLEN];
  int   val; // ou autre type
} TabKeyVal[NBKEY];


Ce qui te donne un tableau a 20 élements dans lequel tu peux mémoriser tes couples.
Par contre il faudra forcément chercher chaque fois que tu veux une valeur.
Par exemple

Code: [Select]
int getVal( const char *key, int *pVal )
{
  int i;
  for ( i = 0 ; i < NBKEY ; i++ )
    if ( 0  == strcmp( key, TabKeyVal[i].key )  )
    {
      *pVal = TabKeyVal[i].val;
      return 1;
    }
    return 0;
}


En C++ avancé il existe des moyens de faire des collections mais cela n'est pas disponible a ma connaissance sur ATmega.
Au mieux, tu peux encapsuler la structure et ses méthodes d'accès dans une classe.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 01, 2012, 12:10 pm
Ok pour cette méthode.

Je viens de trouvé par hasard ceci : http://www.arduino.cc/playground/Code/HashMap
Ça correspond à ce que je voulais faire mais hélas j'ai pas l'impression que ça fonctionne.
Code: [Select]

#include <HashMap.h>

#define SIZE_BUFFER 32  //Nombre de case du buffer

const int nbFic = 10;  //Nombre de fichier potentiel à scruter
const byte SIZE_HASH = 2;  //Nombre de hshtable

char bufferConf[SIZE_BUFFER];  //Le buffer des fichiers de conf
HashType<char*, String> hashRawArray[SIZE_HASH];
HashMap<char*, String> hashMapConfSvg = HashMap<char*, String>(hashRawArray, SIZE_HASH);

File myFile;  //Fichier
String tblFicMdle[nbFic];  //Le tableau des noms des fichiers modèles
String tblFicSvg[nbFic];  //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle;  //Nombre de fichier

/* SETUP */
void setup() {
//Initialiser la carte SD
 if(initSD()) {
   
   //Lister les fichier de sauvegardes
   listeFichier("/svgde/");
   
   //Lister les fichiers de configuration modèle
   nbFichierMdle = listeFichier("/modeles/");
   
   //Ouvrir le fichier de sauvegarde
   ouvrirFichier("/svgde/", tblFicSvg[0]);
 }
 else {
   
   //Charger les valeurs par défaut de la radio
 }
}

/* LOOP */
void loop() {
}

/* FONCTION initLCD */
void initLcd() {
 
 //Initialisation de l'écran par I2C
 Wire.begin();  //Amorce la connection sur SDA et SCL
 Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
 Wire.write((byte)0x00);  //Assigne un null
 Wire.write((byte)0x0C);  //Effacer l'écran
 Wire.write((byte)0x13);  //Allume le rétro-éclairage
 Wire.write((byte)0x04);  //Ne pas afficher le curseur
 Wire.endTransmission();  //Ferme la connexion sur SDA et SCL
}

/* FONCTION ecrireLcd */
void ecrireLcd(String texte, int positionEcran) {
 
 //Initialisation de l'écran par I2C
 Wire.begin();  //Amorce la connection sur SDA et SCL
 Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
 Wire.write((byte)0x00);  //Assigne un null
 Wire.write((byte)0x02);  //Placer le curseur
 Wire.write(positionEcran);  //Sur l'écran
 Wire.print(texte);  //Ecrire un texte
 Wire.endTransmission();  //Ferme la connexion sur SDA et SCL
}

/* FONCTION ecrireLcdChar */
void ecrireLcdChar(char texte[32], int positionEcran) {
 
 //Initialisation de l'écran par I2C
 Wire.begin();  //Amorce la connection sur SDA et SCL
 Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
 Wire.write((byte)0x00);  //Assigne un null
 Wire.write((byte)0x02);  //Placer le curseur
 Wire.write(positionEcran);  //Sur l'écran
 Wire.write(texte);  //Ecrire un texte
 Wire.endTransmission();  //Ferme la connexion sur SDA et SCL
}

/* FONCTION clearLcd() */
void clearLcd() {
 
 //Initialisation de l'écran par I2C
 Wire.begin();  //Amorce la connection sur SDA et SCL
 Wire.beginTransmission(adresseLcd); //Appelle l'écran LCD
 Wire.write((byte)0x00);  //Assigne un null
 Wire.write((byte)0x0C);  //Effacer l'écran
 Wire.endTransmission();  //Ferme la connexion sur SDA et SCL
}

/* FONCTION initSD() */
boolean initSD() {
 
 clearLcd();  //Effacer l'écran
 ecrireLcd("Init SD Card", 01);  //Ecrire
 
 //Si la carte n'est pas présente ou qu'elle est en défaut
 if(!SD.begin(4)) {
   
   ecrireLcd("Non presente", 21);  //Ecrire
   return false;
 }
 
 ecrireLcd("Sd card... Ok", 21);  //Ecrire
 
 delay(1000);
 return true;
}

/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
 int count = 0;
 char path[SIZE_BUFFER];
 
 //Conversion du chemin
 chemin.toCharArray(path, SIZE_BUFFER);
 
 //Ouvre ce qui est défini par le chemin
 myFile = SD.open(path);
 
 //Tant que c'est vrai
 while(true) {
   
   //Prend le nom du fichier
   File entry = myFile.openNextFile();
   
   //Si c'est la fin
   if(!entry) {
     
     break;  //Sortir de la boucle
   }
   
   //Si le nombre de fichier est plus important que le nombre de place en tableau
   if(count == nbFic) {
     
     break;  //Sortir de la boucle
   }
   
   //Si c'est le répertoire /modeles/
   if(chemin == "/modeles/") {
   
       //Rentre le nom de fichier dans le tableau des noms de modèles
       tblFicMdle[count] = entry.name();
   }
   
   //Si c'est le répertoire /sauvegarde/
   if(chemin == "/svgde/") {
       
     //Rentre le nom de fichier dans le tableau des noms de sauvegarde
       tblFicSvg[count] = entry.name();
   }
   
   count++; //Compter le nombre de fichier
 }
 
 //Fermer le fichier
 myFile.close();
 
 //Retourner le nombre de fichier
 return count;
}

/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
 
 //Variables
 char path[SIZE_BUFFER], *key, *val;
 int i, bufferLenght, lineCounter = 0;
 
 clearLcd();  //Effacer l'écran
 ecrireLcd("Fichier en lecture", 01);  //Ecrire
 
 //Re crée le chemin
 chemin = chemin + fic;
 
 //Transforme le chemin en tableau de carractères
 chemin.toCharArray(path, SIZE_BUFFER);
 
 //Ouvre le fichier de configuration
 myFile = SD.open(path, FILE_READ);

 //Erreur d'ouverture du fichier
 if(!myFile) {
   
   clearLcd();  //Effacer l'écran
   ecrireLcd("Pb fichier", 01);  //Ecrire
   for(;;); //Boucle infini (peut tre remplacer par un bouton valider)
 }
 
 //Tant que ce n'est pas la fin du fichier
 while(myFile.available()) {
   
   //Récupère la ligne
   i=0;
   while((bufferConf[i++] = myFile.read()) != '\n') {
     
     //Si la ligne dépasse le buffer
     if(i == SIZE_BUFFER) {
     
       //Finir la ligne et stopper la lecture
       while(myFile.read() != '\n') {
         break;
       }
     }
   }
   
   bufferLenght = i;  //Garder en mémoire le nombre de char
   bufferConf[--i] = '\0';  //Finalise la chaine en virant le \n
   ++lineCounter; //Incrémenter le nombre de ligne
   
   //Ignore les lignes vides, les commentaires # et //
   if(bufferConf[0] == '\0' || bufferConf[0] == '#' || bufferConf[0] == '//') {
   
     continue;
   }
   
   //Cherche l'emplacement de la clef en ignorant les espaces et tabulations
   i = 0;
   while(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
       
     //Ignore les lignes contenant uniquement des espaces ou des tabulations
     if(++i == bufferLenght) {
         
       break;
     }
   }
   //Gère les lignes mal formés
   if(i == bufferLenght) {
     continue;
   }
   key = &bufferConf[i];
   
   //Cherche l'emplacement du séparateur
   while(bufferConf[i] != '=') {
       
     //Ignore les espaces et tabulations
     if(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
           
       bufferConf[i] = '\0';
     }
       
     //Ignore les lignes mal formés
     if(++i == bufferLenght) {
       break;
     }
   }
   
   //Gère les lignes mal formés
   if(i == bufferLenght) {
     continue;
   }
       
   bufferConf[i++] = '\0'; //Transforme me séparateur = en \o et continue
   
   //Cherche l'emplacement de la valeur en ignorant espaces et tabulations
   while(bufferConf[i] == ' ' || bufferConf[i] == '\t') {
         
     //Ignore les lignes contenant uniquement des espaces ou des tabulations
     if(++i == bufferLenght) {
       break;
     }
   }
   
   //Gère les lignes mal formés
   if(i == bufferLenght) {
     continue;
   }
   
   val = &bufferConf[i];

/*
 
String tblConfSvg[clef][valeur];  //Tableau de configuration Sauvegarde
String tblConfMdle[clef][valeur];  //Tableau de configuration valeur

*/    
   //Si c'est le répertoire /sauvegarde/
   if(chemin == "/svgde/") {
      hashMapConfSvg[lineCounter](key, val);
   }
   
   //Si c'est le répertoire /modeles/
   if(chemin == "/modeles/") {
   }
   
   Serial.println(lineCounter);
   Serial.println(key);
   Serial.println(val);
 }
 
 
 Serial.println(hashMapConfSvg.getIndexOf("Modele"), DEC);
 Serial.println(hashMapConfSvg.getValueOf("Modele"));
 
 
 //Fermer le fichier
 myFile.close();
 
 ecrireLcd("Fichier Ok", 21);  //Ecrire
 
 delay(1000);
}


Ceci alourdis pas mal le code le coup du hashtable. Mais tu a peut-être raison, ça m'a l'air aussi simple avec la recherche dans le tableau. Laquelle des deux solutions est la plus pratique / meilleure et surtout non consommatrice de ressources ?

Edit, je laisse tomber les hashtable. Beaucoup de souci d'upload à cause de cette librairie !

Retour à ta solution  :smiley-mr-green:
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 01, 2012, 12:48 pm
Et si je chargais dans un premier tableau la clef, et dans un autre la valeur.

J'appelle la clef, qui me retourne sa position, avec la position je retrouve la valeur ;)

Le tour serais joués sans se prendre la tête avec un tableau de structure  XD
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: barbudor on Nov 01, 2012, 12:57 pm
Un tableau de structure est juste plus propre du point de vue codage.
Sinon, avec 2 tableaux ca revient au même.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Geeks on Nov 01, 2012, 01:49 pm
La, pour le moment mes tableaux sont vide malgres le fait que j'ai bien key et val qui ont des données.

Ok pour le fait que ça soit plus propre. À ce moment la, j'ai peut être intérêt à basculer une partie de mes fonctions en classe.

Des mon retour, je regarde pourquoi mes tableaux de String restent vide et je passe aux classes.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 01, 2012, 03:07 pm
De retour à la maison, je me rend compte que key et val sont des char*.

Donc il me faut les convertir vers char ou String. Je cherche comment !
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: SesechXP on Nov 01, 2012, 08:51 pm
Tout simplement avec le constructeur de la classe String :
Code: [Select]

char* charArray = "Hello world!";
String str = String(charArray);


++
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: barbudor on Nov 01, 2012, 09:23 pm
Code: [Select]
String str = String(charArray);

Voici un très bon exemple de mauvaise utilisation de String

A droite du signe = tu appelles le constructeur de la classe String. Ce qui crée un objet String temporaire, alloue de la mémoire pour stocker la chaine de caractère, copie la chaine de caractère dans l'espace mémoire ainsi alloué.
A gauche du signe égal tu a la définition d'une variable str de type String. Ce qui crée l'objet String appelé str.
Le signe égal signifie qu'il y a copié du membre de droite vers le membre de gauche.
L'objet temporaire est copié dans l'objet str.
La classe String va donc allouer de la mémoire pour stocker la chaine de caractère qui est contenue dans l'objet temporaire, puis copier les caractères.
Une fois la copie effectue, l'objet temporaire n'est plus utile donc il est détruit.

Bref :
- Perte d'efficacité car on copie 2 fois l'ensemble des caractères = perte de temps
- Fragmentation inutile de la mémoire car on alloue pour rien une mémoire temporaire qui est ensuite libérée mais crée un trou dans la zone d'allocation dynamique de mémoire.

Un meilleur code est tout simplement :
Code: [Select]
String str = "chaine initiale";
Qui ne fait que l'allocation de str et une seule copie.


Voilà pourquoi je considère qu'utiliser String c'est MAL  ]:)

Quand on est débutant et qu'on ne comprend pas trop les mécanismes qui sont derrière, les programmes plantent sans qu'on sache pourquoi : que croyez vous qu'il se passe si String essaye de redimensionner l'espace de stockage allouée à une String et qu'il n'y a plus de mémoire dispo : rien et le programme part dans les choux.
Sur un PC avec la mémoire virtuelle, peut de chance que cela arrive, mais au pire vous avez une jolie boite de dialogue : "Cette application s'est inopinément arretée : Pas assez de mémoire"

Malheureusement c'est quand on est débutant qu'on se laisse tenté par la facilité d'utilisation de String...

Par ailleurs sur PC, les classes String équivalents sont bien codées. On utilise ce genre de classe avec du try/catch pour pouvoir intercepter les exceptions. Ce qui n'est pas possible avec la classe String Arduino car les codeurs (ah ces artistes) ont allègrement oublié de lever des exceptions en cas d'erreur, se contentant de ne rien faire.

Sur un système à faible ressource mémoire tel qu'un ATmega, il vaut beaucoup mieux apprendre à gérer sa mémoire proprement en sachant ce que l'on fait plutôt que de laisser du mauvais code le faire dans son dos. A terme vous aurez des programmes plus fiables et plus économes en mémoire.

C'était la minute du Professeur Rollin XD

Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 01, 2012, 09:34 pm
Très bonnes indications !
Justement je vais priofiter de ton cours pour rebondir. La mauvaise habitude que j'ai eu avec les String m'est resté  :smiley-mr-green: Honte à moi !

Donc vers quelle type de variable s'orienté au niveau du final ?

Je demande car e viens de changer un peu la donne. En fait je vais me permettre de simplifier un peu tout ça.
Mon vichier va évoluer comme suit:
Quote

//Modèle
Robot Go

//Type
Robot

//Mix_V1V2 / Mix_V3V4
true
false


Par contre, au retour j'obtiens:
Quote

Robot Go
Robot
fals
false


Il manque un true et j'obtiens un false incomplet qui prends la place du true  :smiley-sad-blue:

Au niveau code quelques changements pour essayer. Tant que j'en suis à tester, autant que je teste toutes les solutions avant de me jetter dans une version finale.
Code: [Select]

#define SIZE_CONF 10  //Nombre de configuration par fichier

File myFile;  //Fichier
String tblFicMdle[SIZE_MODELE];  //Le tableau des noms des fichiers modèles
String tblFicSvg[SIZE_MODELE];  //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle;  //Nombre de fichier

/* SETUP */
void setup() {
//Initialiser la carte SD
  if(initSD()) {
   
    //Lister les fichier de sauvegardes
    listeFichier("/svgde/");
   
    //Lister les fichiers de configuration modèle
    nbFichierMdle = listeFichier("/modeles/");
   
    //Ouvrir le fichier de sauvegarde
    //ouvrirFichier("/svgde/", tblFicSvg[0]);
   
    ouvrirFichier("/modeles/", tblFicMdle[2]);
  }
}
else {
     
    //Charger les valeurs par défaut de la radio
}

/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
  int count = 0;
  char path[SIZE_BUFFER];
 
  //Conversion du chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre ce qui est défini par le chemin
  myFile = SD.open(path);
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Si le nombre de fichier est plus important que le nombre de place en tableau
    if(count == SIZE_MODELE) {
     
      break;  //Sortir de la boucle
    }
   
    //Si c'est le répertoire /modeles/
    if(chemin == "/modeles/") {
   
        //Rentre le nom de fichier dans le tableau des noms de modèles
        tblFicMdle[count] = entry.name();
    }
   
    //Si c'est le répertoire /sauvegarde/
    if(chemin == "/svgde/") {
       
      //Rentre le nom de fichier dans le tableau des noms de sauvegarde
      tblFicSvg[count] = entry.name();
    }
   
    count++; //Compter le nombre de fichier
  }
 
  //Fermer le fichier
  myFile.close();
 
  //Retourner le nombre de fichier
  return count;
}

/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
 
  //Variables
  char path[SIZE_BUFFER], bufferConf[SIZE_BUFFER];
  int i, bufferLenght, lineCounter = 0;
  String toto[SIZE_CONF];
 
  clearLcd();  //Efface l'écran
  ecrireLcd("Fichier en lecture", 01);  //Ecrire
 
  //Crée le chemin
  chemin = chemin + fic;
 
  //Transforme le chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre le fichier
  myFile = SD.open(path, FILE_READ);
 
  //Si le fichier est présent
  if(myFile) {
   
    //Tant que ce n'est pas la fin du fichier
    while(myFile.available()) {
     
     
      //Récupère la ligne
      i = 0;
      while((bufferConf[i++] = myFile.read()) != '\n') {
       
        //Si la ligne dépasse le buffer
        if(i == SIZE_BUFFER) {
         
          //Finir la ligne et stopper la lecture
          while(myFile.read() != '\n') {
           
            break;
          }
        }
      }
     
     
      bufferLenght = i;  //Garder en mémoire le nombre de lettre
      bufferConf[--i] = '\0';  //Finir la ligne en retirant le saut de ligne
     
      //Serial.println(bufferConf[0]);
      //Ne pas enregistrer les lignes vides ou les commentaires
      if(bufferConf[0] == '\0' || bufferConf[0] == '/' || bufferConf[0] == '#') {
        continue;
      }
     
      toto[lineCounter] = bufferConf;
      ++lineCounter; //Compter le nombre de lignes
    }
   
   
    Serial.println(path);
    Serial.println(toto[0]);
    Serial.println(toto[1]);
    Serial.println(toto[2]);
    Serial.println(toto[3]);
    Serial.println(toto[4]);
    Serial.println(toto[5]);
    Serial.println(lineCounter);
   
   
  }
  else {
   
    clearLcd();  //Efface l'écran
    ecrireLcd("Fichier introuvable", 01);  //Ecrire
    for(;;);
  }
 
  //Fermer le fichier
  myFile.close();
 
  ecrireLcd("Fichier Ok", 01);  //Ecrire
 
  delay(1000);
}


Comme on le voie, si j'ai un commentaire, on saute, si j'ai un saut de ligne on saute.

Ne pas tenir compte de la sortie car je demande plus haut vers quoi je devrais évolué pour ne pas forcément utilisé un String  :smiley-mr-green:

Merci.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: barbudor on Nov 01, 2012, 09:44 pm
De mon point de vue, il vaut mieux utiliser des tableaux de char, de dimensions connues et maitrisées.
Utiliser les bonnes fonctions telles que strncpy() au lieu de strcpy() etc ... afin d'éviter les débordements de tableaux.

A la fin tu verra que finalement, les tableaux de char et la libC (stdio.h (http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html) et string.h (http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html)) offrent beaucoup de possibilités et un meilleur contrôle.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 01, 2012, 09:50 pm
Bon j'ai un autre problème :(

A prori je ne sort jamais de la boucle while(myFile.available()) {}

Même quand elle ne contient rien !!
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 01, 2012, 10:06 pm
Bon j'ai trouvé !

Effectivement pas bon les Strings  :smiley-mr-green: mais pas bon du tout  :smiley-red:

Bon, alors j'ai modifier mon code ainsi (et je ne vous met pas tout car c'est que la fin qui change !
Code: [Select]

/* FONCTION initSD() */
boolean initSD() {
 
  clearLcd();  //Effacer l'écran
  ecrireLcd("Init SD Card", 01);  //Ecrire
 
  //Si la carte n'est pas présente ou qu'elle est en défaut
  if(!SD.begin(4)) {
   
    ecrireLcd("Non presente", 21);  //Ecrire
    return false;
  }
 
  ecrireLcd("Sd card... Ok", 21);  //Ecrire
 
  delay(1000);
  return true;
}

/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
  int count = 0;
  char path[SIZE_BUFFER];
 
  //Conversion du chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre ce qui est défini par le chemin
  myFile = SD.open(path);
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Si le nombre de fichier est plus important que le nombre de place en tableau
    if(count == SIZE_MODELE) {
     
      break;  //Sortir de la boucle
    }
   
    //Si c'est le répertoire /modeles/
    if(chemin == "/modeles/") {
   
        //Rentre le nom de fichier dans le tableau des noms de modèles
        tblFicMdle[count] = entry.name();
    }
   
    //Si c'est le répertoire /sauvegarde/
    if(chemin == "/svgde/") {
       
      //Rentre le nom de fichier dans le tableau des noms de sauvegarde
      tblFicSvg[count] = entry.name();
    }
   
    count++; //Compter le nombre de fichier
  }
 
  //Fermer le fichier
  myFile.close();
 
  //Retourner le nombre de fichier
  return count;
}

/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String chemin, String fic) {
 
  //Variables
  char path[SIZE_BUFFER], bufferConf[SIZE_BUFFER];
  int i, bufferLenght, lineCounter = 0;
 
  clearLcd();  //Efface l'écran
  ecrireLcd("Fichier en lecture", 01);  //Ecrire
 
  //Crée le chemin
  chemin = chemin + fic;
 
  //Transforme le chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre le fichier
  myFile = SD.open(path, FILE_READ);
 
  //Si le fichier est présent
  if(myFile) {
    //Tant que ce n'est pas la fin du fichier
    while(myFile.available()) {
     
      //Récupère la ligne
      i = 0;
      while((bufferConf[i++] = myFile.read()) != '\n') {
       
        //Si la ligne dépasse le buffer
        if(i == SIZE_BUFFER) {
          break;
        }
      }
     
      bufferLenght = i;  //Garder en mémoire le nombre de lettre
      bufferConf[--i] = '\0';  //Finir la ligne en retirant le saut de ligne
      lineCounter++; //Compter le nombre de lignes
     
      //Ne pas enregistrer les lignes vides ou les commentaires
      if(bufferConf[0] == '\0' || bufferConf[0] == '/' || bufferConf[0] == '#') {
        continue;
      }
     
      Serial.println(bufferConf);
     
    }
   
    //Fermer le fichier
    myFile.close(); 
  }
 
  return;
}


la ou je sort mon Serial.println(bufferConf); c'est là que je dois entrée en tableau. Ce que je cherche c'est à avoir
tbl[0] -> Robot Go
tbl[1] -> Robot
tbl[2] -> true
tbl[3] -> false

Il y aura des tests sur true et false au final. Donc c'est un point à étudier afin de ne pas le perdre de vue.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 02, 2012, 03:01 pm
En fait ça fonctionne très bien. Beaucoup d'erreur ont été commise au niveau tableau.  :smiley-sad-blue:

La confusion entre un tableau de char ou x valait le nombre de possibilités et un tableau à deux dimensions qui lui a un nombre de possibilité de case contenant un nombre de caractères données.

L'incompréhension de strncpy qui après coup est effectivement une fonction rapide et pratique.

Je met ici la solution finale qui fonctionne.
Code: [Select]

#define SIZE_BUFFER 32  //Nombre de case du buffer
#define SIZE_CMDE 10  //Nombre de commandes

File myFile;  //Fichier
String tblFicMdle[SIZE_CMDE];  //Le tableau des noms des fichiers modèles
String tblFicSvg[SIZE_CMDE];  //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle;  //Nombre de fichier

char tblConfSvg[SIZE_CMDE][SIZE_BUFFER];  //Le tableau des configuration du fichier de sauvegarde
char tblConfMdle[SIZE_CMDE][SIZE_BUFFER]; //Le tableau des configurations du fichier de modèle

/* SETUP */
void setup() {
//Initialiser la carte SD
  if(initSD()) {
   
    //Lister les fichier de sauvegardes
    listeFichier("/svgde/");
   
    //Lister les fichiers de configuration modèle
    nbFichierMdle = listeFichier("/modeles/");
   
    //Ouvrir le fichier de sauvegarde
    //ouvrirFichier("/svgde/", tblFicSvg[0]);
   
    ouvrirFichier("/modeles/", tblFicMdle[2]);
  }
  else {
     
    //Charger les valeurs par défaut de la radio
  }
 
  Serial.println(tblConfMdle[0]);
  Serial.println(tblConfMdle[1]);
  Serial.println(tblConfMdle[2]);
  Serial.println(tblConfMdle[3]);
  Serial.println(tblConfMdle[4]);
}

/* LOOP */
void loop() {
}


/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
  int count = 0;
  char path[SIZE_BUFFER];
 
  //Conversion du chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre ce qui est défini par le chemin
  myFile = SD.open(path);
 
  //Tant que c'est vrai
  while(true) {
   
    //Prend le nom du fichier
    File entry = myFile.openNextFile();
   
    //Si c'est la fin
    if(!entry) {
     
      break;  //Sortir de la boucle
    }
   
    //Si le nombre de fichier est plus important que le nombre de place en tableau
    if(count == SIZE_CMDE) {
     
      break;  //Sortir de la boucle
    }
   
    //Si c'est le répertoire /modeles/
    if(chemin == "/modeles/") {
   
        //Rentre le nom de fichier dans le tableau des noms de modèles
        tblFicMdle[count] = entry.name();
    }
   
    //Si c'est le répertoire /sauvegarde/
    if(chemin == "/svgde/") {
       
      //Rentre le nom de fichier dans le tableau des noms de sauvegarde
      tblFicSvg[count] = entry.name();
    }
   
    count++; //Compter le nombre de fichier
  }
 
  //Fermer le fichier
  myFile.close();
 
  //Retourner le nombre de fichier
  return count;
}

/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String rep, String fic) {
 
  //Variables
  char path[SIZE_BUFFER], bufferConf[SIZE_BUFFER+1];
  int i, bufferLenght, lineCounter = 0;
  String chemin;
 
  clearLcd();  //Efface l'écran
  ecrireLcd("Fichier en lecture", 01);  //Ecrire
 
  //Crée le chemin
  chemin = rep + fic;
 
  //Transforme le chemin
  chemin.toCharArray(path, SIZE_BUFFER);
 
  //Ouvre le fichier
  myFile = SD.open(path, FILE_READ);
 
  //Si le fichier est présent
  if(myFile) {
    //Tant que ce n'est pas la fin du fichier
    while(myFile.available()) {
     
      //Récupère la ligne
      i = 0;
      while((bufferConf[i++] = myFile.read()) != '\n') {
       
        //Si la ligne dépasse le buffer
        if(i == SIZE_BUFFER) {
          break;
        }
      }
     
      bufferLenght = i;  //Garder en mémoire le nombre de lettre
      bufferConf[--i] = '\0';  //Finir la ligne en retirant le saut de ligne
     
      //Ne pas enregistrer les lignes vides ou les commentaires
      if(bufferConf[0] == '\0' || bufferConf[0] == '/' || bufferConf[0] == '#') {
        continue;
      }
     
     
     
      //Charger le tableau des configurations modèle
      if(rep == "/modeles/") {
       
        /*
          Copie le tableau contenant une commande, dans le tableau
          à deux dimensions qui est extérieur
        */
        strncpy(tblConfMdle[lineCounter], bufferConf, SIZE_BUFFER);
        bufferConf[SIZE_BUFFER] = '\0'; //Fini par un '\0'
      }
     
      //Charger le tableau des configurations sauvegardes
      if(rep == "/svgde/") {
       
        /*
          Copie le tableau contenant une commande, dans le tableau
          à deux dimensions qui est extérieur
        */
        strncpy(tblConfSvg[lineCounter], bufferConf, SIZE_BUFFER);
        bufferConf[SIZE_BUFFER] = '\0'; //Fini par un '\0'
      }
     
      lineCounter++; //Compter le nombre de lignes
    }
   
    //Fermer le fichier
    myFile.close(); 
  }
 
  return;
}


La prochaine étape va être de pouvoir charger les variables de tests. Avant je faisait des tests sur des strings. N'aurais-je pas intérêt à faire des tests sur des char fonction1, fonction2, fonction3... chargée par fonction1 = tbl1[0]; ... ?

Dans mon tableau j'ai entre autre du boolean (true ou false) qui doivent au final être tester. Je comprends bien qu'il me faudra faire de nouvelles conversions.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: barbudor on Nov 02, 2012, 04:40 pm
Pour comparer des chaines de caractères : strcmp() ou strcasecmp()
Le premier prend en compte la différence minuscules/MAJUSCULES
Le 2nd ne prend pas en compte la différence
Renvoie 0 si égalité ou -1/+1 si différent (dépend si l'un est avant l'autre dans l'ordre alphabétique)

Si tu veux comparer qu'une partie de la chaîne il y a aussi strncmp() et strncasecmp() qui ne compare que les n premiers caractères
Tout est là : http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html

Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Microbulle on Nov 02, 2012, 05:42 pm
Et bien, c'est super cette page  8) J'ai encore appris des choses  :smiley-mr-green:

Alors, j'ai fait évoluer mon code et je doit en profiter pour vous citer dans mes soures  ;)
Je vous simplifie le code de façon à montrer que ce qui n'a de l'intérêt avec le sujet.
Code: [Select]

/*
  Auteur : Alexandre LABURE
 Aide DVP : Ragmaxone, sevyc64, Winjerome, Bousk
 Aide Arduino.cc : barbudor, SesechXP
 Création : le 30 octobre 2012
 Dernière modification : le 02 novembre 2012
 Version 1.0
*/

/* DEFINITIONS */
#define SIZE_BUFFER 32  //Nombre de case du buffer
#define SIZE_CMDE 10  //Nombre de commandes

File myFile;  //Fichier
String tblFicMdle[SIZE_CMDE];  //Le tableau des noms des fichiers modèles
String tblFicSvg[SIZE_CMDE];  //Le tableau des noms des fichiers de sauvegardes
int nbFichierMdle;  //Nombre de fichier

char tblConfSvg[SIZE_CMDE][SIZE_BUFFER];  //Le tableau des configuration du fichier de sauvegarde
char tblConfMdle[SIZE_CMDE][SIZE_BUFFER]; //Le tableau des configurations du fichier de modèle

//Configuration pour un modèle
String confNom, confType;
boolean confMix_V1V2, confMix_V3V4;

/* SETUP */
void setup() {
//Initialiser l'écran LCD
 initLcd();  //Initialiser l'écran LCD
 ecrireLcd("Telecommande 433Mhz", 01);  //Ecrire
 ecrireLcd("Version 1.0", 24);  //Ecrire
 ecrireLcd("Bonjour", 66);  //Ecrire
 
 delay(2000);
 
 
 //Initialiser la carte SD
 if(initSD()) {
   
   //Lister les fichier de sauvegardes
   listeFichier("/svgde/");
   
   //Lister les fichiers de configuration modèle
   nbFichierMdle = listeFichier("/modeles/");
   
   //Ouvrir le fichier de sauvegarde
   ouvrirFichier("/svgde/", tblFicSvg[0]);
   
   //ouvrirFichier("/modeles/", "model001.txt");
   ouvrirFichier("/modeles/", tblConfSvg[0]);
   
   //Charger les valeurs sauvegardés
   confNom = tblConfMdle[0];
   confType = tblConfMdle[1];
   
   //Compare la configuration
   if(strcmp(tblConfMdle[2], "true") == 0) {
     //Si c'est vrai
     confMix_V1V2 = true;
   }
   else {
     //Si c'est faux
     confMix_V1V2 = false;
   }
   
   //Compare la configuration
   if(strcmp(tblConfMdle[3], "true") == 0) {
     //Si c'est vraie
     confMix_V3V4 = true;
   }
   else {
     //Si c'est faux
     confMix_V3V4 = false;
   }
 }
 else {
   
   //Charger les valeurs par défaut de la radio
   confNom = "Aucun nom";
   confType = "Aucun";
   confMix_V1V2 = false;
   confMix_V3V4 = false;
 }
}

/* LOOP */
void loop() {
}

/* FONCTION initSD() */
boolean initSD() {
 
 clearLcd();  //Effacer l'écran
 ecrireLcd("Init SD Card", 01);  //Ecrire
 
 //Si la carte n'est pas présente ou qu'elle est en défaut
 if(!SD.begin(4)) {
   
   ecrireLcd("Non presente", 21);  //Ecrire
   return false;
 }
 
 ecrireLcd("Sd card... Ok", 21);  //Ecrire
 
 delay(1000);
 return true;
}

/* FONCTION listerFichier() */
int listeFichier(String chemin) {
 
 int count = 0;
 char path[SIZE_BUFFER];
 
 //Conversion du chemin
 chemin.toCharArray(path, SIZE_BUFFER);
 
 //Ouvre ce qui est défini par le chemin
 myFile = SD.open(path);
 
 //Tant que c'est vrai
 while(true) {
   
   //Prend le nom du fichier
   File entry = myFile.openNextFile();
   
   //Si c'est la fin
   if(!entry) {
     
     break;  //Sortir de la boucle
   }
   
   //Si le nombre de fichier est plus important que le nombre de place en tableau
   if(count == SIZE_CMDE) {
     
     break;  //Sortir de la boucle
   }
   
   //Si c'est le répertoire /modeles/
   if(chemin == "/modeles/") {
   
       //Rentre le nom de fichier dans le tableau des noms de modèles
       tblFicMdle[count] = entry.name();
   }
   
   //Si c'est le répertoire /sauvegarde/
   if(chemin == "/svgde/") {
       
     //Rentre le nom de fichier dans le tableau des noms de sauvegarde
     tblFicSvg[count] = entry.name();
   }
   
   count++; //Compter le nombre de fichier
 }
 
 //Fermer le fichier
 myFile.close();
 
 //Retourner le nombre de fichier
 return count;
}

/* FONCTION qui ouvre un fichier */
void ouvrirFichier(String rep, String fic) {
 
 //Variables
 char path[SIZE_BUFFER], bufferConf[SIZE_BUFFER+1];
 int i, bufferLenght, lineCounter = 0;
 String chemin;
 
 clearLcd();  //Efface l'écran
 ecrireLcd("Fichier en lecture", 01);  //Ecrire
 
 //Crée le chemin
 chemin = rep + fic;
 
 //Transforme le chemin
 chemin.toCharArray(path, SIZE_BUFFER);
 
 //Ouvre le fichier
 myFile = SD.open(path, FILE_READ);
 
 //Si le fichier est présent
 if(myFile) {
   //Tant que ce n'est pas la fin du fichier
   while(myFile.available()) {
     
     //Récupère la ligne
     i = 0;
     while((bufferConf[i++] = myFile.read()) != '\n') {
       
       //Si la ligne dépasse le buffer
       if(i == SIZE_BUFFER) {
         break;
       }
     }
     
     bufferLenght = i;  //Garder en mémoire le nombre de lettre
     bufferConf[--i] = '\0';  //Finir la ligne en retirant le saut de ligne
     
     //Ne pas enregistrer les lignes vides ou les commentaires
     if(bufferConf[0] == '\0' || bufferConf[0] == '/' || bufferConf[0] == '#') {
       continue;
     }
     
     //Charger le tableau des configurations modèle
     if(rep == "/modeles/") {
       
       /*
         Copie le tableau contenant une commande, dans le tableau
         à deux dimensions qui est extérieur
       */
       strncpy(tblConfMdle[lineCounter], bufferConf, SIZE_BUFFER);
       bufferConf[SIZE_BUFFER] = '\0'; //Fini par un '\0'
     }
     
     //Charger le tableau des configurations sauvegardes
     if(rep == "/svgde/") {
       
       /*
         Copie le tableau contenant une commande, dans le tableau
         à deux dimensions qui est extérieur
       */
       strncpy(tblConfSvg[lineCounter], bufferConf, SIZE_BUFFER);
       bufferConf[SIZE_BUFFER] = '\0'; //Fini par un '\0'
     }
     
     lineCounter++; //Compter le nombre de lignes
   }
 }
 else {
   clearLcd();  //Efface l'écran
   ecrireLcd("Fichier introuvable", 01);  //Ecrire
   for(;;);
 }
 
 //Fermer le fichier
 myFile.close();
 
 return;
}


Je vous ai épargné le loop() qui contient des choses qui n'ont plus rien à voir.

Je me suis fait un petit exemple avec strcmp() et qui fonctionne parfaitement. On test si c'est sur "true" et si oui, on en profite pour écrire true dans un boolean, sinon on écrit un false. C'est peut-être pas des plus optimisé mais ça fonctionne très bien.

Je profite d'aileur pour vous dire que je vais laisser tomber la carte SD quelques jours car j'aimerais nettoyé un peu mon code. Remplacer des strings inutiles par des char et revoir un peu l'architecture interne avec des classes. Par exemple créer une classe pour la partie LCD. Ainsi, je n'aurais plus à refaire initLcd(); planqué dans ma fonction. Elle sera directement dans la classe. Je pense qu'à terme ça peut faire gagner quelques octets et c'est pas non négligeable. Qu'en pensez-vous ?
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: barbudor on Nov 02, 2012, 06:06 pm
Planquer le code ne le fait pas disparaitre. DOnc tu ne gagnera pas d'octets.

Mais structurer ton code en modules, avec ou sans classes, te fera gagner en lisibilité et maintenabilité.
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Geeks on Nov 02, 2012, 06:53 pm
Ok, au temps pour moi ! Quand je parlais de réduire, le voulais dire augmenter la lisibilité.

Ceci dit, j'aimerais que les classes soit externe à mon programme principal. Comment ça se passe ?

In crée les classes puis un coup de require() suffit ? Ou bien, faut-t-il gardé dans le seul fichier à charger ?
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: barbudor on Nov 02, 2012, 07:35 pm
require() c'est du Java(Script)

En C++ tu crée :
- Un fichier H de déclaration

Code: [Select]
#ifndef _MACLASSE_H_
#define _MACLASSE_H_

Class MaClasse
{
  public:
    MaClasse(); // Constructeur par défaut
    MaClasse( int p1, int p2 ); // Constructeur avec paramètres
    ~MaClasse(); // Destructeur

    int Toto( int p1 ); // Fonction membre publique Toto

  protected:
    void titi( int p2 ) ; fonction membre protégée

    int x;  // variable membre
    int y;
};

#endif


- Un fichier CPP d'implémentation

Code: [Select]


#include "MaClasse.h"

MaClasse::MaClasse()
{
  // code du constructeur par défaut
  x = 0;
  y = 0;
}

MaClasse::MaClasse( int p1, int p2 )
{
  // code du constructeur par défaut
  x = p1;
  y = p2;
}

MaClasse::~MaClasse()
{
  // code du destructeur
}

int MaClasse::Toto( int p1 )
{
  return (x + p1) / (y + 1);
}

void MaClasse::titi( int p1 )
{
  x++;
  y--;
}


Pour créer les fichiers dans l'IDE Arduino, tu cherche la petite fleche vers le bas à droite de la barre d'onglet et tu choisit "Ajouter un onglet"
Tu enregistre tous les fichiers dans le même répertoire que ton INO
Et normalement quand tu double-clique sur le INO, tout se charge

Au début du INO tu mets tous les #include "xxx.h"
Title: Re: Carte SD - programmation [mettre en tableau key et val liées] - config.txt
Post by: Geeks on Nov 02, 2012, 07:53 pm
Ok pour tout ça  8)

Je propose d'utiliser une fonction dans l'éditeur qui est de cocher éditeur externe. J'ai un bon vieux Geany qui me sert pas mal comme éditeur. Par contre, je compilerais avec l'ide arduino.

Je te remercie pour tous ces conseils et infos. Par contre require') php et java le font, peut-être pas c++ en effet  :smiley-sweat:

Bon et bien, la semaine prochaine, je met mon soft par terre, j'externalise tout  :smiley-mr-green: