Problème USART - ATMega2560

bkd974:
Moi aussi je me prends un peu la tête avec les liaisons série sur Mega2560. Je n'ai pas encore testé mais il me semble que si on utilise le port Serial1 il faut écrire alors :

void SerialEvent1() {...}

Oui, en effet, j'ai testé ça ne fonctionne pas. Je me replonge dedans, si tu as des résultats positifs n'hésite pas à les partager !

Merci

Dans la série "Je comprends rien à cette foutue liaison série", nouvel épisode :

J'ai fait une deuxième carte totalement identique (on a même vérifié à trois), j'ai chargé le code ci-dessous et "miracle" sur la nouvelle carte ça fonctionne alors que sur l'ancienne ça ne fonctionne toujours pas ! Même conf de GPS aussi, pas de doute là-dessus !

void setup() {
Serial1.begin(57600);
Serial.begin(57600);
}

void loop() {
int c = Serial1.available();
if(c > 0) {
for(int i = 0; i < c ; i++) {
char data = Serial1.read();
Serial.print(data);
}
}
}

Au scope, sur la nouvelle carte, j'ai un signal TTL (0-3V3) sur le TX du GPS (normal !), alors que sur l'ancienne carte je mesure 3V3 tout le temps sur TX. Si ça parle à qq'un...

jean23:
Au scope, sur la nouvelle carte, j'ai un signal TTL (0-3V3) sur le TX du GPS (normal !), alors que sur l'ancienne carte je mesure 3V3 tout le temps sur TX. Si ça parle à qq'un...

Au pifométre je dirai qu'il y a un point diviseur quelque par entre le RX de la shield et le RX de l'atmega.

Pas de pont diviseur...

Je baisse les bras, ça fait 3 heures que je suis dessus, ça marche un coup et après ça ne marche plus... Quelle mer**...

jean23:
Pas de pont diviseur...

Je baisse les bras, ça fait 3 heures que je suis dessus, ça marche un coup et après ça ne marche plus... Quelle mer**...

bonjour
je sais par expérience que ce genre de situations peuvent être très frustrantes 8)
mais il ne faut pas partir dans tous les sens pour "deverminer"
pose toi calmement
et pour l'instant oublie arduino

ton/tes modules NEO6
acheté où ?
verifié aupres d'Ublox que ce sont des "certifiés OEM" ?

la cablage sur PCB ? PCB fait par qui ? soudé par qui ?
ça donne quoi avec de la simple liaison serie "PC"

Bon ba je n'en suis pas vraiment fier, mais au bout du reply #25 j'ai trouvé mon problème...
Un pote qui avait fait le schéma était optimiste à l'idée que le FTDI qu'on utilise pour communiquer avec le PC, puisse alimenter l'ATMega ET le GPS. (FTDI : https://www.sparkfun.com/products/9873)

Manque de pot, on s'est replanché sur la partie hardware, comme tu préconisais Artouste, et on s'est rendu compte qu'il est limité en conso.... :~ J'aurais du vérifier quel c**... Du coup, j'ai bidouillé une alim 3V3 et ça fonctionne...

Donc, excusez-moi pour ces messages concernant mon pbl de GPS qui ne fonctionnait qu'à moitié. Maintenant je vais me repenché sur mon pbl initial : comment récupérer mes trames à 5Hz sans perdre d'info, tout en calculant d'autres données (gyro accéléro)

J'aimerais sortir mes infos (Yaw, Pitch, Roll) à 20Hz, et inclure dans ce flux mes trames GPS quand elle arrive à 5Hz.
Du genre :

     Yaw = 320, Pitch = 4, Roll = 3
     Yaw = 320, Pitch = 4, Roll = 3
     Yaw = 320, Pitch = 4, Roll = 3
     Yaw = 320, Pitch = 4, Roll = 3
     $GPRMC................................*xx
     Yaw = 320, Pitch = 4, Roll = 3
     Yaw = 320, Pitch = 4, Roll = 3
     Yaw = 320, Pitch = 4, Roll = 3
     Yaw = 320, Pitch = 4, Roll = 3
     $GPRMC................................*xx
     etc...

