Communication entre deux Mega2560, problème de sauvegarde chaine de caractères

Bonjour à toutes et à tous,

Je débute sur Arduino et mon niveau en C est très poussiéreux.
Cela fait plusieurs jour que je fait des essais de communication entre deux Arduino Mega2560 via le port I2C.
Jusque là je me suis débrouillé seul mais maintenant je coince…

Voilà mon problème :
L’idée de mes travaux est de communiquer au travers de chaines de caractères.
L’Arduino Maitre envoie une requête sous forme de message (“Ready ?”) à l’esclave → Ok ça fonctionne.
L’esclave enregistre le message dans la variable (recudumaitre) → Ok ça fonctionne.
L’esclave envoie la requête du Maitre sur sa console → Ok ça fonctionne.
L’esclave envoie au Maitre sa réponse (“Yes Ready !”) → Ok ça fonctionne.
L’esclave envoie la valeur de la variable (recudumaitre) sur sa console → Ça ne fonctionne pas, il n’y a que le dernier caractère (?)…

Je n’arrive pas à comprendre si mon problème vient du fait qu’il n’y ai qu’un seul caractère dans ma variable (recudumaitre) à l’instant T, donc si je dois passer par une incrémentation des caractères ?
Ou si mon problème est d’ordre du format de la variable (recudumaitre) ?

Quelqu’un aurait-il une solution ou une piste??

Le code du Maitre :

// Maitre Arduino 2560
#include <Wire.h>
const int bp = 2;    // Entrée bp

void setup()
{
Wire.begin();       // Init I2C maître
Serial.begin(9600);  // Init Serie
pinMode(bp, INPUT);  // Bouton poussoir envoie de msg à l'esclave
}

void loop()
{
int etatbp; 
etatbp = digitalRead(bp);
if(etatbp == HIGH)
{EnvoieRecoit();}
}

void EnvoieRecoit()
{ 
Wire.beginTransmission(0x01); // Ouvre la comm avec esclave 0x01
Wire.write("Ready ?");          // Charge la valeur à envoyer
Wire.endTransmission();       // envoie et ferme la comm avec esclave 0X01
delay(1000);
Wire.requestFrom(0x01, 11);    // recoit le retour de l'esclave, 11 bytes
while(Wire.available())
  {char retour = Wire.read();
   Serial.print(retour);}
Serial.println();
}

Le code de l’Esclave :

// Esclave Arduino 2560
#include <Wire.h>
char recudumaitre;

void setup()
{ Wire.begin(0x01); 
  Wire.onReceive(reception);      // fonction de lecture appellée quand un msg du Maitre est arrivé
  Serial.begin(9600);
  Wire.onRequest(requestEvent);   // fonction d'écriture appellée en réponse d'une demande du Maitre
}  

void loop()
{delay(100);}

void reception(int NbByte)
{ while(Wire.available() > 0)
    {recudumaitre = Wire.read();  // Enregistrement du message du Maitre dans la variable recudumaitre
    Serial.print(recudumaitre);} // Envoie du message du Maitre dans la console
  
  Serial.print(" : ");
  Serial.print(NbByte);
  Serial.print(" byte(s)");
}

void requestEvent()
{
  Wire.write("Yes Ready !"); // Répondre avec un message de 11 octets (bytes)
  Serial.print(" : recudumaitre = "); // Envoie dans la console de la valeur stockée dans la variable recudumaitre
  Serial.println(recudumaitre);
}

Console du Maitre :
Yes Ready ?

Console de l’Esclave :
Ready ? : 7 byte(s) : recudumaitre = ?

Vous n'enregistez qu'un seul caractère dans recudumaitre, et vous les imprimez à la volée.

 while(Wire.available() > 0)
    {recudumaitre = Wire.read();  // Enregistrement du message du Maitre dans la variable recudumaitre
    Serial.print(recudumaitre);} // Envoie du message du Maitre dans la console

Cest donc normal de ne voir que le dernier caractère.

Utilises un tableau :)

Quand un caractère est reçu, tu incrémentes une variable qui sert de compteur, et utilises la valeur de ce compteur comme position dans le tableau pour y stocker le caractère. Attention à ce que le compteur ne dépasse pas la taille du tableau, et à remettre le compteur à zéro quand nécessaire (détection d'un '\r' ou \'n', par exemple). Voir ici (en bas du post, exemple 2): http://forum.arduino.cc/index.php?topic=396450

bonjour, nous travaillons sur la même chose le bus i2c. Moi aussi, je traite des string. J'ai plus d'avance sur toi. Je fais effectivement un tableau de char: String Transfert deviens char Transfert2 et j'envoie la sauce!

Maitre:

//Transfert
int Transferts(String Transfert)
{
  char Transfert2 [Transfert.length() + 1];                // tableau de char de la taille du String Transfert+1 (caractère de fin de ligne)
  Transfert.toCharArray(Transfert2, Transfert.length() + 1);    // récupère Transfer2 dans le tableau de char

  Serial.print("Transfert: ");
  Serial.println(Transfert2);

  Wire.beginTransmission(adr); // transmettre a l'esclave #10
  Wire.write(Transfert2);      // envoie l'heure
  Wire.endTransmission();      // arrêter la transmission
  Serial.println("Transfert ok");
}

//--------------------------------------------------------------------------

sur mon esclave: je créé un char reception2[l]; de la taille l = Wire.available(); Sa fonctionne bien, mais moi je suis bloqué car je n'arrive pas à récupérer le message 'Message=Wire.onReceive(Reception);' jai une erreur 'no match for 'operator=' (operand types are 'String' and 'void')'

