Perte de données dans les echanges entre deux modules HC-05 (mauvaise methode ?)

Bonjour,
Je suis nouveau dans le monde arduino et j’aurais besoin d’aide afin de réaliser mon projet.
J’ai pas mal chercher sur ce forum et d’autres mais malheureusement je n’ai pas trouvé de solution à mon problème.

Description du problème :
Lors des échanges entres les deux modules je perds des données. Cela doit venir du fait que soit je les envoie mal (pas la bonne méthode ou le bon format) soit je les déchiffre mal à la réception (pas la bonne méthode ou le bon format). Je me suis aperçu qu’il y a un phénomène de timing pour la réception.
J’ai ralenti volontairement l’envoie des données mais pour la réception ben ca cafouille… :o

Soyez indulgent car je ne sui pas programmeur et cela fait très longtemps que je n’ai pas codé en genre de C :confused:
Je vous remercie par avance pour votre aide. :slight_smile:

Mon projet est assez simple: 2 arduino : uno et mega 2560

  • Le uno est le maitre sur lequel sont branchés :
  • un HC05
  • 4 boutons poussoir
  • 4 potentiomètres
  • 4 leds

Fonctionnent du maitre :
Lors de l’appui sur btn 1 par exemple il lit la valeur des potentiomètres, allume la led correspondante. Les valeurs du bouton et des potentiomètres sont transmises au HC-05 qui l’envoie à l’esclave.
Les valeurs des potentiomètres sont lues en permanence et si la valeur d’un d’entre eux change elle est transmise par le HC-05 à l’esclave. Si l’on appui sur un autre bouton, cela recommence avec d’autres couples de valeurs.

L’esclave :
L’arduino Mega 2560 sur lequel sont connectés :

  • un HC05
  • 2 servo SG90
  • une led pour faire genre :slight_smile:

Le fonctionnement de l’esclave :
Assez simple : Il attend les trames du maitre et exécute les commandes reçues.

  • un morceau de code du maitre :
boolean debug = true;
boolean debug1 = false;
SoftwareSerial BT(BT_RX,BT_TX); // RX | TX
Timer t;
String outgoing;
String incoming;
char envoi;
int bytesSent;
int _ABVAR_1_v1;
int _ABVAR_2_g1;
int _ABVAR_3_a;
void led3();
void CH1b();
void CH3b();
void CH2b();
void led2();
void led_mute();
void led1();
void mute();

void loop(){
if (digitalRead(bouton_1)){
        
        Serial.println("led1");
      while ( ( !( digitalRead(bouton_2) ) && ( !( digitalRead(bouton_3) ) && !( digitalRead(bouton_4) ) ) ) ){
           led1();
           CH1b();
        }
      }
      
 Check_HC05_STATE();
     if (digitalRead(bouton_2)){
        
         Serial.println("led2");
      while ( ( !( digitalRead(bouton_1) ) && ( !( digitalRead(bouton_3) ) && !( digitalRead(bouton_4) ) ) ) ){
          led2();
           CH2b();
       }
      }
}
void led1()
{
  digitalWrite( led_1 , HIGH );
  digitalWrite( led_2 , LOW );
  digitalWrite( led_3 , LOW );
  digitalWrite( led_4 , LOW );
}

void led2()
{
  digitalWrite( led_1 , LOW );
  digitalWrite( led_2 , HIGH );
  digitalWrite( led_3 , LOW );
  digitalWrite( led_4 , LOW );
}

void CH1b()
{
_ABVAR_1_v1 = analogRead(A0) ;
//servo_volume_pin_9.write( map ( _ABVAR_1_v1 , 0 , 1023 , 0 , 157 )  );
_ABVAR_2_g1 = analogRead(A1) ;
//servo_gain_pin_8.write( map ( _ABVAR_2_g1 , 0 , 1023 , 15 , 163 )  );
    envoi = '1';    
    //if(debug==true){Serial.println(envoi);}else{}
      bytesSent = BT.write("A");
    delay(300);
      envoi_volume_BT();
      envoi_gain_BT();
  }

