Enregistrement du'un fichier sur carte SD avec horodatage du nom

Bonsoir

Désolé le titre est un peu laborieux et je m’en excuse …

voila ce que je veux faire : enregistrer des données sur une carte SD avec comme nom de fichier la date type “2552012.txt” pour la date d’aujourd’hui (par exemple)

je veux faire ca pour une question pratique : ainsi j’évite d’avoir un énorme fichier unique qui grossit au fur et à mesure des enregistrements, et c’est plus facile de s’y retrouver après pour le dépouillement des données.

pas de soucis côté SD et RTC j’utilise le shield mémoire de snootlab qui fonctionne à merveille (avec un nom de fichier déclaré normalement)

le problème : je n’arrive pas à imposer ce nom de fichier j’ai le message d’erreur suivant : “error: no matching function for call to ‘SDClass::open(String&, int)’” ainsi que “note: candidates are: File SDClass::open(const char*, uint8_t)”

voici le code (allégé) :

String datafile;
datafile=String(moment.day(),DEC)+String(moment.month(),DEC)+String(moment.year(),DEC);
fichier = SD.open(datafile, FILE_WRITE);

je comprend rien, mais alors rien du tout au message d’erreur :~

si quelqu’un a déjà eu ce problème, je suis tout ouï :grin:

d’avance merci :blush:

Chris

Bonsoir, ton erreur est simple, le nom de ton fichier ne doit pas être un string mais un tableau de char donc tu dois faire comme ça:

toi:

String datafile;
datafile=String(moment.day(),DEC)+String(moment.month(),DEC)+String(moment.year(),DEC);
fichier = SD.open(datafile, FILE_WRITE);

La véritée :p

char datafile[12];
int jour=moment.day();
int mois = moment.month();
int annee= moment.year(); 
sprintf(datafile,"%d_%d_%d.txt",jour,mois,annee);  //  %d pour un int 
fichier = SD.open(datafile, FILE_WRITE);

voila, si tes fonctions moment.day .month et .year te retourne un int ça devrai fonctionner :)

J'ai pas IDE sous la main pour tester mon bou de code désolé :s

Skizo !

merci beaucoup, je vais tester et je te tiens au jus :grin:

skizoh: Bonsoir, ton erreur est simple, le nom de ton fichier ne doit pas être un string mais un tableau de char donc tu dois faire comme ça:

toi:

String datafile;
datafile=String(moment.day(),DEC)+String(moment.month(),DEC)+String(moment.year(),DEC);
fichier = SD.open(datafile, FILE_WRITE);

La véritée :p

char datafile[12];
int jour=moment.day();
int mois = moment.month();
int annee= moment.year(); 
sprintf(datafile,"%d_%d_%d.txt",jour,mois,annee);  //  %d pour un int 
fichier = SD.open(datafile, FILE_WRITE);

voila, si tes fonctions moment.day .month et .year te retourne un int ça devrai fonctionner :)

J'ai pas IDE sous la main pour tester mon bou de code désolé :s

Skizo !

C'est vrai que c'est une question que je me suis déjà demandée...

On écrit dans une espèce de C/C++, mais, au final, si une fonction attend un *char, que ce passe t'il si on envoie un String ?

énorme, ca s'est compilé du premier coup sans erreur :grin: :grin: :grin:

j'ai pas l'arduino sous la main mais à mon avis ca doit marcher :D :D :D

vohu: On écrit dans une espèce de C/C++, mais, au final, si une fonction attend un *char, que ce passe t'il si on envoie un String ?

Le compilateur n’appréciera pas et le fera remarquer. :grin: Une variable de type tableau de char c'est une chaine de caractères, mais une variable objet de type String est l'instance d'une classe (String) qui possède un tableau de char en attribut qu'il manipulera via ses méthodes.

On écrit dans une espèce de C/C++

On écrit à 100% en C++. L'IDE prend le sketch .INO, ajoute des bricoles en amont (#include "Arduino.h" et pré-déclarations des fonctions) puis ca passe dans un compilateur C++ C'est 100% du C++ compilé. Toute les règles du C++ s'appliquent.

sprintf(datafile,"%d_%d_%d.txt",jour,mois,annee)

Ce code ne se préoccupe pas des nombres à 1 ou 2 chiffres En plus tu ne sais plus compter : il faut 15 caractères (14 letttres/chiffres + le caractère nul) donc la variable datafile n'est pas assez grande

char datafile[15];
sprintf(datafile,"%04d_%02d_%02d.txt",jour,mois,annee);

Par ailleurs, String est une classe basée sur de la gestion dynamique de mémoire (malloc/free). C'est super pratique de ne pas avoir a se préoccuper de la taille du tableau de caractère à allouer mais c'est super dangereux sur un système qui n'a que 2Koctet de mémoire. On n'est pas en Java ou en C#, il n'y a pas de "garbage collector" et l'allocation/libération de mémoire durant l'exécution crée des "trous" dans la mémoire. On peut se retrouver avec plein de petits morceux de mémoire libre mais non contigus donc impossible d'allouer un nouvel espace mémoire. Et la c'est le crash (pointeur NULL non alloué et le programme fait n’importe quoi).

