Créer un fichier sur une carte SD portant le nom d'un char[]

Bonjour à tous,

Voilà plusieurs jours que je m'acharne sur un point d'un programme qui parait banale mais qui pourtant me rend fou ^^'
J'ai un scanner de code barre(agit comme un clavier) connecté en USB à un Sheild USB qui est gérer par la librairie USB Host Sheild 2.0. Ce dernier envoie les données à un Arduino nano qui est lui même connecté a une carte SD.
Mon programme consiste à:
-Le scanner de code barre lit un code barre de 6 caractères(chiffres) et les envoie un par un à l'arduino
-L'arduino crée une string avec les caractères et l'affiche sur le serial quand il à tout lue
-L'arduino crée un fichier sur la carte SD portant le nom de la chaine de caractères et c'est ici où ça coince!
En effet, il n'arrive pas à créer de fichier mais affiche pourtant bien la chaine de caractère sur le serial
J'en convient, le code est un petit peu biscornue mais c'est la bibliothèque USB qui est comme ça. Ce qu'il faut surtout regarder, c'est le void KbdRptParser::OnKeyPressed(uint8_t key) ligne 35

#include <hidboot.h> 
#include <hiduniversal.h>
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <Usb.h>


#include <SPI.h>
#include <SD.h>
File membre;

uint8_t curseur = 0;
char code[]="000000.txt";
 
USB     Usb;
USBHub     Hub(&Usb); 
HIDUniversal      Hid(&Usb); 

 
class KbdRptParser : public KeyboardReportParser
{
        void PrintKey(uint8_t mod, uint8_t key);             // Add this line to print character in ASCII
protected:
  virtual void OnKeyDown  (uint8_t mod, uint8_t key);
  virtual void OnKeyPressed(uint8_t key);
};
 
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)  
{
    uint8_t c = OemToAscii(mod, key);
 
    if (c)
        OnKeyPressed(c);
}
 
/* quand un symbol arrive : */
void KbdRptParser::OnKeyPressed(uint8_t key)  
{
 
  if(curseur <= 5){
    code[curseur]=(char)key;//ici,(char)key est le caractère reçue
    curseur++;
  }
  else if(curseur == 6){
    curseur=0;
    Serial.println(code);
    membre = SD.open(code, FILE_WRITE);
    membre.close();
    if(SD.exists(code)) {
      Serial.println(F("fichier crée"));
    } 
    else {
      Serial.println(F("fichier non crée"));
    }
    
  }
  
};
 
KbdRptParser Prs;
 
void setup()
{
    Serial.begin( 115200 );
    pinMode(9, OUTPUT); 
    Serial.println(F("Start"));
    SD.begin(9);
    if (Usb.Init() == -1) {
        Serial.println(F("OSC did not start."));
    }
 
    delay( 200 );
 
    Hid.SetReportParser(0, (HIDReportParser*)&Prs);
    delay( 200 );
}
 
void loop()
{
  Usb.Task();
  
}

Si quelqu'un peut m'éclairer ce serait super car depuis 3 jours, je racle les fonds d'internet et tourne mon code dans tout les sens pour essayer de trouver une solution!
J’espère avoir été compréhensible ^^

Merci beaucoup d'avance!

PS : C'est la première fois que j’écris sur le forum mais je l'ai beaucoup lue :smiley:

C'est normal le ; après l'accolade finale de void KbdRptParser::OnKeyPressed(uint8_t key) ?

votre variable cString code contient "[color=red]000000[/color].txt"

