Lecture de fichiers CSV sur SD

Bonjour

j'ai créé une table Excel reprenant sous 4 colonnes les prénoms, noms, jour et mois d'anniversaire de personnes et je les ai sauvés en format .csv sur une carte SD

Je voudrais à l'aide d'un Arduino nano les récupérer individuellement afin de pouvoir les traiter

J'ai câblé le tout et réussi ma 1ere extraction sur une seule entrée en spécifiant combien de caractères comprenait chacun des champs

Mais comme la liste comprendra des prénoms et des noms avec un nombre de caractères différents, comment peut-on faire pour que l'extraction en tienne compte automatiquement?

J'utilise la bibliothèque SD.h

Bonjour,
sachant que le fichier csv contienne des points virgules tu peux lire le fichier en s'arretant à chaque ';' recuperer le contenu

Tu veux dire qu'à chaque lecture d'un caractère, il suffit de le tester jusqu'à ce que l'on rencontre le ";" ?

oui

De façon pratique, est-ce que je me trompe si je vois les choses ainsi ? :

  1. avec File.seek(pos) , File.read() et pos++ je récupère chaque caractère
  2. je le teste chaque fois pour voir si ce n'est pas un ";"
  3. si ça n'en est pas un je l'ajoute au mot que je crée .. si ç'est lui, je saute une position et je recommence pour le champ suivant

C'est le principe d'un fichier CSV (Comma Separated Value, valeur séparées par une virgule). En français, on utilise plutôt le point-virgule. Mais, de toute façon, Excel permet d'utiliser un peu ce que l'on veut comme séparateur.

Pourquoi ce code ne me donne rien en sortie si ce n'est ceci
je lis pourtant chaque caractère (caractere[pos]) de mon fichier .csv et je l'ajoute à la variable prenom jusqu'à ce que rencontre le ";" .. ensuite j'imprime le prenom complet

#include <SD.h>
#include <SPI.h>
/* Broche CS de la carte SD */
const byte SDCARD_CS_PIN = 10; // TODO A remplacer suivant votre shield SD

void setup()
{
  Serial.begin(9600);
  
  /* Initialisation du port SPI */
  pinMode(10, OUTPUT); // Arduino Nano

  // Déclaration des tableaux
  char prenom[20];                   //20 caractères max
  char nom[20];                        //20 caracteres ma
  char jour[2];                          // 2 chiffres
  char mois[2];                       // 2 chiffres
  String (caractere); // caractère lu
  int pos = 0; // variable utilisée pour déplacer le curseur dans le fichier

  // Initialisation de la carte SD
  // -----------------------------

  Serial.print(F("Init SD card... "));
  if (!SD.begin(SDCARD_CS_PIN)) 
  {
    Serial.println(F("FAIL"));
    for (;;); //  appui sur bouton RESET
  }
  Serial.println(F("OK"));

  // Test existence du fichier anniv.csv sur la care SD (oui = "trouvé" non = "introuvable"
  // --------------------------------------------------
  if (SD.exists("anniv.csv")) 
  {
    Serial.println(F("Fichier anniv.csv trouvé"));
  } else {
    Serial.println(F("Fichier anniv.csv introuvable"));
  }

  //test ouverture fichier anniv.csv
  //--------------------------------
  File ANNIVFile = SD.open("anniv.csv"); // si fichier "anniversaires" existe sur le SD il s'ouvre
  if (!ANNIVFile) {
    // Erreur d'ouverture du fichier
    Serial.println(F("Impossible d'ouvrir le fichier anniv.csv"));
    for (;;); // Attend appui sur bouton RESET
  }
  

    // lecture prénoms dans fichier "anniversaires.csv) stocké sur SD
    //--------------------------------------------------------------   
while (caractere[pos] != ";")
      {
      ANNIVFile.seek(pos);                          // La variable pos permet, en l'incrémentant, d'avancer le curseur dans le fichier        
      caractere[pos] = ANNIVFile.read();               // Lire un caractère et le stocker dans caractère[pos]                                    
      strcat (prenom,caractere[pos]);                   // ajoute caractère à l'extrémité de prenom
      pos ++;   
      }
Serial.println(prenom);            
  }


  void loop ()
  {
  }

Essaie ceci.
(code non testé)

    // lecture prénoms dans fichier "anniversaires.csv) stocké sur SD
    //--------------------------------------------------------------   
pos = 0;
char carlu;
do{
    carlu = ANNIVFile.read();   // essaie de lire un caractère
    if(carlu != -1){            // si un caractère est lu
        prenom[pos++] = carlu;  // ajoute le caractère dans prenom
        prenom[pos] = 0;        // termine la chaine
    }
} while(carlu != ';' && carlu != -1 && pos < 18); // tant que les lectures sont valides et que l'on a pas lu le terminateur
Serial.println(prenom);

Bonjour HttpClient - Arduino Reference

Pourrais-tu mettre en ligne, un exemple de fichier?

Cordialement
jpbbricole

Bonsoir jo6466

Voilà une méthode de lecture sur carte SD avec la méthode csvFile.readStringUntil('\n'), elle permet de lire ton fichier ligne par ligne.
Dans mon exemple, le programme compte le nombre de lignes dans le fichier (csvCompterLignes) et lire, en affichant, chaque ligne du fichier (csvLireFichier)
Maintenant, que veux tu faire de ces lignes, faire des recherches ou mettre ces lignes dans un tableau, veux tu pouvoir introduire des critères de recherche?

Le code:

//-- Init SD
#include <SD.h>     // SD library
#include <SPI.h>
const int  iniSDcardCs = 10;     // Set the chip select line to whatever you use (10 doesnt conflict with the library)

char *csvFileName = "anniv.csv";
File csvFile;
int csvNombreDeLignes = 0;