//--------------------------------------------------------------------------
int Reception() //Recevoir du master
{
  Serial.println("Reception");

  l = Wire.available();        //nb d'octé à recevoir
  Serial.print("nb octe: ");
  Serial.println(l);
  char reception2[l];

  while (Wire.available())
  { delay(100);
    char c = Wire.read();     // receive un char
    m = Wire.available();
    m = l - m - 1;
    reception2[m] = c;
  }
  String reception = String(reception2);
  Serial.println(reception);
}

//--------------------------------------------------------------------------

En tout cas, on ne trouve pas grand chose sur le net au sujet de l'i2c. Bon courage!

bonjour, nous travaillons sur la même chose le bus i2c. Moi aussi, je traite des string.
J’ai plus d’avance sur toi.

Moi je dirai que si vous utilisez des Strings avec un grand S vous n’êtes pas vraiment en avance, vous allez au devant des soucis, des que votre code grossira un peu. Cette classe morcelle la mémoire et alourdit votre code; vaut mieux utiliser des tableaux de Caractères et les fonctions C de base.

Si vous tenez à utiliser la classe String, au moins n’alourdissez pas la mémoire inutilement ni ne faites des calculs en trop… votre tableau Transfert2 en pratique ne sert rien, il suffit d’appeler la méthode c_str sur votre String pour passer le pointeur sur la zone de données:

Au lieu de faire
  Wire.write(Transfert2);      // envoie l'heure
Faites

  Wire.write(Transfert.c_str());      // envoie l'heure

Et vous pouvez enlever tout ce qui concerne Transfert2; la vie est plus simple comme celà :slight_smile:

Côté réception, il faut définir le callback comme le fait Gérard avec le nombre d’octets à recevoir en paramètre → void reception(int NbByte)

Vous pouvez essayer un truc comme ça (tapé sur mon tel, je n’ai pas essayé)

void reception(int NbByte)
{
     char messageRecu[NbByte+1];
     messageRecu[NbByte] = '\0'; // pour avoir une belle chaîne de caractères 
     for (int i=0;i<NbByte;i++) messageRecu[i]=Wire.read() ; // on lit tous les caractères 
     
     // on affiche ce que l'on a reçu. Attention le buffer messageRecu étant déclaré dans la fonction il disparaît la sortie de celle ci
     Serial.print("message=[");
     Serial.print(messageRecu);
     Serial.println("]");
}

Bonjour et merci à vous JML, guix, Zarb94,

J’ai bien progressé, toutefois je vais intégrer vos recommandations dans le code, mais j’ai encore du mal avec la manipulation des formats int, String, Char et avec la création et le management des tableaux.
Puis après la couche de JML concernant la mémoire…

Cependant il me reste un problème a surmonter et je me demande bien si mon problème ne vient pas justement des types de variable que j’utilise…

Je m’explique, dans l’esclave en ligne 37, j’utilise un if else, mais il ne fonctionne pas, pourtant les valeurs des variables sont bel et bien identiques au regard de la console de l’Esclave…!
Regarde sous les codes, je vous ai mis les retours des consoles Maitre et Esclave.
La condition if est vrai puisque que j’ai bien la valeur “Ready” dans les variables (recudumaitre) et (Ready) !??
voici le code

Code du Maitre :

// Maitre Arduino 2560
#include <Wire.h>
const int bp = 2;    // Entrée bp

void setup()
{
Wire.begin();       // Init I2C maître
Serial.begin(9600);  // Init Serie
pinMode(bp, INPUT);  // Bouton poussoir envoie de msg à l'esclave
}

void loop()
{
int etatbp; 
etatbp = digitalRead(bp);
if(etatbp == HIGH)
{EnvoieRecoit();}
}

void EnvoieRecoit()
{ 
Wire.beginTransmission(0x01); // Ouvre la comm avec esclave 0x01
Wire.write("Ready");          // Charge la valeur à envoyer
Wire.endTransmission();       // envoie et ferme la comm avec esclave 0X01
delay(1000);
Wire.requestFrom(0x01, 11);    // recoit le retour de l'esclave, 11 bytes
while(Wire.available())
  {char retour = Wire.read();
   Serial.print(retour);}
Serial.println();
}

Code de l’Esclave :

// Esclave Arduino 2560
#include <Wire.h>
int NByte=0;
char recudumaitre[6];
char Ready[6] = "Ready";
void setup()
{ Wire.begin(0x01); 
  Wire.onReceive(reception);      // fonction de lecture appellée quand un msg du Maitre est arrivé
  Serial.begin(9600);
  Wire.onRequest(requestEvent);   // fonction d'écriture appellée en réponse d'une demande du Maitre
}  

void loop()
{delay(100);}

void reception(int NbByte)
{int i=0;
while(Wire.available() > 0){
     recudumaitre[i] = Wire.read();  // Enregistrement du message du Maitre dans la variable recudumaitre
     Serial.print(recudumaitre[i]);
     i++;}
  Serial.print(" | ");
  Serial.print(NbByte);
  Serial.print(" byte(s)");
  NByte = NbByte;
}

void requestEvent()
{ Serial.print("  |  recudumaitre="); // Envoie dans la console de la valeur stockée dans la variable recudumaitre
  Serial.print(recudumaitre);
  Serial.print("|  Valeur Ready="); // Envoie dans la console de la valeur stockée dans la variable recudumaitre
  Serial.print(Ready);
  Serial.println("|");     
        if(recudumaitre[6] == Ready)
        {Wire.write("Yes Ready !"); }   // Répondre avec un message de 11 octets (bytes)
        else 
        {Wire.write("No Ready  !"); }
}

Console du Maitre :
No Ready !

Console de l’Esclave :
Ready | 5 byte(s) | recudumaitre=Ready| Valeur Ready=Ready|

C'est quoi cette ligne ?

if(recudumaitre[6] == Ready)

Si tu veux comparer les deux strings, utilise la fonction strcmp.