Vous replacez donc les caratactère à l'indice 0...5 par ce que vous recevez mais vous avez un else

    if(curseur <= 5){
    code[curseur]=(char)key;//ici,(char)key est le caractère reçue
    curseur++;
  }
  else if(curseur == 6){
     ...

qui fait que le code ne se déclenchera qu'après avoir reçu un autre caractère. Hors quand vous avez fini de remplacer le dernier '0', votre curseur++ met la variable à 6 et c'est sans doute là qu'il faudrait écrire non?

si vous enlevez le else vous rentrez immédiatement dans la seconde partie

(bien sûr ça devrait déclencher si le lecteur USB envoie plus de caractères mais ça risque aussi de mettre le bazar car vous recommencez ensuite à remplir votre buffer)

--> vérifiez exactement tous les codes reçus lors du scan
--> virez le else
--> ignorez les caractères en trop en attente de la fin d'un scan


et le ; ne sert à rien :slight_smile:

Bonjour J-M-L,
tout d'abord, merci de votre réponse.
Mon programme avec le else fonctionne très bien, en effet, il me retourne les bonnes valeurs et c'est ça qui me rend fou car sur le serial tout est OK, il affiche la bonne chaîne de caractères en ASCII mais il ne veut pas créer de dossier nommé avec cette dernière !

Start
OK
000000.txt
non membre
123456.txt
non membre
011896.txt
non membre
011679.txt
non membre

Je me demande donc ce qui ne vas pas dans ma chaîne, j'ai effectué un test avec le programme exemple "Files" de la librairie SD

#include <SPI.h>
#include <SD.h>

File membre;
char code[]="000000.txt";
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  if (!SD.begin(9)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  if (SD.exists(code)) {
    Serial.println("000000.txt exists.");
  } else {
    Serial.println("000000.txt doesn't exist.");
  }

  // open a new file and immediately close it:
  Serial.println("Creating 000000.txt...");
  membre = SD.open(code, FILE_WRITE);
  membre.close();

  // Check to see if the file exists:
  if (SD.exists(code)) {
    Serial.println("000000.txt exists.");
  } else {
    Serial.println("000000.txt doesn't exist.");
  }
}

void loop() {
  // nothing happens after setup finishes.
}

et il me retourne :

Initializing SD card...initialization done.
000000.txt doesn't exist.
Creating 000000.txt...
000000.txt exists.

Sur la carte SD connectée à mon PC je peux clairement voir le fichier ! je me demande donc ce qui ne fonctionne pas...
Les caractères ASCII retournés par le sheild USB sont ils différents des autres ? Car même avec un fichier nommé "123456.txt" dans la carte SD n'est pas reconnue par le code comme un fichier existant...
J'ai aussi essayé en fermant la chaîne de caractère avec la commande

code[11]= '\0';

mais rien n'y fait.

En espérant que vous pourrez m’éclaircir :smiley:

Ton code a du changer car le contenu de la console que tu nous donnes dans ton message précédent ne correspond pas au code que tu as fourni. Pas facile d'aider dans ces conditions.

Poste la version courante du code, celle qui correspond à ce que tu as copié dans ton message.

oui postez le code

Bonjour,
désolé pour le code, il reste strictement le même, j'ai juste modifié ce que l'arduino renvoie au serial et je m'en excuse.
j'ai traduis mon post sur le forum anglophone et quelqu'un m'a fait une remarque interessante :
Mon sheild USB est en SPI tout comme ma carte SD et mon programme s’exécute durant une communication avec l'USB donc impossible de communiquer avec la carte SD! Il m'a donc proposé de rajouter ces lignes pour "faire taire" l'USB:
(ici csUSB est le CS de l'USb soit 10)

void KbdRptParser::OnKeyPressed(uint8_t key) 
{
 
  if(curseur <= 5){
    code[curseur]=(char)key;//here,(char)key is the recieved character
    curseur++;
  }
  else if(curseur == 6){
    curseur=0;
    Serial.println(code);

    digitalWrite(csUSB, HIGH); // Add this here
    membre = SD.open(code, FILE_WRITE);
    membre.close();
    if(SD.exists(code)) {
      Serial.println(F("file created"));
    }
    else {
      Serial.println(F("file can't be creat"));
    }
    digitalWrite(csUSB, LOW); // Add this here
   
  }
 
};

C'est théoriquement un bonne idée mais malheureusement, ça n'a pas fonctionné j'ai donc essayé avec ceinture et bretelle de cette manière :

#include <hidboot.h>                           
#include <hiduniversal.h>                
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <Usb.h>


#include <SPI.h>
#include <SD.h>
File membre;

uint8_t curseur = 0;
char code[]="000000.txt";
 
USB     Usb;
USBHub     Hub(&Usb);                                          
HIDUniversal      Hid(&Usb);                                  

 
class KbdRptParser : public KeyboardReportParser
{
        void PrintKey(uint8_t mod, uint8_t key);             
protected:
  virtual void OnKeyDown  (uint8_t mod, uint8_t key);
  virtual void OnKeyPressed(uint8_t key);
};
void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
{
  MODIFIERKEYS mod;
  *((uint8_t*)&mod) = m;
  PrintHex<uint8_t>(key, 0x80);
};
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)  
{
    uint8_t c = OemToAscii(mod, key);
    if (c)
        OnKeyPressed(c);
}
 
/* what to do when symbol arrives */
void KbdRptParser::OnKeyPressed(uint8_t key)  
{
  if(curseur <= 5){
    code[curseur]=(char)key;
    curseur++;
  }
  else if(curseur == 6){
    curseur=0;
    Serial.println(code);
    digitalWrite(10, HIGH); // Add this here
    digitalWrite(9, LOW); // Add this here
    membre = SD.open(code, FILE_WRITE);
    membre.close();
    if(SD.exists(code)) {
      Serial.println(F("fichier crée"));
    } 
    else {
      Serial.println(F("fichier non crée"));
    }
    digitalWrite(9, HIGH); // Add this here
    digitalWrite(10, LOW); // Add this here
  }
  
}
 
KbdRptParser Prs;
 
void setup()
{
    Serial.begin( 115200 );
    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT);
    Serial.println(F("Start"));
    SD.begin(9);
    Serial.println(F("OK"));
  
    if (Usb.Init() == -1) {
        Serial.println(F("OSC did not start."));
    }
 
    delay( 200 );
 
    Hid.SetReportParser(0, (HIDReportParser*)&Prs);       
    delay( 200 );
}
 