void setup()
{
	Serial.begin(115200);
	Serial.println("Read ini file");

	Serial.print("Initializing SD card...");
	if (!SD.begin(iniSDcardCs))
	{
		Serial.println("failed!");
		return;
	}
	Serial.println("OK!");
	delay(1000);

	csvNombreDeLignes = csvCompterLignes(csvFileName, '\n');
	Serial.print(F("\nLe fichier "));
	Serial.print(csvFileName);
	Serial.println(" contient " + String(csvNombreDeLignes) + " ligne(s)");

	Serial.println(F("\nContenu du fichier"));
	Serial.println(F("------------------"));
	csvLireFichier(csvFileName);
}

void loop()
{
}

//------------------------------------- Lecture du fichier avec recherche de Prénom et Nom
void csvLireFichier(char *fichierNom)
{
	String csvLine;
	String retVal = "?";
	
	csvFile = SD.open(fichierNom, FILE_READ);
	if (csvFile)
	{
		while (csvFile.available())
		{
			String csvLine = csvFile.readStringUntil('\n');
			csvLine.trim();     // Pour nettoyer les données (sprrrimer espaces,, \r|
			Serial.println(csvLine);
		}
		csvFile.close();
	}
	else
	{
		Serial.print("error opening ");
		Serial.println(csvFileName);
	}
}

//------------------------------------- Compter les lignes du fichier
int csvCompterLignes(char *fichierNom, char ligneTerminaison)
{
	char caractereLu;
	int lignesNombre = 0;
	
	csvFile = SD.open(fichierNom, FILE_READ);
	if (csvFile)
	{
		while (csvFile.available())
		{
			caractereLu = csvFile.read();

			if(caractereLu == '\n') 
			{
				lignesNombre ++;
			}
		}
		csvFile.close();
	}
	else
	{
		Serial.print("error opening ");
		Serial.println(csvFileName);
	}
	
	return lignesNombre;
}

Cordialement
jpbbricole

Mon but est de permettre d'encoder facilement des dates de fêtes et anniversaires dans exel et de les utiliser ensuite dans Arduino pour créer des alarmes dans une horloge-calendrier (programme terminé)

Je viens d'essayer ton sketch et voici ce que j'obtiens

Je voudrais vous transmettre mon fichier anniv.csv mais je ne sais pas comment faire?

Comment vous le transmettre? ... joindre un fichier ne fonctionne pas

voici ce que ton sketch donne ... ne suffit-il pas que je fasse la même chose avec les noms , jour et mois en ne réinitialisant pas le compteur (pos) ?

capture 2022-07-15 à 21.01.16

sur mon fichier exel suivant :
capture 2022-07-15 à 21.00.25

Bonsoir jo6466

Il faut passer ton moniteur série de 9600 à 115200 baud.

Il faut le zipper.

Connais tu le nombre maximum d'entrées que tu penses avoir?

Cordialement
jpbbricole

Regarde bien le code.
pos ne sert pas d'index dans le fichier mais d'index dans la chaine que tu remplis. Il faut donc le remettre à 0 pour chaque nouvelle acquisition.
Il n'est généralement pas nécessaire d'avoir un index dans le fichier car à chaque lecture le pointeur avance tout seul.
Il faudra ajouter une condition de sortie du while car le dernier champ d'une ligne dans un fichier csv ne se termine pas avec un point-virgule mais un retour à la ligne.

Juste ... j'avais pas vu ... voici ce que j'obtiens avec 9600

capture 2022-07-15 à 23.26.40

Mais ce même résultat, je l'avais déjà obtenu beaucoup plus simplement

  // lecture prénoms dans fichier "anniversaires.csv) stocké sur SD
  // read from the file until there's nothing else in it
  //--------------------------------------------------------------   
  
  while (ANNIVFile.available()) {

    Serial.write(ANNIVFile.read());  // serial.write permet d'envoyer dans le moniteur des caractéres
  
  }
  
  
  // close the file:
  //---------------
  
  ANNIVFile.close();
  }

Mon fichier anniv.csv à 2 lignes pour essais
anniv.csv.zip (579 Octets)

Le nombre de lignes pourrait atteindre les 50 lignes mais l'idéal serait qu'on ne doive pas avoir à le connaitre

Non.
Tu te contentais de copier le contenu du fichier sans interpréter le contenu.
Avec le morceau de code que je t'ai donné tu isoles chaque membre de la ligne. Après c'est à toi d'en faire ce que tu veux.

Bojour jo6466

Oui, mais entre simplement afficher des donnés et ou les traiter il y a du taf!

Pour passer de:

Contenu du fichier
bubu;toto;3;10joseph;bozzer;7;10

à;

Contenu du fichier
bubu;toto;3;10
joseph;bozzer;7;10

il faut changer cette ligne

String csvLine = csvFile.readStringUntil('\n');
// en
String csvLine = csvFile.readStringUntil('\r');

C'est vrai, que de toute façon, si tu veux tester des dates, il ne faut lire le fichier qu'une fois par jour, nul n'est nécessaire de connaître le nombre d'enregistrements.

Cordialement
jpbbricole

jpbbricole ...

Ta solution fonctionne parfaitement maintenant pour mon besoin ... en fait cette banque de données ne sera lue qu'une seule fois dans le Setup uniquement lorsque je voudrais qu'un changement du fichier anniv.csv soit pris en compte

Il me reste maintenant à réfléchir à une méthode pour :

  1. comparer journalièrement le jour et le mois de tous les enregistrements à ceux de mon calendrier Arduino et d'en extraire la ligne correspondante
  2. afficher une fenêtre avec "demain anniversaire de Joseph Bozzer .. il a 70ans"

capture 2022-07-16 à 17.15.45