[RESOLU] Enregistrer data sur carte SD puis Envoie vers COSM

Bonjour,

je reviens vers vous avec un nouveau problème ...
j'essaie d'enregistrer le nombre de clignotement d'une led sur une carte SD puis de stocker cette valeur sur COSM.

j'ai donc commencé par l'enregistrement sur la carte SD => cela fonctionne
puis j'ai essayé l'envoie d'une valeur à COSM avec l'exemple de l'IDE cela fonctionne

j'essaie maintenant de regrouper les deux progs et là ... problème

j'ai dans l'interface série ceci qui n'arrête pas de défiler

InitInitialisation de la SD card...
InitInitialisation de la SD card...
InitInitialisation de la SD card...
InitInitialisation de la SD card...

j'ai essayé d'isoler le morceaux de code pour identifier d'ou vient le problème mais impossible de trouver ce qui cloche.

Auriez vous une idée ?

#include <SD.h>
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
// --- Déclaration des constantes utiles ---
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield

// cosm
#define APIKEY         "xxxxxxxxxxxxxxxxxx" // replace your Cosm api key here
#define FEEDID         56809 // replace your feed ID
#define USERAGENT      "Vera" // user agent is the project name
//

byte mac[] = {  
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
// cosm
// initialize the library instance:
EthernetClient client;
char server[] = "api.cosm.com";   // name address for cosm API

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000; //delay between updates to cosm.com
//

time_t prevDisplay = 0; // when the digital clock was displayed
const  int timeZoneOffset = +1; // GMT zone;
// --- Déclaration des constantes des broches E/S numériques ---

const int brocheSDCardSelect=4;

// --- Déclaration des constantes des broches analogiques ---


// --- Déclaration des variables globales ---

volatile long comptageImpulsion=0; // variable accessible dans la routine interruption externe 0
int test; // Variable utilisée pour tester valeur renvoyée par fonctions SD Card

// --- Déclaration des objets utiles pour les fonctionnalités utilisées ---
File file; // objet file 
File root; // objet root pour le répertoire racine

// ////////////////////////// 2. FONCTION SETUP = Code d'initialisation ////////////////////////// 
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme

void setup()   { // debut de la fonction setup()

  // --- ici instructions à exécuter 1 seule fois au démarrage du programme --- 

  // ------- Initialisation fonctionnalités utilisées -------  

  Serial.begin(115200); // initialise connexion série à 115200 bauds
  // IMPORTANT : régler le terminal côté PC avec la même valeur de transmission 

  //---- initialise l'utilisation de la carte mémoire SD en mode SPI  
  pinMode(10, OUTPUT); // met la broche 10 (SS) en sortie (nécessaire avec module ethernet)
  digitalWrite(10, HIGH); // mais désactive le  circuit intégré W5100 du module ethernet!

  //----- initialisation de la carte SD ----- 
  Serial.println("Initialisation de la SD card...");

  pinMode(10, OUTPUT); // laisser la broche SS en sortie - obligatoire avec librairie SD

  test=SD.begin(brocheSDCardSelect); // initialisation de la carte SD avec broche 4 en tant que CS - renvoie true/false

  if (test!=true) { // si initialisation n'est pas réussie
    Serial.println("Echec initialisation!"); // message port Série
  }
  else { // si nitialisation réussie
    Serial.println("Initialisation reussie !"); // message port Série

    //----- affiche le contenu du répertoire 

    root = SD.open("/"); // ouvre la SD Card à la racine

    Serial.println("Repertoire racine ouvert !");
  }

  attachInterrupt(0, gestionINT0, RISING); // attache l'interruption externe n°0 à la fonction gestionINT0()
  // mode déclenchement possibles = LOW, CHANGE, RISING, FALLING


    // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  Udp.begin(localPort);
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet)   
    ; // wait until the time is set by the sync provider
  //---- crée fichier en écriture --- 
  file = SD.open("data.txt", FILE_WRITE); // ouvre le fichier en écriture
  // NB : le fichier est créé si il n'existe pas !

  //---- test si fichier dispo en écriture 
  if (!file) { // si fichier pas dispo 

    Serial.println ("Erreur ouverture fichier !");

  } // fin if

  else { // si le fichier existe et est ouvert 

    Serial.println ("Fichier pret pour ecriture !");

    //----- Ecriture dans le fichier au format CSV ----- 

    // premiere ligne du fichier CSV - entete avec liste des champs
    file.println("Nbreimpulsion;Millis;Heure;Minute;Seconde;Jour;Mois;Annee");


    file.close(); // ferme le fichier
    Serial.println("Fin enregistrement !");  
    Serial.println("Fermeture fichier !");
  }  
  // ------- Broches en sorties numériques -------  

  // ------- Broches en entrées numériques -------  

  // ------- Activation si besoin du rappel au + (pullup) des broches en entrées numériques -------  

  // ------- Initialisation des variables utilisées -------  

} // fin de la fonction setup()