void envoi_volume_BT(){
    Serial.print("Dans envoi envoi : ");
    Serial.println(envoi);
    
if (envoi=='1'){
   BT.println(_ABVAR_1_v1);
 delay(300);
   if(debug==true)Serial.println(_ABVAR_1_v1);else{}
    
 }   
if (envoi=='2'){
   BT.println(_ABVAR_1_v1);
    if(debug==true)Serial.println(_ABVAR_1_v1);else{}
   delay(300);
    
}
void envoi_gain_BT(){
    Serial.print("Dans gain envoi : ");
    Serial.println(envoi);
    
if (envoi=='1'){
   BT.println(_ABVAR_2_g1);
      if(debug==true)Serial.println(_ABVAR_2_g1);else{}
  delay(300);
}   
if (envoi=='2'){
   BT.println(_ABVAR_2_g1);
      if(debug==true)Serial.println(_ABVAR_2_g1);else{}
  delay(300);
}
  • un morceau de code de l’esclave :
String channel;
String incoming;
String trame  ;
String message;

boolean debug=true;

int _ABVAR_1_v1;
int _ABVAR_2_g1;
int _ABVAR_3_a;

Servo servo_gain_pin_8;
Servo servo_volume_pin_9;

SoftwareSerial BT(BT_RX, BT_TX); // RX | TX
void CH1b()
{
incoming= incoming.substring(1,5);
trame = trame.substring(1,5);
_ABVAR_1_v1 =incoming.toInt();
_ABVAR_2_g1 =trame.toInt();
if(debug==true){Serial.print("CH1 et la valeur est :");Serial.println(_ABVAR_1_v1);}else{}
//_ABVAR_1_v1 = analogRead(A0) ;
servo_volume_pin_9.write( map ( _ABVAR_1_v1 , 0 , 1023 , 0 , 157 )  );
if(debug==true){Serial.print("CH1 la valeur de _ABVAR_2_g1 est :");Serial.println(_ABVAR_2_g1);}else{}
//_ABVAR_2_g1 = analogRead(A1) ;
servo_gain_pin_8.write( map ( _ABVAR_2_g1 , 0 , 1023 , 15 , 163 )  );
  
}  
void CH2b()
{
incoming= incoming.substring(1,5);
trame = trame.substring(1,5);

_ABVAR_1_v1 =incoming.toInt();
_ABVAR_2_g1 =trame.toInt();

if(debug==true){Serial.print("je suis dans CH2 et la valeur est :");Serial.println(_ABVAR_1_v1);}else{}
//_ABVAR_1_v1 = analogRead(A2) ;
servo_volume_pin_9.write( map ( _ABVAR_1_v1 , 0 , 1023 , 0 , 157 )  );
if(debug==true){Serial.print("CH2 la valeur de _ABVAR_2_g1 est :");Serial.println(_ABVAR_2_g1);}else{}
//_ABVAR_2_g1 = analogRead(A3) ;
servo_gain_pin_8.write( map ( _ABVAR_2_g1 , 0 , 1023 , 15 , 163 )  );
  
  
  }

void loop()
{

  // listen for a response from the HC-05 and write it to the serial monitor
  if(BT.available()){
     byte inc = BT.read(); //check the incoming character    
      if(inc != 0 && inc < 127){ //if the incoming character is not junk then continue reading the string
        //delay(10);
        incoming = char(inc) + BT.readStringUntil('\n');
        //incoming = char(inc) + BT.read();
        if (debug==true){Serial.print ("incoming : ");Serial.println (incoming);}else{}
        
        //delay(10);
        trame = char(inc) + BT.readStringUntil('\n');
        if (debug==true){Serial.print ("trame : ");Serial.println (trame);}else{}
      } 
    }
                channel=incoming.substring(0,1);
                
              if (debug==true){Serial.print("channel : ");Serial.println(channel);}else{}
                if(channel == "D") {
                digitalWrite(led,HIGH); 
                if (debug==true){Serial.println ("switch 4 : ");}else{}
                mute();
                }
                
                if(channel == "C") {
                digitalWrite(led,HIGH); 
                if (debug==true){Serial.println ("switch 3 : ");}else{}
                CH3b();
                }

                if (channel == "B") {
                    digitalWrite(led,LOW); 
                    if (debug==true){Serial.println ("switch 2 : ");}else{}
                    CH2b();
                 }
                  
                  if (channel == "A") {
                    digitalWrite(led,LOW); 
                    if (debug==true){Serial.println ("switch 1 : ");}else{}
                    CH1b();
                  }
                  if ((channel != "A")||(channel != "B")||(channel != "C")||(channel != "D")){
                  //Serial.println("Perte de message");
                  }
}

la fonction readStringUntil() ne vous garantit pas de lire jusqu'au caractère indiqué, si les data sont lentes à arriver alors vous pouvez avoir un timeout

jouer avec la classe String c'est aussi avoir envie de tomber dans des soucis de mémoire si on ne comprend pas bien ce que l'on fait... --> à éviter

lisez éventuellement mon petit tuto Ecouter le Port Série ou un keypad (applicable à 1 flux de données asynchrone )

Bonjour J-M-L,
Merci pour votre réponse je vais regarder cela attentivement.
Je vais essayer de faire ne sorte d'envoyer une trame au lieu de donnée par donnée.

Bonjour,
Alors j’ai bien étudié toute la littérature que tu m’as conseillé.
J’en suis arrivé à la conclusion qu’il faut que je change la façon d’envoyer et recevoir la trame.
Donc je construis une trame dans le code du maitre sous cette forme : <A,900,280> par exemple.
L’esclave reçoit la trame, la décode puis exécute les commandes.
Je me suis beaucoup inspiré de Topic: Serial Input Basics :slight_smile: :slight_smile: http://forum.arduino.cc/index.php?topic=396450.0 merci!!

Maintenant je rencontre un problème différent. Il semble que ne perde plus de données mais le décodage de la trame ne fonctionne pas correctement. De temps en temps j’ai des valeurs tronquées ou mal décodée.

Pourriez-vous m’aider ?

voici une copie de la console quand cela ratatouille :

//cycle n-1 qui fonctionne 
channel : A
_ABVAR_1_v1 286
_ABVAR_2_g1 285
switch 1 : 
CH1 et la valeur est :286
CH1 la valeur de _ABVAR_2_g1 est :285
cloture la chaine

//cycle n qui ratatouille  on voit que _ABVAR_2_g1 est 28 au lieu de 289

               a =   0
channel : A
_ABVAR_1_v1 286
_ABVAR_2_g1 28
switch 1 : 
CH1 et la valeur est :286
CH1 la valeur de _ABVAR_2_g1 est :28    
cloture la chaine
               a =   0

Voici le code du maitre :

void CH1b()
{
_ABVAR_1_v1 = analogRead(A0) ;
//servo_volume_pin_9.write( map ( _ABVAR_1_v1 , 0 , 1023 , 0 , 157 )  );
_ABVAR_2_g1 = analogRead(A1) ;
//servo_gain_pin_8.write( map ( _ABVAR_2_g1 , 0 , 1023 , 15 , 163 )  );
    envoi = '1';
    envoi_volume_BT();
    envoi_gain_BT();
  } 
}

void envoi_volume_BT(){
    
if (envoi=='1'){

    trame = trame + "," +_ABVAR_1_v1;

  }   
}

void envoi_gain_BT(){
    if(debug==true){Serial.print("Dans gain envoi : ");Serial.println(envoi);}else{}
    
if (envoi=='1'){
    trame = trame + "," +_ABVAR_2_g1+">";

  }
}

void envoi_trame(){
BT.println(trame);
delay(400);
Serial.print("trame envoyée : ");
Serial.println(trame);
}

void loop{
if (digitalRead(bouton_1)){
        
        Serial.println("led1");
        
      while ( ( !( digitalRead(bouton_2) ) && ( !( digitalRead(bouton_3) ) && !( digitalRead(bouton_4) ) ) ) ){
           trame = "<A";
         
           CH1b();
           envoi_trame();
           trame = "";
        }
}

Voici le code de l’esclave :

int a=0;
void loop() {
         
    
          recvWithStartEndMarkers();    
    
    if (newData == true) {
      
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
 

        parseData();
        
        showParsedData();
      
        selection();
        
      receivedChars[numChars] ={0};
      tempChars[numChars] ={0};
      messageFromPC[numChars] = {0};

      }
        newData = false;
}   

void recvWithStartEndMarkers() {
    static boolean recvInProgress = true;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (BT.available() > 0 && newData == false) {
        
        rc = BT.read();
        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                Serial.println("cloture la chaine");
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
                }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
  
}


void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index
int a;
    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    _ABVAR_1_v1 = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");
    _ABVAR_2_g1 = atoi(strtokIndx);     // convert this part to a float
    
    strtokIndx = strtok(NULL, ",");
    a = atoi(strtokIndx);     // convert this part to a float
    Serial.print("               a =   ");
    Serial.println(a);
}


void showParsedData() {
    channel = messageFromPC;
    Serial.print("channel : ");
    Serial.println(channel);
    
    Serial.print("_ABVAR_1_v1 ");
    Serial.println(_ABVAR_1_v1);
    Serial.print("_ABVAR_2_g1 ");
    Serial.println(_ABVAR_2_g1);
}


void selection(){
 //if (debug==true){Serial.print("trame : ");Serial.println(trame);}else{}
                if(channel == "D") {
                digitalWrite(led,HIGH); 
                if (debug==true){Serial.println ("switch 4 : ");}else{}
                mute();
                
                }
                
                if(channel == "C") {
                digitalWrite(led,HIGH); 
                if (debug==true){Serial.println ("switch 3 : ");}else{}
                CH3b();
                }

                if (channel == "B") {
                    digitalWrite(led,LOW); 
                    if (debug==true){Serial.println ("switch 2 : ");}else{}
                    CH2b();
                 }
                  
                  if (channel == "A") {
                    digitalWrite(led,LOW); 
                    if (debug==true){Serial.println ("switch 1 : ");}else{}
                    CH1b();
                  }
                  if ((channel != "A")||(channel != "B")||(channel != "C")||(channel != "D")){
                  //Serial.println("Perte de message");
                  }
}

Faites afficher toute la chaîne reçue

Bonjour,
Maintenant j’envoie deux fois la trame mais même résultat! La trame envoyée n’as pas d’erreur ni de caractères bizarre.
On dans la trame reçue il y a le premier cycle qui est bon et se second qui ratatouille!!! >:(
Dans la trame reçue les <> sont rétirés puisque ce sont les markers début et fin de chaine.
Merci encore pour ton temps et tes explications.

La trame envoyée est :

HC-05 serial is ready too!
For a list of commands, visit: 
Type AT commands  

Now setting HC-05 mode to COMMUNICATION_MODE
HC-05 non connecté. Relance d'une connexion
Now setting HC-05 mode to AT_MODE
>>AT+ROLE=1
>>AT+CMODE=0
OK
OK
>>AT+CLASS=0
>>AT+BIND=0015,83,3558f1
OK
OK
>>AT+INIT
>>AT+INQ
OK
+INQ:78AB:BB:F9792E,8043C,7FFF
OK
>>AT+LINK=0015,83,3558f1
HC-05 is connected to a bluetooth device.
led1
trame1 envoyée : <A,533,460>
trame2 envoyée : <A,533,460>
trame1 envoyée : <A,405,401>
trame2 envoyée : <A,405,401>
trame1 envoyée : <A,354,356>
trame2 envoyée : <A,354,356>
trame1 envoyée : <A,342,341>
trame2 envoyée : <A,342,341>

La trame reçue :

***************************** dans Sélection
*************************dans new parseData : 
Message reçu sans traitement: A,392,388
Message reçu apres copie pour traitement: A,392,388
***************************dans showParsedData:  
channel : A
_ABVAR_1_v1 392
_ABVAR_2_g1 388
***************************** dans Sélection
*************************dans new parseData : 
Message reçu sans traitement: A,3⸮i⸮⸮⸮j
<A,344,346
Message reçu apres copie pour traitement: A,3⸮i⸮⸮⸮j
<A,344,346
***************************dans showParsedData:  
channel : A
_ABVAR_1_v1 3
_ABVAR_2_g1 344

Message reçu sans traitement: A,3⸮i⸮⸮⸮j

Vous êtes en software Serial à 115200 bauds ?

Si oui c’est trop rapide pour software serial si vous envoyez bcp de data essayez à 9600 et en ralentissant la fréquence d’envoi

Bonjour,
Non j’étais à 38400 (défaut) et je suis passé à 9600. :o Bof bof
J'ai donc implémenté une trame reçue n-1 qui compare à la trame reçue.
Si elles sont égales je fais l'action sinon le lit la suivante et je re-compare .
C'est mieux mais bof bof c'est pas top...