Donc je déconseille fortement tout ce qui utilise malloc/free, new/delete et String.

donc en gros, tu conseilles de coder en C dans un environnement C++. Car si tu n'utilises pas new, tu n'utilises plus grand chose apporté par le C++

Ce qui revient à ce que je disais 'On écrit dans une espèce de C/C++'

Le C++ ne se limite pas à la création dynamique.

Tu fais du C++ à chaque instant sur ton Arduino : - Serial.print() qui supporte plusieurs type de paramètre d'entrée : c'est le mécanisme de surcharge du C++ qui n'existe pas en C - Serial : classe dérivée e Stream dérive de Print : hérite des fonctions de conversion et d'affichage de différents types En utilisant LiquidCrytal tu en bénéficie aussi. - Le fait de déclarer ses variables n'importe où dans le code et non pas seulement en en-tête des fonctions : c'est du C++.

Une bonne partie de lib Core Arduino est en C++.

Donc non, utilisez le C++ à fond mais sachez ce que vous faites et surtout faites attention à l'usage dynamique de la mémoire.

Un code embarqué ne peut pas afficher "Cette application s'est inopinément arrêtée pour manque de mémoire. Veuillez contacter votre administrateur système". Elle ne dispose pas de swap pour étendre la mémoire à l'infinie sur le disque dur.

Elle crashe et suivant ce qu'elle contrôle il peut y avoir des dégats (moteurs actionneurs, 220V, etc ...). Donc elle doit être à 100% prédictible. La plupart des gens ne vérifient pas le retour des fonctions y compris malloc() et ne savent pas gérer correctement les cas d'erreurs. new ne doit s'utiliser que dans un try/catch et le catch doit gérer proprement le cas d'erreur.

Salut,

vohu: donc en gros, tu conseilles de coder en C dans un environnement C++. Car si tu n'utilises pas new, tu n'utilises plus grand chose apporté par le C++

De toute manière pour new et delete c'est pas bien compliqué, l'implémentation de new fourni avec le compilateur de base est buggé (donc inutilisable).

barbudor: Un code embarqué ne peut pas afficher "Cette application s'est inopinément arrêtée pour manque de mémoire. Veuillez contacter votre administrateur système". Elle ne dispose pas de swap pour étendre la mémoire à l'infinie sur le disque dur.

Ce serais marrant d'avoir un message dans le genre :grin: Tient ça me fait penser au 2 minutes du peuple :grin: http://www.youtube.com/watch?v=XszvS98VxOc&feature=player_detailpage#t=110s

bon ca a pas l'air de marcher, en fait aucun fichier n'est créé sur la carte SD

je me demande si les fonctions moment.xxx retournent bien un int ? :astonished:

Effectivement autre problème oublié : le nom d'un fichier est max de 8 caractèers plus l'extension Donc il ne faut pas les soulignés :

sprintf(datafile,"%04d%02d%02d.txt",jour,mois,annee);

C'est d'ailleurs ce que tu voulais faire ua début

n'hésite pas à afficher sur le terminal le nom de fichier ainsi créé pour vérifier ce que ca fait.

olalala ^^ oui effectivement j'ai oublié le caractère de fin chaine désolé :s et c'est vrai pour cette histoire de 8 caractère javai oublier j'ai déjà eu ce problème et c'est justement barbudor qui m'avais dépanné et oui j'avais également oublié les %02 ou %04 mais ça c'est du rajout si il s'en fou des 0 comme dans sont exemple c'est bon du coup ^^

bref au final test ça:

char datafile[13];
int jour=moment.day();
int mois = moment.month();
int annee= moment.year(); 
sprintf(datafile,"%02d%02d%04d.txt",jour,mois,annee);  //  %d pour un int 
datafile[13]='\0';
fichier = SD.open(datafile, FILE_WRITE);

Voila monsieur :)

Skizo !

Skizoh

pas besoin de rajouter le caractères nul à la fin, sprintf le fait de lui même. Il fallait surtout penser à le compter dans la taille du tableau.

skizoh: olalala ^^ oui effectivement j'ai oublié le caractère de fin chaine désolé

ralala faut lire la doc dés fois ;)

http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

On success, the total number of characters written is returned. This count does not include the additional null-character automatically appended at the end of the string.

Comme on dis dans ce genre de cas : [u]Read The Fucking Manual[/u] :grin:

Edit : Damned j'ai été grilled by barbudor ...

olalala autant pour moi les filles on la refais:

char datafile[13];
int jour=moment.day();
int mois = moment.month();
int annee= moment.year(); 
sprintf(datafile,"%02d%02d%04d.txt",jour,mois,annee);  //  %d pour un int 
fichier = SD.open(datafile, FILE_WRITE);

skywodd:

skizoh: olalala ^^ oui effectivement j'ai oublié le caractère de fin chaine désolé

ralala faut lire la doc dés fois ;)

pas question de doc petit oublie c'est tout :)

Skizo !

Ca marche Ni-ckel XD XD XD