Pour le moment, quand j'affiche ma trame Y,P,R je teste après si (Serial1.available() > 0)
Si oui, j'affiche la trame

Du coup, je me retrouve avec un truc de ce style :

     Yaw = 320, Pitch = 4, Roll = 3
     $GPRMC..........Yaw = 320, Pitch = 4, Roll = 3
     Yaw = 320, Pitch = 4, Roll = 3
     ......................*xx
     Yaw = 320, Pitch = 4, Roll = 3
     etc...

Si j'arrive à faire ça, un pote se chargera de faire une IHM pour faire rêver les encadrants. Moi j'en peux plus !

Merci pour votre aide à tous

Jean

jean23:
Bon ba je n'en suis pas vraiment fier, mais au bout du reply #25 j'ai trouvé mon problème...
Un pote qui avait fait le schéma était optimiste à l'idée que le FTDI qu'on utilise pour communiquer avec le PC, puisse alimenter l'ATMega ET le GPS. (FTDI : https://www.sparkfun.com/products/9873)

Manque de pot, on s'est replanché sur la partie hardware, comme tu préconisais Artouste, et on s'est rendu compte qu'il est limité en conso.... :~ J'aurais du vérifier quel c**... Du coup, j'ai bidouillé une alim 3V3 et ça fonctionne...

bonjour
le principal c'est d'avoir trouvé le probleme
Il faut savoir quelquefois accepter de remettre à 0 ses idées.

pour maintenant revenir au traitement des sentences à 5Hz pour l'integrer dans ton projet

pour faire simple une sentence RMC c'est 100 (large) caractères à transmettre soit un taux de baud de 1000=5000 pour du 5Hz
tu peux configurer le NE6 pour qu'il ne sorte que de la RMC ?
si oui tu à tout intérêt à descendre le taux de baud (19200 me semble là un bon compromis)

Je mets ça en standby pendant qlqs jours, mais pour le moment je suis revenu sur l'idée de skywood, c'est-à-dire utiliser la fonction readBytesUntil(). Je pense voir le bout...

Artouste:
pour faire simple une sentence RMC c'est 100 (large) caractères à transmettre soit un taux de baud de 1000=5000 pour du 5Hz
tu peux configurer le NE6 pour qu'il ne sorte que de la RMC ?
si oui tu à tout intérêt à descendre le taux de baud (19200 me semble là un bon compromis)

Oui c'est assez génial, avec le logiciel U-center tu programmes tous les GPS Ublox assez intuitivement. Baudrate, fréq, messages, etc...
Je prends note du 19200, par contre si j'envoie plusieurs trames en plus, ça va peut-être être juste. A voir la semaine prochaine.

Merci pour le temps que vous m'avez consacré.

Jean

Bien le bonjour à tous.
Après lecture de ce sujet j'ai moi-même hésiter à faire communiquer 2 MEGA2560 entre eux via XBEE sachant qu'il s'agit de piloter un chariot convoyeur de deux tonnes dans une usine de parpaings !! Voici ce que j'ai appris et ce qui m'inquiète un peu sur les communications Serial d'Arduino :

@jean23 : La nouvelle alim 3.3 a-t-elle résolu tous tes problèmes ?
Pour moi, un autre soucis (de taille) se pose : la taille d'une trame RMC et la taille du buffer série d'Arduino.

  1. Toutes les fonctions Serial. available() peek() read() etc.. s'adressent essentiellement à un buffer (et non directement au "flux"). Ce Buffer est donné pour 128 octets (en réalité 64 octets IN et 64 octets OUT). A 57600 bauds il se sature en 9ms et toutes les données Serial suivantes sont perdues... Seuls les 63 octets les plus anciens survivent en attendant d'être lus ! Donc, avant toute lecture série, des Serial.flush() s'imposent... D'un seul tenant il est impossible que le buffer série contienne toute une trame RMC ! Cela signifie qu'il faut lire plus vite que cela ne rentre sinon des données seront perdues et les prochaines ne seront là que dans 200ms... Dans le cas d'une trame RMC les données sont à "compter" dans un ordre bien précis. L'oubli d'une virgule séparatrice serait une catastrophe !

  2. Quand lire le port série ? Malheureusement, Serial.Event() ne fonctionne pas comme une interruption. Cette fonction est appelée entre 2 loop. Donc, impossible de compter là-dessus dans une boucle while ou autre... C'est tant mieux car on serait constamment en interruption !

  3. Les Find() et FindUntil() sont très pratiques mais ce sont des fonctions "bloquantes". A même titre que delay() le programme s'arrête tant que Find() n'est pas "vrai" et ce, durant toute la durée du SetTimeOut() qui par défaut est à 1000ms ! Si plusieurs arguments de Find() existent dans le buffer seul le plus ancien est pris en compte. A noter que lorsque l'argument est trouvé, ces fonctions Find("argument") ont un effet destructeur sur les données lues jusque là (ce qui n'est pas plus mal). Cela revient à faire des read() jusqu'à ce que l'argument soit trouvé.

Exemple de fonctionnement de find("argument") :

  • Le buffer contient "abcdefX123ghijklmnopX456qrstuvwxyz" soit Serial.available()=30
  • find("X") a pour effet de détruire la suite "abcdef"
  • parseInt() a pour effet de lire la valeur 123 comprise entre le "X" et le "g"
  • A ce stade le buffer n'est plus que "ghijklmnopX456qrstuvwxyz"
    Il faudra répéter ces opérations afin d'aller chercher le "X456"

Voilà. Après avoir appris et vérifié tout ceci je regarde la communication Serial d'un autre oeil.
Sur un port série, les informations les plus importantes étant les plus récentes, une bonne gestion du buffer s'impose.
J'ai mis au point la petite technique ci-dessous (mais je n'ai pas la science infuse!)

  • Côté émetteur, j'envoie les infos comme suit : ["nom", valeur]. Exemple: X10Y20
  • J'évite d'utiliser Serial.available() car il est toujours available ! Un émetteur Serial diffusant généralement en permanence et à vitesse maxi.

Exemple simpliste sur le port Serial1 :

Serial1.setTimeout(5); // à faire une fois pour toute (à ajuster en fonction du flux)

// Lecture des dernieres valeurs x, y
Serial1.flush();
while ( !Serial1.find("X") );
int x = Serial1.parseInt();
while ( !Serial1.find("Y") );
int y = Serial1.parseInt();

Cette méthode fonctionne bien pour des flux "répétitifs". Ici un transfert continu de coordonnées X et Y comprises entre 0 et 999 soit au maximum 8 octets par boucle. A 57600 on transmet jusqu'à 900 couples XY par seconde soit (en théorie) à peine 1ms d'attente pour un Serial.find("X"). Le setTimeout() devient alors juste une sécurité.

Voilà pourquoi j'ai arrêté les available() et read() !

@jean23
Ton problème de trame RMC résolvant le mien par la même occasion, je me suis donc un peu penché sur le sujet...

Je n'ai pas de module GPS sous la main mais d'après ce que j'ai pu lire la trame RMC se compose de 13 champs (dont 2 champs de CTL début et fin de trame) séparés par des virgules.
Attraper un bout de trame "en vol" n'a aucun intérêt. " ,10,50,E" ne veut strictement rien dire ! Il faut donc compter depuis le "top départ" qui est "$GPRMC"

Idéalement, si ton Arduino n'avait que çà à faire, on peut imaginer :

while ( !Serial1.find("$GPRMC") ); // attente de 200ms maxi qu'une trame RMC arrive

Serial1.find(","); float gpsTime = parseFloat();
Serial1.find(","); char gpsValid = Serial1.read();
Serial1.find(","); float gpsLatitude = parseFloat();
Serial1.find(","); char gpsNS= Serial1.read();
Serial1.find(","); float gpsLongitude = parseFloat();
Serial1.find(","); char gpsOE= Serial1.read();
Serial1.find(","); int gpsSpeed= parseInt();
Serial1.find(","); float gpsCap = parseFloat();
Serial1.find(","); int gpsDate= parseInt();
Serial1.find(","); int gpsVar= parseInt();
Serial1.find(","); int gpsCorr= Serial1.read();
Serial1.find("*XX");

Mais ton Arduino n'a pas que çà à faire ! Pourtant, à partir de l'instant où le GPS transmet, à son rythme, une salve RMC sur le port série il ne reste plus beaucoup de temps pour lire le buffer de 63 octets avant qu'il ne soit saturé !

  • A 4800 bauds comme préconisé par une vieille norme NMEA, une trame RMC (70 octets maxi) prendrait 120ms pour se charger dans le buffer série. A cette vitesse il n'y aurait pas trop de soucis, les Serial.find() et Serial.setTimeout() se chargeant du délai d'attente.
  • 57600 bauds ce délai passe à 10ms... Le temps de réagir à l'arrivée d'une trame, le buffer est déjà saturé et on risque de perdre les dernières informations. Surtout vers la fin de trame, la date, la variation etc...

Comme tu redistribues à 20Hz tu n'es plus à 20ms près...
Les données GPS pourraient entrer à 9600 çàd 58ms de transfert toutes les 200ms (5Hz).
Il reste 58ms à l'Arduino pour comprendre ce qui se passe et vider le buffer rapidos avant que n'arrive le "*XX"

Le MUST serait que ton module GPS soit équipé d'une entrée CTS. C'est une entrée qui gère une "invitation à émettre".
L'Arduino dirait au GPS (en aparté TTL) : Vas-y, balance !
Sinon ça, par défaut on est en ASYNCHRONE... l'émetteur envoie quand il veut, le récepteur lit quand il peut... Tout ce qui "dépasse" est perdu !

// Lecture des dernieres valeurs x, y
Serial1.flush();

Erreur !!!
Serail.flush attend que le buffer d'émission soit vide voir là --> http://arduino.cc/en/Serial/Flush

fdufnews:

// Lecture des dernieres valeurs x, y
Serial1.flush();

Erreur !!!
Serail.flush attend que le buffer d'émission soit vide voir là --> Serial.flush() - Arduino Reference

Oups! Oui bien vu... c'est terrible çà !
Une fonction qui change totalement d'une version à l'autre !! Ils ne se seraient pas un peu planté chez Arduino sur ce coup là ?

J'ai cherché à comprendre pourquoi et j'arrive à cette conclusion : La fonction Serial.write(data) ayant changé elle aussi. Elle n'est plus bloquante. Donc le programme continue son process pendant que data est envoyé. Il fallait alors une autre fonction pour attendre la fin de transmission. Pourquoi ont-ils utilisé flush() ? c'est un grand mystère pour moi. A moins de travailler à 300 bauds je ne vois aucun intérêt dans ces modifications.
Merci @fdufnews

Dans la mesure où je n'ai aucune idée de l'âge des données inscrites dans le buffer d'entrée, il faut alors le vidanger d'un autre manière... Car dans mon cas, 10ms peut représenter jusqu'à 2cm de mouvement d'un automate de 2 tonnes !

// Pour remplacer le défunt serial.flush()
void monFlush(){
for (int c=0; c<64; c++){
if ( Serial1.available()>0 ) Serial1.read();
else return;
}}

Testé: Cette fonction s'exécute en 0,4ms pour un buffer plein de 63 octets.

bkd974:
Une fonction qui change totalement d'une version à l'autre !! Ils ne se seraient pas un peu planté chez Arduino sur ce coup là ?

C'est pas la seule chose qu'il ont planté durant le passage 002x -> 1.0.x.
Cette fonction en particulier à lancer un coup de gueule général de pas mal de personne, mais la team Arduino n'as rien voulu savoir.

bkd974:
J'ai cherché à comprendre pourquoi et j'arrive à cette conclusion : La fonction Serial.write(data) ayant changé elle aussi. Elle n'est plus bloquante. Donc le programme continue son process pendant que data est envoyé. Il fallait alors une autre fonction pour attendre la fin de transmission. Pourquoi ont-ils utilisé flush() ? c'est un grand mystère pour moi. A moins de travailler à 300 bauds je ne vois aucun intérêt dans ces modifications.
Merci @fdufnews

La gestion des réceptions/transmissions par interruption permet le transfert de données à toutes vitesses sans blocage.
C'est un changement qui lui est bien pensé, mais il aurait été bon de fournir un version bloquante pour l'envoi ... tant pis.
Tu peut aller taper dans le registre UDR du port série qui t'intéresse si tu veut du bloquant sans buffer :wink:

bkd974:

// Pour remplacer le défunt serial.flush()

void monFlush(){
for (int c=0; c<64; c++){
if ( Serial1.available()>0 ) Serial1.read();
else return;
}}




Testé: Cette fonction s'exécute en 0,4ms pour un buffer plein de 63 octets.

Sans doute plus rapide

while(Serial.available()){
    Serial.read();
}

fdufnews:
Sans doute plus rapide

while(Serial.available()){

Serial.read();
}

A mon sens, cette formule est assez inquiétante... Je crois qu'il y a un risque de ne jamais sortir de cette boucle !
A peine l'octet 1 est-il lu est libéré dans le buffer qu'un nouvel octet viendrait occuper la place 63...
Certes, on lit plus vite que l'arrivée d'un flux à 115200. Mais quand est-ce qu'on sort de la boucle ? Ca c'est un grand mystère...
C'est pourquoi je préfère compter jusqu'à 63 afin d'être sûr que les nouveaux arrivants soient les plus récents.

Je me remets tout doucement dans mon projet et je viens de voir tous tes posts BKD974.

A moins que qq'un me contredise mais j'ai l'impression d'avoir régler ce problème de buffer série facilement, depuis longtemps :
Dans le fichier HardwareSerial.h (ou un truc comme ça) que tu as par défaut avec ton IDE Arduino, tu peux modifier la taille de ton buffer en changeant " #define SERIAL_BUFFER_SIZE 64 " par " #define SERIAL_BUFFER_SIZE 255 "

Je ne sais pas si c'est la bonne solution mais j'avais noté cette modif dans les premiers jours de mon projet.

bkd974:

fdufnews:
Sans doute plus rapide

while(Serial.available()){

Serial.read();
}

A mon sens, cette formule est assez inquiétante... Je crois qu'il y a un risque de ne jamais sortir de cette boucle !
A peine l'octet 1 est-il lu est libéré dans le buffer qu'un nouvel octet viendrait occuper la place 63...
Certes, on lit plus vite que l'arrivée d'un flux à 115200. Mais quand est-ce qu'on sort de la boucle ? Ca c'est un grand mystère...
C'est pourquoi je préfère compter jusqu'à 63 afin d'être sûr que les nouveaux arrivants soient les plus récents.

On sort de la boucle lorsque le buffer et vide tout simplement.

@jean23 : Oui thanks. Jouer sur la taille du buffer peut être très utile notamment pour les trames dont on maîtrise la longueur et le timing.

@fdufnews : avec un flux continu à 115200 bauds le buffer se remplit en 4,5ms. A mon avis il se remplit au fur et à mesure qu'il se vide (FIFO). Donc il n'est jamais vide !