void loop()
{
  Usb.Task();
  
}

mais toujours rien... il m'a aussi proposé de sortir ma fonction d'écriture sur la carte de l'USB.task
j'ai donc essayé de cette manière (testé avec et sans les "digitalWrite")

#include <hidboot.h>                          
#include <hiduniversal.h>                 
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <Usb.h>


#include <SPI.h>
#include <SD.h>
File membre;

uint8_t curseur = 0;
char code[]="000000.txt";
bool codeOK = false;
USB     Usb;
USBHub     Hub(&Usb);                                         
HIDUniversal      Hid(&Usb);                                  

 
class KbdRptParser : public KeyboardReportParser
{
        void PrintKey(uint8_t mod, uint8_t key);             
protected:
  virtual void OnKeyDown  (uint8_t mod, uint8_t key);
  virtual void OnKeyPressed(uint8_t key);
};
void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
{
  MODIFIERKEYS mod;
  *((uint8_t*)&mod) = m;
  PrintHex<uint8_t>(key, 0x80);
};
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)  
{
    uint8_t c = OemToAscii(mod, key);
    if (c)
        OnKeyPressed(c);
}
 
/* what to do when symbol arrives */
void KbdRptParser::OnKeyPressed(uint8_t key)  
{
  if(curseur <= 5){
    code[curseur]=(char)key;
    curseur++;
  }
  else if( curseur == 6){
    codeOK = true;
    curseur = 0;
    }

}
 
KbdRptParser Prs;
 
void setup()
{
    Serial.begin( 115200 );
    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT); 
    Serial.println(F("Start"));
    SD.begin(9);
    Serial.println(F("OK"));
  
    if (Usb.Init() == -1) {
        Serial.println(F("OSC did not start."));
    }
 
    delay( 200 );
 
    Hid.SetReportParser(0, (HIDReportParser*)&Prs);        
    delay( 200 );
}
 