chapeau les gars, vous êtes des dieux vivants. Sérieux j'aurais jamais trouvé ca tout seul !

j'espère que ca pourra servir à tout ceux qui veulent faire de l'arduino un super datalogger.

encore un grand merci :grin:

mistercricri: Ca marche Ni-ckel XD XD XD

chapeau les gars, vous êtes des dieux vivants. Sérieux j'aurais jamais trouvé ca tout seul !

j'espère que ca pourra servir à tout ceux qui veulent faire de l'arduino un super datalogger.

encore un grand merci :grin:

Pourquoi un nom de fichier type JJMMAAAA et non pas AAAAMMJJ ? Pour trier c'est bien plus simple si tu veux faire un historique de courbe par exemple.

De rien monsieur !

Skizo !

Hello !

Je déterre un topic preuve que j’ai utilisé la fonction rechercher :stuck_out_tongue:

J’ai testé pour mon horodatage, mais j’ai l’erreur suivante qui ressort…

'moment' was not declared in this scope

J’ai cherché un peu partout mais je ne vois pas comment le déclarer sans que le compilateur m’embête…

Pour l’instant c’est une configuration 1 bouton, mais à terme j’en mettrai 4.
J’y vais étape par étape…

Voici mon code :

ps : si au passage vous avez une idée pour simplifier le code, je suis preneur !

Merci !

    #include <SD.h>
    #include <Wire.h>
    #include "RTClib.h"
    
    RTC_DS1307 rtc;
    
    // constants won't change. They're used here to 
    // set pin numbers:
    const int buttonPin = 2;    // the number of the pushbutton pin
    const int ledPin = 12;      // the number of the LED pin
    const int chipSelect = 4;
    
    
    // Variables will change:
    int ledState = HIGH;         // the current state of the output pin
    int buttonState = 0;             // the current reading from the input pin
    
    char datafile[13];
    int jour = moment.day();
    int mois = moment.month();
    int annee = moment.year(); 
    
    void setup() {
    
       // Open serial communications and wait for port to open:
      Serial.begin(57600);
      
      Serial.println("Initializing RTC...");
      #ifdef AVR
    Wire.begin();
  #else
    Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
  #endif
    rtc.begin();
  
    if (! rtc.isrunning()) 
    {
      Serial.println("RTC is NOT running!");
      // following line sets the RTC to the date & time this sketch was compiled
      rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
      // This line sets the RTC with an explicit date & time, for example to set
      // January 21, 2014 at 3am you would call:
      // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));  
    }
        else 
      {
      Serial.println("                RTC OK");
      delay (200);
    }
        
  Serial.println("Initializing SD card...");
  
  
      // make sure that the default chip select pin is set to
      // output, even if you don't use it:
      pinMode(10, OUTPUT);
      
      // see if the card is present and can be initialized:
      if (!SD.begin(chipSelect)) {
        Serial.println("Card failed, or not present");
        // don't do anything more:
        return;
       
      }
      Serial.println("                Card initialized.");
      delay(100);
      Serial.println("...Waiting for incoming data...");
  
      pinMode(buttonPin, INPUT);
      pinMode(ledPin, OUTPUT);
    
      // set initial LED state
      digitalWrite(ledPin, ledState);  
  
  }
      
    void loop() {
       buttonState = digitalRead(buttonPin);
      if (buttonState == HIGH) { 
     
      DateTime now = rtc.now();
        
      // make a string for assembling the data to log:
      String dataString = "A";
      
      // open the file. note that only one file can be open at a time,
      // so you have to close this one before opening another.
      
     
      sprintf(datafile,"%02d%02d%04d.txt",jour,mois,annee);  //  %d pour un int 
      fichier = SD.open(datafile, FILE_WRITE);
      
    
      // if the file is available, write to serial :
      
      if (dataFile) {
      Serial.print(dataString);
      Serial.print(';');
      Serial.print(now.year(), DEC);
      Serial.print('/');
      Serial.print(now.month(), DEC);
      Serial.print('/');
      Serial.print(now.day(), DEC);
      Serial.print(';');
      Serial.print(now.hour(), DEC);
      Serial.print(':');
      Serial.print(now.minute(), DEC);
      Serial.print(':');
      Serial.print(now.second(), DEC);
      Serial.println();
      
      //and to SD Card
      dataFile.print(dataString);
      dataFile.print(';');
      dataFile.print(now.year(), DEC);
      dataFile.print('/');
      dataFile.print(now.month(), DEC);
      dataFile.print('/');
      dataFile.print(now.day(), DEC);
      dataFile.print(';');
      dataFile.print(now.hour(), DEC);
      dataFile.print(':');
      dataFile.print(now.minute(), DEC);
      dataFile.print(':');
      dataFile.print(now.second(), DEC);
      dataFile.println();
        dataFile.close();
        // print to the serial port too:
        Serial.println();
        Serial.println("Data correctly logged!");  
        delay(1000);
      }  
      // if the file isn't open, pop up an error:
      else {
        Serial.println("error opening datalog.txt");
         // re-open the file for reading:
         
      } 
      }
      
    }

Merci d’avance pour votre aide !