Fin du code :slight_smile:

void loop(){ // debut de la fonction loop()
  //---- crée fichier en écriture --- 
  file = SD.open("data.txt", FILE_WRITE); // ouvre le fichier en écriture
  // NB : le fichier est créé si il n'existe pas !

  //---- test si fichier dispo en écriture 
  if (!file) { // si fichier pas dispo 

    Serial.println ("Erreur ouverture fichier !");

  } // fin if

  else { // si le fichier existe et est ouvert 

    Serial.println ("Fichier pret pour ecriture !");

    //----- Ecriture dans le fichier au format CSV ----- 

    Serial.println ("Enregistrement en cours :");

    // valeur deuxieme champ
    file.print(comptageImpulsion), file.print(';'); 

    // valeur quatrieme champ
    file.print(millis()), file.print(';');

    // le dernier champ doit se terminer par un saut de ligne +++
    if( now() != prevDisplay) //update the display only if the time has changed
    {
      prevDisplay = now();
      digitalClockDisplay();  
    }  
    file.close(); // ferme le fichier
    Serial.println("Fin enregistrement !");  
    Serial.println("Fermeture fichier !"); 

    // cosm
    // read the analog sensor:
    int sensorReading = comptageImpulsion ;   

    // if there's incoming data from the net connection.
    // send it out the serial port.  This is for debugging
    // purposes only:
    if (client.available()) {
      char c = client.read();
      Serial.print(c);
    }
    // if there's no net connection, but there was one last time
    // through the loop, then stop the client:
    if (!client.connected() && lastConnected) {
      Serial.println();
      Serial.println("disconnecting.");
      client.stop();
    }
    // if you're not connected, and ten seconds have passed since
    // your last connection, then connect again and send data:
    if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
      sendData(sensorReading);
    }
    // store the state of the connection for next time through
    // the loop:
    lastConnected = client.connected();


    //

    delay(120000);

  } // fin else

} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
// ********************************************************************************



// this method makes a HTTP connection to the server:
void sendData(int thisData) {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    //  send the HTTP PUT request:
    client.print("PUT /v2/feeds/");
    client.print(FEEDID);
    client.println(".csv HTTP/1.1");
    client.println("Host: api.cosm.com");
    client.print("X-ApiKey: ");
    client.println(APIKEY);
    client.print("User-Agent: ");
    client.println(USERAGENT);
    client.print("Content-Length: ");

    // calculate the length of the sensor reading in bytes:
    // 8 bytes for "sensor1," + number of digits of the data:
    int thisLength = 8 + getLength(thisData);
    client.println(thisLength);

    // last pieces of the HTTP PUT request:
    client.println("Content-Type: text/csv");
    client.println("Connection: close");
    client.println();

    // here's the actual content of the PUT request:
    client.print("sensor2,");
    client.println(thisData);

  } 
  else {
    //if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }
  // note the time that the connection was made or attempted:
  lastConnectionTime = millis();
}


// This method calculates the number of digits in the
// sensor reading.  Since each digit of the ASCII decimal
// representation is a byte, the number of digits equals
// the number of bytes:

int getLength(int someValue) {
  // there's at least one byte:
  int digits = 1;
  // continually divide the value by ten, 
  // adding one to the digit count for each
  // time you divide, until you're at 0:
  int dividend = someValue /10;
  while (dividend > 0) {
    dividend = dividend /10;
    digits++;
  }
  // return the number of digits:
  return digits;
}
// ////////////////////////// FONCTIONS DE GESTION DES INTERRUPTIONS //////////////////// 

// ------------------- fonction de gestion l'interruption externe n°0 (broche 2) ----------------
// cette fonction est appelée à chaque fois que l'interruption a lieu selon le mode configuré (LOW, CHANGE, RISING, FALLING)
void gestionINT0() {// la fonction appelée par l'interruption externe n°0

    comptageImpulsion=comptageImpulsion+1; // Incrémente la variable de comptage

  //---- affiche le nombre d'impulsions sur le port série
  Serial.print("Nombre impulsions = "); 
  Serial.println(comptageImpulsion); 

  // tout se passe dans la fonction de gestion de l'interruption externe

}


