Carte SD récupérer une variable

Bonjour à tous camarades de programme,
je débute en arduino, et me voici dans un mur, enfin surtout sur un projet que j'essaie de mener à terme en apprenant de mes erreurs, et me voici à ne plus rien comprendre....

Et comme je ne suis pas certain de la bonne action de mes programmes, je préfère demander.
Je dois récupérer une chaine de caractère, suivi d'une variable de 1, 2 ou 3 chiffres depuis une carte SD. Ceci dans le but de créer pour mon superbe meuble maison : un compteur de filament digitale pour chacune de mes bobines.
La chaine de caractères sera la matière du filament qui sera utilisé et que je dois envoyer sur un SSD1306 et la variable a 3 chiffres, le nombre de mètres restant que je dois incrémenter grâce à une roue codeuse ( codeur rotatif ) incrémentiel et envoyer sur le même SSD1306. Au total 12 SSD1306 sur ce meuble, et chacun ( je ne l'ai ai pas encore reçu donc j'espère faisable ) devra être connecté en i2c grâce à des TCA9548 ou peut-être si j'y arrive, en modifiant le Chipselect si ça peut fonctionner.
Je pensais enregistrer la quantité de mètres restant de chaque emplacement dans plusieurs fichiers texte differents sur la SD. Mais surtout, ma carte SD va t'elle durer longtemps si j'enregistre à chaque incrémentation la valeur obtenue dans la SD.

J'espère avoir été assez clair dans mes propos.

Mon souci à l'heure actuelle est d'arrivé à récupérer cette chaine de caractères en deux variables différentes. Un String pour le texte, et une variable pour le compteur. Je trouve sur le net, des idées pour stocker ces caractères dans un tableau avec un système de curseur pour stopper à un endroit donné mais aucune idée de comment mettre en pratique.


#include <Adafruit_SSD1306.h>
#include <splash.h>
#include <Adafruit_GFX.h>
#include <Adafruit_GrayOLED.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <SPI.h>
#include <Wire.h>
#include <SD.h>

#define OLED_RESET 4
Adafruit_SSD1306 ecran1(OLED_RESET);        // création de l'objet afficheur
/*
  Adafruit_SSD1306 ecran2(OLED_RESET);
  Adafruit_SSD1306 ecran3(OLED_RESET);
  Adafruit_SSD1306 ecran4(OLED_RESET);
  Adafruit_SSD1306 ecran5(OLED_RESET);
  Adafruit_SSD1306 ecran6(OLED_RESET);
  Adafruit_SSD1306 ecran7(OLED_RESET);
  Adafruit_SSD1306 ecran8(OLED_RESET);
  Adafruit_SSD1306 ecran9(OLED_RESET);
  Adafruit_SSD1306 ecran10(OLED_RESET);
  Adafruit_SSD1306 ecran11(OLED_RESET);
  Adafruit_SSD1306 ecran12(OLED_RESET);
*/

Sd2Card card;             // Déclaration de la SD
SdVolume volume;
SdFile root;


String buffer;
String filename = "test";   

File myFile;                  //Creation du fichier nommé monFichier

//////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////// CODEUR INCREMENTAL /////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////

 volatile int pos = 0;


