Problème avec Serial.available() et Serial.println()

Bonjour à tous !

J'ai récemment découvert "Arduino"... Et franchement c'est génial.
Je suis en BTS IG (Développeur d'applications), et j'ai un examen oral de présentation de projet Vendredi 17 :astonished: ...

En fait voila, j'ai comme projet la réalisation d'une banque électronique avec cartes RFID pour le monopoly.
J'utilise: 1 Ecran LCD I2C, 1 clavier numérique, 1 lecteur RFID Parallax et éventuellement l'EEPROM pour enregistrer une partie (Je verrais ça plus tard).

Le clavier que j'ai est tout pourri, comme j'ai pas le temps d'en trouver un qui marche avec la librairie "Keypad", j'ai décidé de remplacer le clavier par un PC...
Donc j'ai fais quelques librairies, dont "Keypad.h" (la mienne, pour l'ordi) qui ne contient que 2 fonctions.
getNum() et getStr();

getNum() se charge de récupérer le nombre de caractères disponible ( Serial.available() ), stocke la première valeur, puis x10 puis + la 2e valeur... Et ainsi de suite pour obtenir un nombre (int).
Mon problème, c'est que quand j'affiche avec Serial.print() la variable nouvellement initialisée par le retour de getNum(), j'obtiens des caractères aléatoires.
MAIS... Quand j'ai voulu débugger, j'ai ajouté dans mon Keypad.cpp, Serial.print(Serial.available()); pour vérifier si le bon nombre est détecté et j'ai aussi ajouté un print(nombre_final) dans getNum().

Alors le BUG... C'est que quand j'ajoute le print(Serial.available) ET le print(nombre_final)... Le print du "setup()/loop()" fonctionne... O_O ...

Je comprends pas. J'aurais besoin que quelqu'un m'explique ma connerie svp :slight_smile:

Je joins un zip, il contient tout les fichiers.
Il est utilisable tel quel, j'ai testé avec un Arduino Uno. Rien à brancher à part l'USB.
Le problème c'est la fonction void Keypad::getNum(void) du fichier Keypad.cpp[/i].
Si quelqu'un veut bien m'expliquer...
Merci beaucoup de votre aide :slight_smile:
Monopoly.zip (13.1 KB)

bonjour,