// ////////////////////////// AUTRES FONCTIONS DU PROGRAMME //////////////////// 

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" -- ");
  Serial.print(day());
  Serial.print("/");
  Serial.print(month());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println();
  file.print(hour()), file.print(';');
  printDigitsSD(minute()), file.print(';');
  printDigitsSD(second()), file.print(';');
  file.print(day()), file.print(';');
  file.print(month()), file.print(';');
  file.print(year()), file.print(';'); 
  file.println();
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void printDigitsSD(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  if(digits < 10)
    file.print('0');
  file.print(digits);
}

/*-------- NTP code ----------*/

unsigned long getNtpTime()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  delay(1000);
  if ( Udp.parsePacket() ) {  
    // We've received a packet, read the data from it
    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord; 
    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years and add the time zone:
    unsigned long epoch = secsSince1900 - seventyYears + (timeZoneOffset * 3600L);
    return epoch;
  }
  return 0;
}

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

Boucler ainsi sur la fonction setup c'est souvent signe d'un gros plantage, généralement écrabouillage de la mémoire qui fait que le code part dans les choux.
Etonnnant que ca n'aille pas plus loin

Ton code est trop grand pour ma Leonardo.
Je vais essayer de le simplifier pour tester.

J'arrive pas à faire rentrer sur ma Léonardo. Ethernet+SD ca fait trop...

Je pense qu'il y a un problème de mémoire.
Tu as beaucoup beaucoup beaucoup de chaines de caractères.
Or les chaines de caractères sont recopiées de la mémoire Flash en RAM.
Il y a des astuces pour garder les chaines en Flash.
Regarde de ce coté :

http://jeelabs.org/2011/05/23/saving-ram-space/

merci pour le tuyau.
J'ai modifié le code pour l'initialisation

showString(PSTR("Initialisation de la SD card..."));

et j'ai ajouté la fonction

void showString (PGM_P s) {
        char c;
        while ((c = pgm_read_byte(s++)) != 0)
            Serial.print(c);
    }

cela ne boucle plus le l'initalisation et l'indique que celel ci est réussie sauf que ... cela ne va pas plus loin le fichier DATA.txt n'est pas créé ???

dois je continuer à remplacer tous les strings selon la méthode précédente ? Est ce cela mon unique problème ?

Je pense que tu es partit dans la bonne direction. Le programme va plus loin mais finit par planter.
Continuer à passer encore plus de chose en FLASH.

Evites les chaines de 1 caractères :

  Serial.print("/");

qui consomme 2 octets alors que un caractère :

  Serial.print('/');

n'en consomme qu'un.

J'ai continué à remplacer tous les serial.print et en effet cela semble progresser.

Puis je faire la meme chose avec les file.print et les client.print ?

En ajoutant cette fonction

void showStringfile (PGM_P s) {
char c;
while ((c = pgm_read_byte(s++)) != 0)
file.print(c);
}

et en l'appelant ainsi
showStringfile(PSTR("Nbreimpulsion;Millis;Heure;Minute;Seconde;Jour;Mois;Annee"))

Une autre question, il semble impossible de passer une variable comme parametre est ce exact ou y a t il une syntaxe différente à utiliser ?

Merci encore pour votre aide efficace

Puis je faire la meme chose avec les file.print et les client.print ?

Oui

Puis je faire la meme chose avec les file.print et les client.print ?
En ajoutant cette fonction

Pourquoi ajouter une fonction ?
Tous les types qui dérivent de Stream/Print supportent cette fonction.

size_t Print::print(const __FlashStringHelper *ifsh)
{
  const char PROGMEM *p = (const char PROGMEM *)ifsh;
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    n += write(c);
  }
  return n;
}

Donc Serial, EthernetClient, File, etc ... l'ont déjà.

  Serial.print( (__FlashStringHelper *)PSTR("Nbreimpulsion;Millis;Heure;Minute;Seconde;Jour;Mois;Annee") );
  file.print( (__FlashStringHelper *)PSTR("Nbreimpulsion;Millis;Heure;Minute;Seconde;Jour;Mois;Annee") );
  client.print( (__FlashStringHelper *)PSTR("Nbreimpulsion;Millis;Heure;Minute;Seconde;Jour;Mois;Annee") );

Une autre question, il semble impossible de passer une variable comme paramètre est ce exact ou y a t il une syntaxe différente à utiliser ?

Ben si. Que cherches tu a passer ?

void toto( int a )
{
  Serial.println(a);
}

x = 123;

void setup()
{
  toto( x );
}

je n'avais pas fait comme cela pour la syntaxe.
J'ai corrigé comme tu me l'as dis et cela fonctionne bien.

Par contre lorsque je mets ca

file.print( (__FlashStringHelper *)PSTR(comptageImpulsion));

j'ai un message d'erreur.

error: initializer fails to determine size of '__c'

comptageimpulsion est une variable. D'ou ma question de tout à l'heure ..

Je comprend la question.

Non seules les chaines de caractères qui sont constantes doivent passer en Flash.
Tu ne peux pas mettre une variable en flash, sinon, elle n'est plus variable :wink:

PS: Va voir aussi ici : Questions sur le html - #25 by system - Français - Arduino Forum
Je donne un exemple sur comment utiliser un serveur web externe pour stocker les pages et n'aller chercher sur l'Arduino que les données.

ok donc j'ai modifié le code des chaines de caractere pour les passer en flash.
L'enregistrement sur la carte SD est maintenant opérationnel.

Merci :slight_smile:

Par contre la partie envoie des données vers cosm ne fonctionne pas.
Je n'ai rien dans les logs donc je suppose que le prog ne passe jamais dans la partie du code qui gère la partie cosm.

J'ai fait des modifs à droite à gauche mais impossible d'envoyer les datas vers cosm. Why ?? Je ne sais plus je suis perdu :relaxed:

Peux tu remettre en attachement ton code dans l'état actuel ?
J'essayerais d'y jeter un coup d'oeil demain ou mardi.

Le voici merci encore pour ton aide

// /////////////////////////////// 1. Entête déclarative /////////////////////// 
// A ce niveau sont déclarées les librairies incluses, les constantes, les variables, les objets utiles...

// --- Déclaration des constantes ---

// --- Inclusion des librairies ---
#include <SD.h>
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
#include <avr/pgmspace.h>
// --- Déclaration des constantes utiles ---
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield

// cosm
#define APIKEY         "xxxxxxxxxxxxxxx" // replace your Cosm api key here
#define FEEDID         56809 // replace your feed ID
#define USERAGENT      "Vera" // user agent is the project name
//

byte mac[] = {  
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets 

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
// cosm
// initialize the library instance:
EthernetClient client;
char server[] = "api.cosm.com";   // name address for cosm API

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 10*1000; //delay between updates to cosm.com
//

time_t prevDisplay = 0; // when the digital clock was displayed
const  int timeZoneOffset = +1; // GMT zone;
// --- Déclaration des constantes des broches E/S numériques ---

const int brocheSDCardSelect=4;

// --- Déclaration des constantes des broches analogiques ---


// --- Déclaration des variables globales ---

volatile long comptageImpulsion=0; // variable accessible dans la routine interruption externe 0
int test; // Variable utilisée pour tester valeur renvoyée par fonctions SD Card

// --- Déclaration des objets utiles pour les fonctionnalités utilisées ---
File file; // objet file 
File root; // objet root pour le répertoire racine

// ////////////////////////// 2. FONCTION SETUP = Code d'initialisation ////////////////////////// 
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme

void setup()   { // debut de la fonction setup()

  // --- ici instructions à exécuter 1 seule fois au démarrage du programme --- 

  // ------- Initialisation fonctionnalités utilisées -------  

  Serial.begin(115200); // initialise connexion série à 115200 bauds
  // IMPORTANT : régler le terminal côté PC avec la même valeur de transmission 

  //---- initialise l'utilisation de la carte mémoire SD en mode SPI  
  pinMode(10, OUTPUT); // met la broche 10 (SS) en sortie (nécessaire avec module ethernet)
  digitalWrite(10, HIGH); // mais désactive le  circuit intégré W5100 du module ethernet!

  //----- initialisation de la carte SD ----- 
  Serial.println( (__FlashStringHelper *)PSTR("Initialisation de la SD card..."));

  pinMode(10, OUTPUT); // laisser la broche SS en sortie - obligatoire avec librairie SD

  test=SD.begin(brocheSDCardSelect); // initialisation de la carte SD avec broche 4 en tant que CS - renvoie true/false

  if (test!=true) { // si initialisation n'est pas réussie
    Serial.println( (__FlashStringHelper *)PSTR("Echec initialisation!")); // message port Série
  }
  else { // si nitialisation réussie
    Serial.println( (__FlashStringHelper *)PSTR("Initialisation reussie !")); // message port Série

    //----- affiche le contenu du répertoire 

    root = SD.open("/"); // ouvre la SD Card à la racine

    Serial.println( (__FlashStringHelper *)PSTR("Repertoire racine ouvert !"));
  }

  attachInterrupt(0, gestionINT0, RISING); // attache l'interruption externe n°0 à la fonction gestionINT0()
  // mode déclenchement possibles = LOW, CHANGE, RISING, FALLING


    // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    Serial.println( (__FlashStringHelper *)PSTR("Failed to configure Ethernet using DHCP"));
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  Udp.begin(localPort);
  setSyncProvider(getNtpTime);
  while(timeStatus()== timeNotSet)   
    ; // wait until the time is set by the sync provider
  //---- crée fichier en écriture --- 
  file = SD.open("data.txt", FILE_WRITE); // ouvre le fichier en écriture
  // NB : le fichier est créé si il n'existe pas !

  //---- test si fichier dispo en écriture 
  if (!file) { // si fichier pas dispo 

    Serial.println( (__FlashStringHelper *)PSTR("Erreur ouverture fichier !"));

  } // fin if

  else { // si le fichier existe et est ouvert 

    Serial.println( (__FlashStringHelper *)PSTR("Fichier pret pour ecriture !"));

    //----- Ecriture dans le fichier au format CSV ----- 

    // premiere ligne du fichier CSV - entete avec liste des champs
    // showStringfileln(PSTR("Nbreimpulsion;Millis;Heure;Minute;Seconde;Jour;Mois;Annee"));
    file.println( (__FlashStringHelper *)PSTR("Nbreimpulsion;Millis;Heure;Minute;Seconde;Jour;Mois;Annee") );

    file.close(); // ferme le fichier
    Serial.println( (__FlashStringHelper *)PSTR("Fin enregistrement !"));  
    Serial.println( (__FlashStringHelper *)PSTR("Fermeture fichier !"));
  }  
  // ------- Broches en sorties numériques -------  

  // ------- Broches en entrées numériques -------  

  // ------- Activation si besoin du rappel au + (pullup) des broches en entrées numériques -------  

  // ------- Initialisation des variables utilisées -------  

} // fin de la fonction setup()
// ********************************************************************************

////////////////////////////////// 3. FONCTION LOOP = Boucle sans fin = coeur du programme //////////////////
// la fonction loop() s'exécute sans fin en boucle aussi longtemps que l'Arduino est sous tension

void loop(){ // debut de la fonction loop()





  //---- crée fichier en écriture --- 
  file = SD.open("data.txt", FILE_WRITE); // ouvre le fichier en écriture
  // NB : le fichier est créé si il n'existe pas !

  //---- test si fichier dispo en écriture 
  if (!file) { // si fichier pas dispo 

    Serial.println( (__FlashStringHelper *)PSTR("Erreur ouverture fichier !"));

  } // fin if

  else { // si le fichier existe et est ouvert 

    Serial.println( (__FlashStringHelper *)PSTR("Fichier pret pour ecriture !"));

    //----- Ecriture dans le fichier au format CSV ----- 

    Serial.println( (__FlashStringHelper *)PSTR("Enregistrement en cours :"));

    // valeur deuxieme champ
    file.print(comptageImpulsion);
    file.print(';'); 
    // valeur quatrieme champ
    file.print(millis()), file.print(';');

    // le dernier champ doit se terminer par un saut de ligne +++
    if( now() != prevDisplay) //update the display only if the time has changed
    {
      prevDisplay = now();
      digitalClockDisplay();  
    }  
    file.close(); // ferme le fichier
    Serial.println( (__FlashStringHelper *)PSTR("Fin enregistrement !"));  
    Serial.println( (__FlashStringHelper *)PSTR("Fermeture fichier !")); 

    // cosm
    // read the analog sensor:
    int sensorReading = comptageImpulsion ;   

    // if there's incoming data from the net connection.
    // send it out the serial port.  This is for debugging
    // purposes only:
    if (client.available()) {
      char c = client.read();
      Serial.print(c);
    }
    // if there's no net connection, but there was one last time
    // through the loop, then stop the client:
    if (!client.connected() && lastConnected) {
      Serial.println();
      Serial.println( (__FlashStringHelper *)PSTR("disconnecting."));
      client.stop();
    }
    // if you're not connected, and ten seconds have passed since
    // your last connection, then connect again and send data:
    if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
      sendData(sensorReading);
    }
    // store the state of the connection for next time through
    // the loop:
    lastConnected = client.connected();


    //

    delay(120000);

  } // fin else

} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
// ********************************************************************************
// ////////////////////////// FONCTIONS DE GESTION DES INTERRUPTIONS //////////////////// 

// ------------------- fonction de gestion l'interruption externe n°0 (broche 2) ----------------
// cette fonction est appelée à chaque fois que l'interruption a lieu selon le mode configuré (LOW, CHANGE, RISING, FALLING)
// this method makes a HTTP connection to the server:
void sendData(int thisData) {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println( (__FlashStringHelper *)PSTR("connecting..."));
    // send the HTTP PUT request:
    client.print("PUT /v2/feeds/");
    client.print(FEEDID);
    client.println(".csv HTTP/1.1");
    client.println("Host: api.cosm.com");
    client.print("X-ApiKey: ");
    client.println(APIKEY);
    client.print("User-Agent: ");
    client.println(USERAGENT);
    client.print("Content-Length: ");

    // calculate the length of the sensor reading in bytes:
    // 8 bytes for "sensor1," + number of digits of the data:
    int thisLength = 8 + getLength(thisData);
    client.println(thisLength);

    // last pieces of the HTTP PUT request:
    client.println("Content-Type: text/csv");
    client.println("Connection: close");
    client.println();

    // here's the actual content of the PUT request:
    client.print("sensor2,");
    client.println(thisData);

  } 
  else {
    // if you couldn't make a connection:
    Serial.println( (__FlashStringHelper *)PSTR("connection failed"));
    Serial.println();
    Serial.println( (__FlashStringHelper *)PSTR("disconnecting."));
    client.stop();
  }
  // note the time that the connection was made or attempted:
  lastConnectionTime = millis();
}


// This method calculates the number of digits in the
// sensor reading.  Since each digit of the ASCII decimal
// representation is a byte, the number of digits equals
// the number of bytes:

int getLength(int someValue) {
  // there's at least one byte:
  int digits = 1;
  // continually divide the value by ten, 
  // adding one to the digit count for each
  // time you divide, until you're at 0:
  int dividend = someValue /10;
  while (dividend > 0) {
    dividend = dividend /10;
    digits++;
  }
  // return the number of digits:
  return digits;
}

void gestionINT0() {// la fonction appelée par l'interruption externe n°0

    comptageImpulsion=comptageImpulsion+1; // Incrémente la variable de comptage

  //---- affiche le nombre d'impulsions sur le port série
  Serial.print("Nombre impulsions = "); 
  Serial.println(comptageImpulsion); 

  // tout se passe dans la fonction de gestion de l'interruption externe

}


// ////////////////////////// AUTRES FONCTIONS DU PROGRAMME //////////////////// 

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" -- ");
  Serial.print(day());
  Serial.print("/");
  Serial.print(month());
  Serial.print("/");
  Serial.print(year()); 
  Serial.println();
  file.print(hour()), file.print(';');
  printDigitsSD(minute()), file.print(';');
  printDigitsSD(second()), file.print(';');
  file.print(day()), file.print(';');
  file.print(month()), file.print(';');
  file.print(year()), file.print(';'); 
  file.println();
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void printDigitsSD(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  if(digits < 10)
    file.print('0');
  file.print(digits);
}

/*-------- NTP code ----------*/

unsigned long getNtpTime()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  delay(1000);
  if ( Udp.parsePacket() ) {  
    // We've received a packet, read the data from it
    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord; 
    const unsigned long seventyYears = 2208988800UL;     
    // subtract seventy years and add the time zone:
    unsigned long epoch = secsSince1900 - seventyYears + (timeZoneOffset * 3600L);
    return epoch;
  }
  return 0;
}

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress& address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE); 
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49; 
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

// ////////////////////////// Fin du programme ////////////////////

Je pense que tu as repris le code de l'exemple COSM et tu la mélangé à ton code SD sans trop chercher à en comprendre la logique.

Le delay de 120 dans le loop est une mauvaise idée car tout est bloqué pendant 2 minutes.
Je suppose que toutes les 120 secondes tu veux enregistrer une donnée dans la SD et envoyer la mise à jour à COSM.

Si c'est bien cela j'ai revu la logique de ta boucle :

// variables globales :
#define PERIOD_WRITE_DATA    120000
unsigned long last_write_data;

void setup()
{
 ..... toute le reste et on finit par :
  last_write_data = millis() - PERIOD_WRITE_DATA;
}

void loop(){ // debut de la fonction loop()

  // On purge l'arrivée de caractères, retour de COSM (pour debug)
  if (client.available()) {
    while( client.available() )
      Serial.print(client.read() );
  }

  // Si la communication a été coupée, on ferme le client et on indique lastConnected = false;
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println( (__FlashStringHelper *)PSTR("disconnecting."));
    client.stop();
    lastConnected = false;
  }

  // Si et seulement si PERIOD_WRITE_DATA s'est écoulé depuis la dernière fois, on exécute la fonction d'écriture SD et l'envoi sur COSM
  // Sinon, on recommence loop
  if ( (millis()-last_write_data) > PERIOD_WRITE_DATA )
  {
    last_write_data = millis();

    //---- crée fichier en écriture --- 
    file = SD.open("data.txt", FILE_WRITE); // ouvre le fichier en écriture
    // NB : le fichier est créé si il n'existe pas !

    //---- test si fichier dispo en écriture 
    if (!file) { // si fichier pas dispo 
      Serial.println( (__FlashStringHelper *)PSTR("Erreur ouverture fichier !"));
    } // fin if
    else { // si le fichier existe et est ouvert 
      Serial.println( (__FlashStringHelper *)PSTR("Fichier pret pour ecriture !"));
      //----- Ecriture dans le fichier au format CSV ----- 
      Serial.println( (__FlashStringHelper *)PSTR("Enregistrement en cours :"));
      // valeur deuxieme champ
      file.print(comptageImpulsion);
      file.print(';'); 
      // valeur quatrieme champ
      file.print(millis()), file.print(';');
      // le dernier champ doit se terminer par un saut de ligne +++
      if( now() != prevDisplay) //update the display only if the time has changed
      {
        prevDisplay = now();
        digitalClockDisplay();  
      }  
      file.close(); // ferme le fichier
      Serial.println( (__FlashStringHelper *)PSTR("Fin enregistrement !"));  
      Serial.println( (__FlashStringHelper *)PSTR("Fermeture fichier !")); 

      // cosm
      // read the analog sensor:
      int sensorReading = comptageImpulsion ;   

      // A chaque fois qu'on écrit dans le fichier, on envoi aussi sur COSM.
      // La gestion du délai est déjà fait plus haut
      sendData(sensorReading);
      // store the state of the connection for next time through
      // the loop:
      lastConnected = client.connected();
    } // fin else
  }

} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin

A coté de cela, tu peux encore gagner un peu de code par-ci par -là :

#define localPort 8888      // local port to listen for UDP packets

Toute constante gagne à être un #define plutot qu'une variable.

sendDataversion compacte :

void sendData(int thisData) {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println( (__FlashStringHelper *)PSTR("connecting..."));
    // send the HTTP PUT request:
    client.print((__FlashStringHelper *)PSTR(\
      "PUT /v2/feeds/" FEEDID ".csv HTTP/1.1\n" \
      "Host: api.cosm.com\n" \
      "X-ApiKey: " APIKEY "\n" \
      "User-Agent: " USERAGENT "\n" \
      "Content-Length: " \
      ));
    // calculate the length of the sensor reading in bytes:
    // 8 bytes for "sensor1," + number of digits of the data:
    int thisLength = 8 + getLength(thisData);
    client.println(thisLength);

    // last pieces of the HTTP PUT request:
    client.print((__FlashStringHelper *)PSTR(\
      "Content-Type: text/csv\n" \
      "Connection: close\n" \
      "\n" \
      ));

    // here's the actual content of the PUT request:
    client.print( (__FlashStringHelper *)PSTR("sensor2,") );
    client.println(thisData);

  } 
  else {
    // if you couldn't make a connection:
    Serial.println( (__FlashStringHelper *)PSTR("connection failed"));
    Serial.println();
    Serial.println( (__FlashStringHelper *)PSTR("disconnecting."));
    client.stop();
  }
  // note the time that the connection was made or attempted:
  //lastConnectionTime = millis();
}

Attention, il faut que FEEDID soit une chaine et pas un nombre :
#define FEEDID "99999"
Le code si dessus est basé sur le fait que
"XXXX" "YYYY" "ZZZZ"
est automatiquement convertit par le compilateur en
"XXXXYYYYYZZZZ"
En ajoutant "\n" pour le retour chariot.
Tu obtient une chaîne plus longue qui est la somme de toutes le petites chaines mais tu n'a plus qu'un seul appel à la fonction print();
Attention, comme PSTR() est une macro (#define) il faut impérativement le symbole \ suivit de rien du tout (retour à la ligne immédiat) qui indique que la ligne de code se poursuit à la ligne de texte suivante.

ainsi :

    client.print((__FlashStringHelper *)PSTR(\
      "PUT /v2/feeds/" FEEDID ".csv HTTP/1.1\n" \
      "Host: api.cosm.com\n" \
      "X-ApiKey: " APIKEY "\n" \
      "User-Agent: " USERAGENT "\n" \
      "Content-Length: " \
      ));

est vu par le compilateur comme :

    client.print((__FlashStringHelper *)PSTR( "PUT /v2/feeds/" FEEDID ".csv HTTP/1.1\n" "Host: api.cosm.com\n" "X-ApiKey: " APIKEY "\n" "User-Agent: " USERAGENT "\n" "Content-Length: " )); /code]

Et se compile correctement alors que sans les \ tu auras une erreur de compil
Parce qu'une substitution de macro doit se faire sur une seule "ligne de code"