void interruptA() {
  int A = digitalRead(2);
  int B = digitalRead(3);
  if (A && B || !A && !B) {                         // test si rotation positive
    pos++;
  } else {                                          // Sinon rotation negative
    pos--;
  }
}
void interruptB() {
  int A = digitalRead(2);
  int B = digitalRead(3);
  if (A && B || !A && !B) {                         // test si rotation positive
    pos--;
  } else {                                          // Sinon rotation negative
    pos++;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////////

int choixDeLecran = 1;

void setup() {

 
  pinMode(5, INPUT); // bouton changement de l'ecran
  pinMode(2, INPUT); //entree voie A
  pinMode(3, INPUT); //entree voie B
  attachInterrupt(0, interruptA, CHANGE);
  attachInterrupt(1, interruptB, CHANGE);
  //Serial.begin(9600);         
  Serial.begin(115200);

  if (!SD.begin(10)) {                                         // Si c'est different du port du CS de la carte SD
    Serial.println(" Initialisation Echec !");
    return;
  }
  Serial.println(" Initialisation Reussi ");

  if (choixDeLecran == 1) {
    
    ecran1.begin(SSD1306_SWITCHCAPVCC, 0x3C);                     // initialisation de l'objet afficheur
    if (logo == 0){
      ecran1.clearDisplay(); 
     // ecran1.drawBitmap(50, 50, logo, 64, 64, 1);
      ecran1.display();
    }


    
    //Read file line by line
    myFile = SD.open("filament1.txt", FILE_WRITE);
    if (myFile) {
      Serial.println("Lecture filament1.txt ligne par ligne: ");

      while (myFile.available()) {
        //buffer = myFile.readStringUntil('\n');          /// HELP !!!!!!!! 
        while (char filament = myFile.read;
        Serial.println(buffer);                    
        ecran1.clearDisplay();                                               // effacement de l'écran
        ecran1.setTextSize(2);                                              // choix de la taille des caractères
        ecran1.setTextColor(1);                                            // caractères en blanc
        ecran1.setCursor(43, 19);                                        // positionnement du curseur
        ecran1.print(buffer);                                         // affichage de la lecture de la sd
        ecran1.display();                                                      // validation
        
      }
      int A = digitalRead(2);
      int B = digitalRead(3);
      if (A && B || !A && !B) {                         // test si rotation positive
        filament++;
        myFile.println(filament);
        Serial.print("dans le if filament 1 :");
        Serial.println(filament);
        ecran1.print(filament); 
        ecran1.display();
      } else {                                          // Sinon rotation negative
        filament--;
        myFile.println(filament);
        Serial.print("dans le else filament 1 :");
        Serial.println(filament);
        ecran1.print(filament); 
        ecran1.display();
      }`Preformatted text`

Bonsoir

Pour que le programme soit étudié il est important de corriger le message initial pour respecter les modalités de publication de code (indentation et utilisation du balisage) .

:warning:Lire ici la partie "Utilisation de quelques outils' dans l'important message mise en évidenc en tête du nouveau Forum !

Bonjour AdminArchon

Ca fonctionne, grâce aux pin A0, A1 et A2, tu peux avoir 8 TCA9548, c'est à dire 64 affichages ou autres périphériques. i2C.

PS: Mets ton programme entre des balises image, il sera plus lisible.

Cordialement
jpbbricole

1 Like

Salut,

je crois que tu as un peu foiré avec tes balises code, je ne te jette pas la pierre, cela m'arrive aussi souvent :wink:

Pour la survie de la SD, tu estimes à combien d'écritures dans le fichier par an ?

Sinon pour le décodage d'une ligne le code suivant va peut-être t'aider :

// Decode une ligne de la forme "name=value", value de type entier (ex : truc=42)
// En retour : 0 si ok, -1 si ligne mal formée.

int decode(const String &line, char delim, String &name, int &value) {
    
    char *pline=line.c_str(); // représentation langage C, chaine terminée par 0
    char *pvalue=strchr(pline, delim); // recherche du caractère délimiteur
 
    if(pvalue==NULL) return -1; 
 
    *pvalue=0; // remplace le délimiteur par 0 pour "couper" la chaine en 2
    
    name=pline;             // lecture première partie
    value=atoi(pvalue+1);   // lecture seconde partie et conversion en entier

    *pvalue=delim; // remet le démimiteur, ni vu ni connu.

    return 0;
}

void setup() {
    Serial.begin(9600);
}

void loop() {
    String line("bidule=42");
    String name;
    int value;

    if(decode(line, '=', name, value)) {
        Serial.println("Erreur : ligne mal formée !");
        return;
    }

    Serial.println(name+" ==>  "+value);
}

Merci de ce conseil, j'ai compris comment mettre mon code complet en balise.
Autre chose que je dois changer pour correspondre à la charte du forum ?

Supercc !!!!! Un morceau de code ! J'en attendais pas tant, surtout que je suis incapable d'écrire une chose pareil, n'en ayant pas le niveau. Je pensais inscrire une variable toutes les 20 minutes environ sur des impressions qui durent en moyenne de 5h a 12h environ.
Seulement je dois récupérer la variable, la modifier (décrementer -- ) et toutes les 20 minutes, effacer l'ancienne valeur du fichier texte pour en réinscrire la nouvelle.

Merci beaucoup en tous cas, je vais tester ce code dès que je comprendrais pourquoi mon code refuse de compiler à l'heure actuelle rien que pour initialisation de la SD.
Hier, j'ai testé un programme de base pour communiquer et écrire dans la SD. Il m'annonçait que la SD n'était pas formatée, pourtant reconnue dans le programme mais impossible d'accéder aux données malgré un formatage en FAT32 fait.
J'ai essayé de rajouter SdFat, SdFatUtil, plein de bibliothèques parce que ca ne veut pas marcher malgré toutes les manipulations.... je vous joins le code qui ne compile plus...

'Sd2Card' does not name a type; did you mean 'SdCard'?
Si je supprime le 2, il me parle de SdVolume en FsVolume....
ensuite SdFile....

Le cauchemar....

#include <SdFat.h>
#include <SdFatConfig.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <utility/SdFatUtil.h>
#include <Wire.h>
#include <SPI.h>
#include <ctype.h>
LiquidCrystal_I2C lcd (0x27, 16, 2);

const int chipSelect = 10;  //pin de l'Arduino reliee au CS du module SD
Sd2Card card;
SdVolume volume;
SDFile root;
File myFile;

void setup()
{

  Serial.begin(115200);
  pinMode(A1, INPUT);
  SD.begin(10);

  while (!Serial) {
    ;
  }

  Serial.print("\nRecherche de la carte SD...");

  pinMode(10, OUTPUT);     // 53 si ArduinoMega. Peu importe la valeur de chipSelect.


  // On vérifie si une carte est présente
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("pas de carte?");
    return;
  }
  else {
    Serial.println("la carte est bien la.");
  }

  // On trouve le volume
  if (!volume.init(&card)) {
    Serial.println("La carte n'est pas formatee?");
    return;
  }

  // on sort la liste des fichiers déjà présents
  Serial.println("\nFichiers trouves sur la carte (nom, date et taille): ");
  root.openRoot(volume);
  root.ls(LS_R | LS_DATE | LS_SIZE);

  // On se prepare a jouer dans les fichiers
  if (!SD.begin(chipSelect)) {
    Serial.println("Echec de l'initialisation");
    return;
  }
  Serial.println("Initialisation OK.");

  ////////////////////////////////////

  // ouverture du fichier pour ecriture (il sera créé s'il n'existait pas déjà)
  myFile = SD.open("SECRET.txt", FILE_WRITE);
  // Si l'ouverture du fichier a fonctionné, on écrit quelque chose à l'intérieur
  if (myFile) {
    Serial.print("Ecriture dans le fichier...");
    myFile.println("Arduino est venu ici!");
    // fermeture du fichier
    myFile.close();
    Serial.println("c'est fait.");
  }
  else {
    // si l'ouverture du fichier a échoué, on l'indique
    Serial.println("impossible d'ouvrir le fichier pour l'ecriture");
  }

  // on ouvre le fichier, et on vérifie son contenu
  myFile = SD.open("SECRET.txt");
  if (myFile) {
    Serial.println("Contenu du fichier:");
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // Fermeture du fichier
    myFile.close();
  }
  else {
    // si l'ouverture du fichier a échoué, on l'indique
    Serial.println("impossible d'ouvrir le fichier pour la lecture");
  }


}

void loop() {
   
}

Salut,

aucune expérience avec les SD avec Arduino...

j'ai un peu regardé et ne voit rien d'anormal dans le code et si j'ai bien compris c'est volume.init qui foire...

Essaye peut-être une autre carte SD (peut-être qu'il y a une limite de taille ?).

Essaye peut-être d'autres exemples trouvés sur le forum ou sur Internet.

Après sauf erreur de calcul de mal part, cela fait 3x12x365 = 13140 écritures par an, il y a de la marge normalement. En plus mais là je ne suis pas certain, mais pour bénéficier du "nivellement par l'usure" du pilote de la flash je forcerai le changement de bloc à chaque écriture :

  • renommage (sauvegarde) de data.txt en data.bak
  • création d'un nouveau fichier data.txt
  • écriture dans data.txt

Bien évidemment j'arrête si erreur lors du renommage.

En procédant ainsi de nouveaux blocs mémoire sont demandés à la carte à chaque fois. Et parmi ses millions de blocs elle te trouvera les moins utilisés. Tu pourrais ainsi envisager de faire des sauvegardes plus fréquentes, voir à chaque changement de valeur.

Le wear leveling est géré par le contrôleur intégré à la carte.

Tout le programme m'a l'air bien alambiqué pour juste une lecture écriture.
Pour lire/écrire dans un fichier, il suffit d'inclure SD.h et c'est suffisant.
Le plus simple c'est de partir des fichiers d'exemple qui sont installés avec l'IDE, le sketch ReadWrite doit faire l'affaire.
Si tu veux sortir la liste des fichiers il y a l'exemple ListFiles.

#include <SdFat.h>
#include <SdFatConfig.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>

Il ne faut pas tout mélanger : SdFat et SD sont deux librairies distinctes.

S'inspirer des exemples de l'une OU de l'autre.