Plus de données ! Mesurer la température et stocker les données sur une carte SD

Posted on sam. 16 septembre 2023 in Datalogging, Arduino

L’instant « logger »

Eh oui, dans « datalogger », il y a « logger », soit enregistreur. Maintenant que tout fonctionne comme on le veut d’un point de vue mise en veille, réveil, mesure, récupération et formatage de l’heure, il est temps de sauvegarder nos données pour une exploitation ultérieure. Pour faire simple d’un point de vue stockage et récupération, on va les enregistrer sur une carte micro-SD, en utilisant la lib SD. Cette lib présente des limitations, par exemple sur la longueur du nom de fichier, qui doit suivre la norme 8.3 (8 caractères, un point, 3 caractères d’extension).

Le formattage de la date

Pour le moment, on formatte la date comme des bourrins, à grands coups de Serial.print. Outre le fait que ça consomme quand même un peu de mémoire, ça ne nous permet pas d’enregistrer la date au format texte dans une variable pour ensuite l’intégrer dans un fichier.

Cette fois, on va travailler directement avec des char pour gagner de l’espace en mémoire.

char* format_datetime(DateTime dt) {
  char* datebuf = malloc(20);
  sprintf(datebuf, "%04d-%02d-%02d %02d:%02d:%02d", dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute(), dt.second());
  return(datebuf);
}

// L’utilisation se fait dans une autre fonction

On commence par allouer un tableau de char de 20 caractères de long. En effet, une date au format YYYY-MM-DD hh:mm:ss, ça occupe 19 caractères, et il en faut un dernier, le \0, qui vient annoncer la fin de la chaîne de caractères (c’est ainsi que les chaînes de caractères fonctionnent en C). On ne l’explicite nulle part dans la fonction, ce \0, mais il est bien là.

Ensuite, on utilise sprintf, qui a un comportement similaire à printf, mais enregistre le résultat dans une variable (ici, datebuf, le premier argument de la fonction) au lieu de l’afficher à l’écran. Dans le second argument (le "%04d…), à chaque fois que vous voyez un %XXd, cela signifie que l’on demande de formater la variable correspondante avec XX chiffres (le d dénote un nombre, digit en anglais). Le reste de l’appel à la fonction contient autant d’arguments qu’il y a de nombres à formatter (6 ici), et les substitutions entre les %XXd et les nombres sont effectués dans l’ordre où ils apparaissent.

On peut ensuite retourner le résultat, une date formatée comme on l’a demandé.

La fonction pour enregistrer

bool to_sd_card(DateTime dt, uint16_t displacement_micrometers) {
  bool result;
  File datafile; // On initialise notre objet fichier, pour une ré-utilisation plus tard
  if(!SD.begin(4)) { // Initialisation de la carte SD *via* connexion SPI
    Serial.println("Could not init SD card");
    result = false;
  }

  // Une fois le fichier ouvert, on peut y écrire les données.
  // Pour le moment, on les écrit en ASCII. Pas le plus optimisé, mais c’est simple.
  datafile = SD.open(filename, FILE_WRITE);
  if(datafile) {
    char* formatted_dt = format_datetime(dt);
    datafile.print(formatted_dt);
    datafile.print(",");
    datafile.println(displacement_micrometers);
    free(formatted_dt);
    datafile.close();
    result = true;
  } else {
    Serial.println("Cannot open data file");
    result = false;
  }
  return(result);
}

Note : la fonction retourne un bool : true si l’écriture s’est bien passée, false sinon. Cette valeur peut ensuite être réutilisée dans le code principal, par exemple pour faire clignoter une LED si on rencontre un problème lors de l’écriture.