Bref, j'obtient à l'exécution cela :
[code]Initialisation de la SD card...
Initialisation reussie !
Repertoire racine ouvert !
Fichier pret pour ecriture !
Fin enregistrement !
Fermeture fichier !
Fichier pret pour ecriture !
Enregistrement en cours :
Fin enregistrement !
Fermeture fichier !
connecting...
72848480474946493...(plein de chiffres).....0131032
disconnecting.
--------------------------------------------------->>>>> ( pause de 120 secondes ) <<<<<<
Fichier pret pour ecriture !
Enregistrement en cours :
Fin enregistrement !
Fermeture fichier !
connecting...
72848480474946493...(plein de chiffres).....0131032
disconnecting.
--------------------------------------------------->>>>> ( pause de 120 secondes ) <<<<<<
etc...

[/code]

Bonjour ,
Nouveau sur le forum arduino , je cherche a modifier un fichier txt sur carte SD avec arduino et librairie SD .

En fait j'aimerai par exemple modifier la 5 eme ligne du fichier data.txt qie en comporterai 10 !

AUriez vous un exemple de code .....

Merci d'avance , j'ai questionné google tout ce we et j ai rien trouvé .

Merci

Jean Luc
jlpic@wanadoo.fr

Bonjour Jean-Luc
Je ne pense pas que ta question ai un rapport avec la question de PITP2.
Merci d'ouvrir un nouveau sujet

Merci Barbudor
j'ai modifié le code comme tu l'as indiqué et cela fonctionne super bien !
Respect ! :slight_smile:

En effet j'avais fait des copier coller dans tous les sens à partir d'autres exemples ....

Maintenant il ne me reste plus qu'à comprendre pourquoi lorsque je retire le réseau pendant un petit moment puis que je le reconnecte cela ne repart pas correctement ... même chose lorsque je retire la carte SD puis que je la remets.
Cela fonctionne pourtant avec les fonctions prises séparément.

après quelques tests plus rien n'est inscrit sur la carte SD lorsque je retire le carte SD meme 2 secondes et même si je ne suis pas dans la phase d'ecriture. => reset obligatoire

l'envoie se fait bien vers cosm si l'on retire le cable reseau puis on le remet.
Par contre si la phase d'initialisation ne s'est pas bien passée (cable reseau debranché par exemple) l'arduino n'essaie plus d'etablir une nouvelle connexion ... surement parceque l'intialisation se passe dans la partie setup.

Je vais essayer de tester dans la partie loop si la connexion existe et sinon relancer la procédure d'initialisation de la connexion ...

Pour la carte SD et bien je n'ai pas d'idée ..

PITP2:
après quelques tests plus rien n'est inscrit sur la carte SD lorsque je retire le carte SD meme 2 secondes et même si je ne suis pas dans la phase d'ecriture. => reset obligatoire

je ne connais pas le protocole de gestion d'une carte SD en mode SPI mais je sais qu'il y a 2 modes de fonctionnement de l'interface SD :

  • En SPI
  • dans un autre mode pas possible pour l'Arduino mais utilisé plutôt parles PC et autres équipements plus performants

Il est possible que lors du SD.begin quelque chose soit fait afin de sire à la carte SD de passer la dans le mode SPI.
Quand tu retires la carte, tu la reset.

Malheureusement sur les shields SD ou Ethernet+SD le signal d'insertion/extraction de la carte SD (qui est pourtant souvent disponible sur le connecteur) n'est jamais cablé quelque part. Donc on ne peut pas savoir que la carte a été enlevée ou remise.
Dommage.

Si c'est important pour toi de pouvoir enlever la carte en fonctionnement, 2 solutions :

  • Brutale : tu refait un SD.begin a chaque fois que tu veux accéder à la carte
  • Tu prévoit un interrupteur que l'utilisateur doit changer pour demander à enlever la carte. Si ton soft détecte ce signal, il n'effectue pas les accès à la SD. Quand l'interrupteur revient en place, il refait un SD.begin. Eventuellement prévoir un retour vers l'utilisateur genre allumé une led verte quand tu as bien pris en compte la demande et que tout accès en cours est terminé.

l'envoie se fait bien vers cosm si l'on retire le cable reseau puis on le remet.
Par contre si la phase d'initialisation ne s'est pas bien passée (cable reseau debranché par exemple) l'arduino n'essaie plus d'etablir une nouvelle connexion ... surement parceque l'intialisation se passe dans la partie setup.

Je vais essayer de tester dans la partie loop si la connexion existe et sinon relancer la procédure d'initialisation de la connexion ...

Peut être le même problème : refaire un Ethernet.begin() après une déconnexion ?
Malheureusement, je ne vois pas de moyen de tester l'état du cable (link status up/down).
La solution la plus simple semble de relier la pin qui pilote la LED LINK à une entrée de l'Arduino et de tester ce signal.

Attention a ne pas confondre la connexion du câble avec la connexion du EthernetClient.