Je reconnais dans la manière de coder les méthodes d'un développeur d'applications pc (j'en suis moi même un).
Utiliser l'opérateur new sous arduino est (pour moi) une catastrophe (je vois ça comme ça).

Je suis sur que ton code pourrai tourner niquel dans une optique "pc" mais je suis aussi presque sur que ton problème viens de la complexité ajouter au code.

Déjà tous les truc du genre "Keypad * kpad;" puis "kpad = new Keypad(9600);" devrait être remplacer par "Keypad kpad(9600);".
Ensuite je vois des Serial.end() et des Serial.begin(xx) par plein vagons je ne serais pas étonné que une parti de ton problème vienne de là.
Autre chose sous avr-gcc les "return this->variable;" son inutile puisque déclarer dans le .h en private ou public, "return variable;" suffit.

Tu dois revoir ton code presque entièrement en gardant en tête que l'atmega328 ne contient que 2Ko de ram ! quand je vois des strcmp() en pagaille mais cheveux ce dresse !

Je ne critique pas mais si je peut te donner quelque conseils les voici:
supprime tout ces class fait juste des fonctions elle sont totalement superflus,
dans ton code il ne doit pas y avoir de Serial.end et UN seul Serial.begin, faire l'inverse c'est courir au problème,
ensuite la libraire softwareSerial est donnée avec l'ide arduino inutile de la mettre dans ton dossier fait comme avec la librairie wire.

Sans vouloir être méchant j'ai l'impression que tu a voulu en faire beaucoup trop :wink: ton projet contient 12 fichiers alors qu'en réalité codé de manière réfléchi et avec l'optique microcontrolleur il ne prendrai que 1 fichier .pde de maximum 200 lignes.

Je regarde ton code demain matin et te propose une version plus "arduino" pour que tu puisse voir :wink:
Sinon je dois dire que tu te débrouille vraiment bien en c++ :wink: tu utilise quel compilateur habituellement ?

Salut salut :slight_smile:

Tout d'abord, merci de ta réponse plutôt rapide ^^'
Je vais m'expliquer :wink:

skywodd:
Je reconnais dans la manière de coder les méthodes d'un développeur d'applications pc (j'en suis moi même un).
Utiliser l'opérateur new sous arduino est (pour moi) une catastrophe (je vois ça comme ça).

Je suis sur que ton code pourrai tourner niquel dans une optique "pc" mais je suis aussi presque sur que ton problème viens de la complexité ajouter au code.

Exactement. Comme je l'ai dis au début, et comme tu l'as remarqué, je suis à la base un dev "PC".
En fait, les 2 dernières années (BTS), j'ai appris le C et le C++ cette année en guise de "Langage Objet. J'ai découvert l'arduino il y a quelques semaines, mes réflexes PC surgissent, je n'ai pas encore les réflexes micro-contrôleurs (même si pendant 2 ans on m'a répété qu'il faut prévoir petit, niveau code et ressources).

skywodd:
Déjà tous les truc du genre "Keypad * kpad;" puis "kpad = new Keypad(9600);" devrait être remplacer par "Keypad kpad(9600);".

Je ne pensais pas que c'était si... Déconseillé :confused:

skywodd:
Ensuite je vois des Serial.end() et des Serial.begin(xx) par plein vagons je ne serais pas étonné que une parti de ton problème vienne de là.

Là... C'était parce que je voulais "utiliser" le mode série QUE quand j'en avais besoin. Pourquoi, je sais pas trop, mais encore une fois, ça doit être le réflexe "Quand tu utilise la mémoire, libère la dès que tu peux, et tout et tout", du coup pour le série, il m'a paru une bonne idée de ne m'en servir qu'au besoin. Cela dit, que mon problème vienne de là, je te crois car c'est tout à fait possible, mais je te cache pas que "logiquement", je ne vois vraiment pas le rapport, ni comment c'est possible (au fond, j'ouvre et je ferme bien non ?)... Mais bon, au moins maintenant je saurais qu'il est inutile de fermer le mode série.

skywodd:
Autre chose sous avr-gcc les "return this->variable;" son inutile puisque déclarer dans le .h en private ou public, "return variable;" suffit.

Là... C'est une habitude que j'ai pris en C++. Il m'arrive de donner le même nom à mes variables private et les variables envoyées en paramètre, j'ai donc pris l'habitude de mettre this->. C'est vraiment important ou je peux garder cette habitude ?

skywodd:
Tu dois revoir ton code presque entièrement en gardant en tête que l'atmega328 ne contient que 2Ko de ram ! quand je vois des strcmp() en pagaille mais cheveux ce dresse !

Bon... Ok, j'aurais pu faire un for() et copier les caractères? Mais je pensais que strcmp() faisait pareil ^^'

skywodd:
Je ne critique pas mais si je peut te donner quelque conseils les voici:
supprime tout ces class fait juste des fonctions elle sont totalement superflus,
dans ton code il ne doit pas y avoir de Serial.end et UN seul Serial.begin, faire l'inverse c'est courir au problème,
ensuite la libraire softwareSerial est donnée avec l'ide arduino inutile de la mettre dans ton dossier fait comme avec la librairie wire.

Dernière chose. Pour le SerialSoftware, j'avais le message d'erreur "No such file or directory". Comme mon oral est dans 3 jours, je me suis pas attardé dessus, j'ai recopié les fichiers.

skywodd:
Sans vouloir être méchant j'ai l'impression que tu a voulu en faire beaucoup trop :wink: ton projet contient 12 fichiers alors qu'en réalité codé de manière réfléchi et avec l'optique microcontrolleur il ne prendrai que 1 fichier .pde de maximum 200 lignes.

Je regarde ton code demain matin et te propose une version plus "arduino" pour que tu puisse voir :wink:
Sinon je dois dire que tu te débrouille vraiment bien en c++ :wink: tu utilise quel compilateur habituellement ?

Enfin... Aucun problèmes :wink:
Je ne suis pas assez prétentieux pour prendre tes conseils et remarques comme une attaque ou des critiques. Bon, les critiques c'est normal, je suis débutant alors c'est ce genre de remarques/reproches/critiques/discussions qui me font avancer et en apprendre plus.

Merci pour le compliment, j'utilise habituellement... Mingw, sur Windows, Mac et linux.
Je me suis rabattu sur "Qt" de Nokia pour éviter d'avoir à porter mes applis fenêtres à chaque fois...

Je vais quand même pas attendre que tu me ponde un code tout fait, je vais commencer par le corriger et je regarderais ce que tu as fais (quand tu l'auras fait)... Si tu as le temps et tout et tout.
Merci merci pour tes conseils!

--- EDIT: 14/06 ---
Finalement, j'ai testé en laissant QU'UN SEUL Serial.begin(), de retirer tout les end().
Et bizarrement... Dans ou hors de la fonction, le nombre est retourné correctement QUE si je mets "print" avant O_O'.
J'ai essayé, j'ai mis un Serial.print("Available: "), j'ai commenté le Serial.available(), et il renvoie bien le nombre. Je commente le print, et le Serial.available() renvoie 1 ...
Impensable...
Et si je commente le Serial.print("Available: "), et que j'affiche le .available(), là... Il affiche 1 et mon while( Serial.available() > 0 ) s'éxécute 2 fois... Je comprends plus T_T

Bon aller.
J'ai refais quelques tests, et pour montrer que je suis désespéré tellement les erreurs sont... Bizarres...

int Keypad::getNum(void) // Get int
{
	while (Serial.available() < 1); // Waiting for input
	for (int i=0;i<10;i++)
		Serial.println(Serial.available());

	while(1); // Aucun retour, normalement l'arduino bloque là.
	return 0;
}

J'ai réécris ma fonction comme ça.
Et voici l'output quand j'écris "765":

1
2
3
3
3
3
3
3
3
3

C'est curieux non ? :confused:

Bonjour,

Non, le résultat donné par ton code est conforme à ce que tu peux attendre de ce code.

Il sort sur la série, 10 fois le nombre d'octets contenus dans le buffer de réception.

Que veux-tu faire exactement avec getNum() ?


Stéphane

Snootlab:
Bonjour,

Non, le résultat donné par ton code est conforme à ce que tu peux attendre de ce code.

Il sort sur la série, 10 fois le nombre d'octets contenus dans le buffer de réception.

Que veux-tu faire exactement avec getNum() ?

Je veux récupérer une entrée.
Le problème (si t'as bien tout lu =P ) c'est qu'il me sort les 3 premières valeurs différentes...

C'est normal ?
(Alors que j'envoie une seule fois "765"...)

Bonjour,

Oui, c'est normal.
Dès que le premier octet arrive dans le buffer, il sort de ton 'while', tombe dans ton 'for', et affiche donc la valeur '1'. Le temps que ta boucle et que ton envoie se fassent, le deuxième octet est arrivé dans le buffer, il te sort '2', et ainsi de suite.
Si tu veux attendre que tous les caractères soient arrivés, pose la limite du Serial.available à '< 3' ou met un delay() qui sera fonction de ta vitesse de transmission.

Et oui, j'avais lu, mais j'ai l'habitude de redemander aux gens ce qu'ils veulent exactement faire, cela permet de recadrer l'objectif et de voir d'éventuelles dérives.


Stéphane

Ok ok.
Je n'avais pas pensé à l'ordre d'arrivée.

Du coup... Ca explique TOUT mes problèmes précédents O_O'
Bah... Merci beaucoup :slight_smile:

Mon getNum() récupère l'entrée série du PC, le transforme en int car après j'en ai besoin pour une autre fonction :slight_smile:

Bonjour,

j'ai été grilled par Snootlab en beauté :slight_smile:

Au cas ou cela t'intéresse voila ma version modifié.

Je garanti rien :wink: c'est juste pour te montrer comment j'aurai fait (même si j'aurai pas vraiment fait comme ça ^^"")

Ps: Qt sous mac je suppose ? Bon ok je vais éviter le troll :slight_smile:

Edit: Pour ta fonction getNum tu peux faire ceci :

int Keypad_getNum()
{
  char buffer[3];        
      
  if (Serial.available()>0) delay(25);

  if (Serial.available() >= 2)    
  {                           
    buffer[0] = Serial.read();
    buffer[1] = Serial.read();
    buffer[2] =  '\0';    
    return atoi(&buffer[0]);  // pas top mais bon 
  }
  else
    return -1;            
}

Tu rentre un nombre 01 à 99 (bien 01, 02, ..) et il te le transforme en int

monopoly.zip (7.06 KB)

J'avais complètement oublié de répondre.

Merci beaucoup pour ton code en tout cas. Je m'y suis remis, et je commence du début: http://arduino.cc/forum/index.php/topic,113747.0.html

Sur ce, merci encore, je m'en re-servirais.