void loop()
{
  Usb.Task();
   if(codeOK == true){
    Serial.println(code);
    digitalWrite(10, HIGH); // Add this here
    digitalWrite(9, LOW);
    membre = SD.open(code, FILE_WRITE);
    membre.close();
    if(SD.exists(code)) {
      Serial.println(F("fichier crée"));
    } 
    else {
      Serial.println(F("fichier non crée"));
    }
    digitalWrite(10, LOW); // Add this here
    digitalWrite(9, HIGH);
    codeOK = false;
  }

Mais toujours rien...
Je pense que c'est la source du problème, j'en viens donc à vous pour m'aider si vous avez des idées ^^
Je continue d’effectuer des recherches de mon coté et je vous tiens au courant :wink:
Merci

Salut ,

Dans un premier temps , je me creerai un mini projet similaire au votre mais qui permettrai de lire un fichier sur la carte SD .

ca mettrai deja en evidence la ou ca coince , sans tout le reste du code a gerer , qui vous induit en erreur sur le probleme a mettre en evidence .

ensuite avec le meme mini projet , je gererai l' ecriture d' un fichier simple , qui a coup sur a ce niveau là vous permettra de trouver la ou ca coince .

ensuite retransposer le tout dans votre projet principal a la main .

c'est vrai que OnKeyPressed() est potentiellement appelé dans le contexte d'une interruption et d'usage du bus SPI et donc ce ne serait pas l'endroit pour gérer le fichier à cause de la contention sur les resources.

Une solution (et une meilleure architecture logicielle) serait de mettre un drapeau à vrai (true) quand vous avez reçu une scan complet d'un code et de ne plus scanner quoi que ce soit tant que ce drapeau n'est pas remis à false, chose que vous feriez dans la loop() après avoir traité la notification que quelque chose était scanné

De la sorte vous désynchronisez l'acquisition du nom de fichier de la création effective sur la carte SD.

Bonjour,

j'ai déja crée un autre projet ne mettant en action seulement la carte sd avec les fonctions que je lui demande d'effectuer mais sans le sheils USB:

Tsukay:

#include <SPI.h>

#include <SD.h>

File membre;
char code[]="000000.txt";
void setup() {
 // Open serial communications and wait for port to open:
 Serial.begin(9600);
 while (!Serial) {
   ; // wait for serial port to connect. Needed for native USB port only
 }

Serial.print("Initializing SD card...");

if (!SD.begin(9)) {
   Serial.println("initialization failed!");
   while (1);
 }
 Serial.println("initialization done.");

if (SD.exists(code)) {
   Serial.println("000000.txt exists.");
 } else {
   Serial.println("000000.txt doesn't exist.");
 }

// open a new file and immediately close it:
 Serial.println("Creating 000000.txt...");
 membre = SD.open(code, FILE_WRITE);
 membre.close();

// Check to see if the file exists:
 if (SD.exists(code)) {
   Serial.println("000000.txt exists.");
 } else {
   Serial.println("000000.txt doesn't exist.");
 }
}

void loop() {
 // nothing happens after setup finishes.
}




et il me retourne :



Initializing SD card...initialization done.
000000.txt doesn't exist.
Creating 000000.txt...
000000.txt exists.

ce qui soutient que le problème viens de la communication avec le sheild USB.
En effet même avec un fichier préexistant, il est incapable de le lire dans mon programme

Je viens d'essayer avec un flag mais toujours pas...

#include <hidboot.h>                           
#include <hiduniversal.h>                  
#include <usbhub.h>
#include <avr/pgmspace.h>
#include <Usb.h>


#include <SPI.h>
#include <SD.h>
File membre;

uint8_t curseur = 0;
char code[]="000000.txt";
bool codeOK = false;
bool scan = true;
USB     Usb;
USBHub     Hub(&Usb);                                          
HIDUniversal      Hid(&Usb);                                  

 
class KbdRptParser : public KeyboardReportParser
{
        void PrintKey(uint8_t mod, uint8_t key);             
protected:
  virtual void OnKeyDown  (uint8_t mod, uint8_t key);
  virtual void OnKeyPressed(uint8_t key);
};
void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
{
  MODIFIERKEYS mod;
  *((uint8_t*)&mod) = m;
  PrintHex<uint8_t>(key, 0x80);
};
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)  
{
    uint8_t c = OemToAscii(mod, key);
    if (c)
        OnKeyPressed(c);
}
 
/* what to do when symbol arrives */
void KbdRptParser::OnKeyPressed(uint8_t key)  
{
  if(curseur <= 5){
    code[curseur]=(char)key;
    curseur++;
  }
  else if( curseur == 6){
    codeOK = true;
    scan = false;
    curseur = 0;
    digitalWrite(10, HIGH);
    digitalWrite(9, LOW);
    }
    //Add char to print correct number in ASCII
}
 
KbdRptParser Prs;
 
void setup()
{
    Serial.begin( 115200 );
    pinMode(9, OUTPUT);
    pinMode(10, OUTPUT); 
    Serial.println(F("Start"));
    SD.begin(9);
    Serial.println(F("OK"));
  
    if (Usb.Init() == -1) {
        Serial.println(F("OSC did not start."));
    }
 
    delay( 200 );
 
    Hid.SetReportParser(0, (HIDReportParser*)&Prs);        
    delay( 200 );
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
}
 
void loop()
{
  if(scan == true){
  Usb.Task();
  }
  if(codeOK == true){
    Serial.println(code);
    
    membre = SD.open(code, FILE_WRITE);
    membre.close();
    if(SD.exists(code)) {
      Serial.println(F("membre"));
    } 
    else {
      Serial.println(F("non membre"));
    }
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
    codeOK = false;
    scan = true;
  }
  
}

je l'ai aussi testé sans les digitalesWrite manuels mais ça ne fonctionne pas.

J'ai oullier le forum et trouver quelqu'un qui avait un problème assez similaire mais je n'ai pas bien compris comment il l'a réglé, on dirait que c'est avec le technique des digitaleWrite
je vous laisse le lien(en anglais) : Topic: How to Handle Multiple SPI Slaves With USB Host Shield on Arduino?

Quel est le chip sélect de votre SD ?

dans la doc du shield ils disent

Arduino communicates with the MAX3421E using the SPI bus (through the ICSP header). This is on digital pins 10, 11, 12, and 13 on the Uno and pins 10, 50, 51, and 52 on the Mega. On both boards, pin 10 is used to select the MAX3421E. Pins 7, 8 and 9 are used for GPX, INT and RES pins.

--> il ne faut donc pas utiliser 7,8,9,10,11,12 et 13 si vous êtes sur un UNO

Ma chip est le 9.
je viens de la changer par 2 et tout fonctionne, merci beaucoup!!!

Magique :slight_smile:

:slight_smile: