[Resolu] Problèmes lors de transmission serie entre deux arduino

Bonjour, voici en gros le topo :

  • J'ai une arduino Mega qui envoie via son port Serie1 un msg du type "A0.0F"
  • Quelques µs plus tard (le temps de quelques instructions) envoie toujours sur le meme port "E8.3F"
  • De l'autre coté une arduino uno, avec la bibliotèque SoftwareSerial sur les pin 12 et 13, recois les donnée et les renvoies sur son port Serie pour suivre les valeurs avec le moniteur Série de l'ordinateur
  • L'arduino Uno envoie à la mega "R" pour lui signifier qu'elle est prête à recevoir une nouvelle valeur
  • Puis l'arduino Mega au bout de 10s vérifie qu'elle a bien recu ce "R" et recommence sa transmission avec les meme valeurs (A0.0F puis E8.3F

Quel est le problème me diriez vous?

Le soucis c'est que la première reception se passe très bien (voir capture 1)

Mais à partir de la deuxième les valeur retransmises n'ont aucun sens (voir capture 2)

Voici le programme de lecture de l'arduino Uno :

#include <SoftwareSerial.h>
byte lecture = 0;

SoftwareSerial mySerial(12, 13); // RX, TX
void setup() {
  Serial.begin(9600);
  Serial.println("Attente réception !");
  mySerial.begin(300);
}
//-- Affichage de la communication
void loop() {
  //-- Si des données sont présentes
  if (mySerial.available())
  {
    lecture = mySerial.read();


    Serial.print("Recpetion en Binaire :");
    Serial.println(lecture, BIN);
    Serial.print("Recpetion en decimal :");
    Serial.println(lecture, DEC);
    Serial.print("Recpetion en ascci :");
    Serial.write(lecture);
    Serial.println();
    //    Serial.print("Valeur variable : ");
    //    Serial.println(atoi(lecture));
  }
  else {
    mySerial.print("R");
  }
}

Le code de la mega peut s'assimiler à :

char MsgA[]="A0.0F";
char MsgE[]="E8.3F";

if (Serial1.available() && (Serial1.read() == 'R')) { //on verifie que l'affichage est pret : R pour Ready
   Serial1.print(MsgA);
}

delay(1); // delais represantant des instruction qui se sont déroulée entre temps.

if (Serial1.available() && (Serial1.read() == 'R')) { //on verifie que l'affichage est pret : R pour Ready
  Serial1.print(MsgE);
}

Il dois y avoir un problème j'imgine au niveau des protocoles série ou autre mais j'arrive vraiment pas à trouver la source du problème.

Les deux arduinos sont reliée entre elle (Rx/ Tx) par des fils de 10cm donc je ne pense pas à des problèmes de pertubation extérieures.

Capture2.PNG

Tu dis que la mega attends 10s avant de vérifier si elle a bien reçu le 'R'

Si le programme que tu donnes est représentatif du code que tu utilises, le problème c'est que pendant ce temps, le programme de lecture boucle en permanence sur ces lignes

  else {
    mySerial.print("R");
  }

puisqu'il n'y a pas de caractère en réception. Donc il essaye d'envoyer des milliers de 'R' pendant l'attente. Il faudrait peut-être ne l'envoyer qu'une fois.

L'envoyer qu'une seule fois me pauserais problème car cela me sert à vérifer que l'arduino Uno n'est pas déconnectée dans ce code (présent sur l'arduino mega):

int LedTimeout = 3;
bool USB = true;

void setup (){
   Serial1.begin(300);
   Serial.begin(9600);
   pinMode(LedTimeout, OUTPUT);
}

void loop(){
   TimeOut(TransmettreA);
   delay(1);                        // delais représentant d'autre calculs
   TimeOut(TransmettreE);
   delay(10000);                 //10s pour eviter spam les consoles
}

void TransmettreA(){
   Serial1.print("A0.0F");
}

void TransmettreE(){
   Serial1.print("E8.3F");
}

void TimeOut(void * pointeurFonction()) {
  long refTmp = millis();
  while (true) {
    digitalWrite(LedTimeout, LOW);
    if ((millis() - refTmp) > 1000) {
      if ( USB) {
        Serial.println("/!\\ TimeOUT ! Verifiez l'alimentation et la connection entre les deux arduinos ! /!\\ ");//error
      }
      digitalWrite(LedTimeout, HIGH);
      delay(500);
      break;
    }
    else if (Serial1.available() && (Serial1.read() == 'R')) { //on verifie que l'affichage est pret : R pour Ready
      (*pointeurFonction)();
      while (Serial1.available() > 0) {
        /*On vide le buffer pour mieux detecter la perte de connection*/
        Serial1.read();
      }
      break;
    }
  }
}

ThorOden:
L'envoyer qu'une seule fois me pauserais problème car cela me sert à vérifer que l'arduino Uno n'est pas déconnectée dans ce code (présent sur l'arduino mega)

Oui mais alors il faut l'envoyer de manière réfléchie. Ton hors temps est fixé à 1s et tu vérifies toutes les 500ms la présence d'un caractère 'R' reçu. Il est donc parfaitement inutile d'envoyer ce caractère en boucle car cela sature le buffer d'émission de l'équipement distant. Tu pourrais te contenter d'envoyer le 'R' toutes les 100ms par exemple.

A noter : tu utilises beaucoup de delay() qui bloquent le déroulement du code. Ce n'est pas nécessairement la façon de coder la plus efficace. Mais c'est un autre problème

fdufnews:
A noter : tu utilises beaucoup de delay() qui bloquent le déroulement du code. Ce n'est pas nécessairement la façon de coder la plus efficace. Mais c'est un autre problème

Oui ils sont la que pour eviter que la console spam et pour representer les des délais du à l'appel des fonctions qui produise ces "A0.0F" et "E8.3F" je ne les ai pas écrite ici car le code est assez gros et ca alourdirait pour rien l'essentiel.

Neamoins je vais essayer de m'en passer en passer en utilisant le

void serialEvent()

je reveins dès que j'ai une alternative utilisant cette fonction.

Mais à la limite ce problème de delay() n'est pas gênant.
Ce qui est gênant c'est que tu ne cadences pas l'émission des 'R' parce que tu remplis le buffer de l'émetteur et du coup il ne fait plus rien tant qu'il n'a pas vidé ce buffer. Ce qui pourrait expliquer tes problèmes de réceptions

Ok j'ai rien dis le serialEvent n'est appelé par l'arduino qu'en fin de loop() donc ca n'a pas d'interêt pour moi...

Mais effectivment en remodelant le code et en suprimant les delay() cela marche ! Merci !

Pour en revenir aux buffers je crois avoir compris donc il faut ajuster la frequence d'envois à une valeur plus petite que le débit de transmission c'est ça ?

Voici le résultat pour ceux que cela interesserais :

Code UNO :

#include <SoftwareSerial.h>
byte lecture = 0;

SoftwareSerial mySerial(12, 13); // RX, TX
void setup() {
  Serial.begin(250000);
  Serial.println("Attente réception !");
  mySerial.begin(9600);
}
//-- Affichage de la communication
void loop() {
  //-- Si des données sont présentes
  while (mySerial.available() > 0){
    lecture = mySerial.read();
    Serial.print("Recpetion en Binaire :");
    Serial.println(lecture, BIN);
    Serial.print("Recpetion en decimal :");
    Serial.println(lecture, DEC);
    Serial.print("Recpetion en ascci :");
    Serial.write(lecture);
    Serial.println();
  }
  //on envoie "R" toute les 100ms tant que le buffer est vide
  long reftmp = millis();
  while (mySerial.available() <= 0) {
    if (millis() - reftmp > 100) { 
      mySerial.print("R");
      reftmp=millis();
    }
  }
}

Code MeGa :

int LedTimeout = 11;
bool USB = true;

void setup()
{ //-- définition du port Série Logiciel
  Serial1.begin(9600);
  pinMode(LedTimeout, OUTPUT);
  if (USB) {
    Serial.begin(250000);
  }
}

void loop() { //-- Toutes les 2 secondes envoi d'un message
  TimeOut(EnvoyerA);
  TimeOut(EnvoyerE);
}

void EnvoyerA() {
  Serial1.print("A0.0F");
  if (USB) {
    Serial.println("j'ai envoyé : A0.0F");
  }
}

void EnvoyerE() {
  Serial1.print("E8.3F");
  if (USB) {
    Serial.println("j'ai envoyé : E8.3F");
  }
}
void TimeOut(void * pointeurFonction()) {
  long refTmp = millis();
  bool EtatLed = LOW;
  while (Serial1.available() <= 0) {
    if ((millis() - refTmp) > 1000) {
      if ( USB ) {
        Serial.println("/!\\ TimeOUT ! Verifiez l'alimentation et la connection entre les deux arduinos ! /!\\ ");//error
      }
      EtatLed = !EtatLed;
      digitalWrite(LedTimeout, EtatLed);
      refTmp = millis();
    }
  }
  while (Serial1.available() > 0) {
    if ((Serial1.read() == 'R')) { //on verifie que l'affichage est pret : R pour Ready
      digitalWrite(LedTimeout, LOW);
      (*pointeurFonction)(); //on exute la fonction demande
      /*On vide le buffer*/
      while (Serial1.available() > 0) {
        Serial1.read();
      }
      break; // on assure de quiter la boucle car on veut que la fonction s'execute qu'une seule fois
    }
  }
}

Faut que j'intègre ces test au programme gobal en espérant que cela marche, mais il ne devrait pas y avoir de raison :slight_smile:

ThorOden:
Pour en revenir aux buffers je crois avoir compris donc il faut ajuster la frequence d'envois à une valeur plus petite que le débit de transmission c'est ça ?

Ce serais meme 8fois plus petit non ? donc pour une connection de 9600baud faut un appel de transmission à un débit de 1200Hz max donc avoir un delais d'au moins 900µs

ThorOden:
Ce serais meme 8fois plus petit non ? donc pour une connection de 9600baud faut un appel de transmission à un débit de 1200Hz max donc avoir un delais d'au moins 900µs

Il y a 9 moments par octets : 8 bits de data plus un stop (modifié :slight_smile: par défaut.
Vous pouvez monter jusqu'à 1000000 bauds/s

bidouilleelec:
Il y a 9 moments par octets : 8 bits de data plus un stop.

Effectivement je l'avais oublié celui la merci, et encore cela dépend de la définition de la communication série lors du Serial.begin(Debit,Format).

bidouilleelec:
Vous pouvez monter jusqu'à 1000000 bauds/s

Certe mais dans l'application que j'ai de mes programmes cela ne sera pas possible car je vais communiquer via des fils de 25m il va falloir que je réduise le débit. 9600baud c'est peut être encore trop

BTW : bauds = bit par seconde. bauds/s = accélération ?

bidouilleelec:
Il y a 9 moments par octets : 8 bits de data plus un stop.
Vous pouvez monter jusqu'à 1000000 bauds/s

Et comme il y a aussi un start....

Donc 10 bit à transmettre lors du protocole SERIAL_8N1 ?

ce qui veux dire un delais d'au moins 10ms entre chaques envois des "R"

hello
juste une question hors sujet ( quoique...)

la liaison série de 25 m, se passe bien ? 25 m ce n'est pas trop long ?

j'ai une liaison de 10 m à faire et pensant que c'était trop long pour du filaire, je pensais passer par bluetooth

Bonjour fdufnews

fdufnews:
Et comme il y a aussi un start....

Il n'y a pas de start bit.

Cordialement,
bidouillelec

bidouilleelec:
Il n'y a pas de start bit.

Bonjour,

Bien sur qu'il y a un start bit, autrement comment serait détecté le début d'un caractère?

bidouilleelec:
Bonjour fdufnews
Il n'y a pas de start bit.

Cordialement,
bidouillelec

Un peu de lecture