Communication serie entre arduino... plantage

Bonjour à tous,

j'aimerai connecter 2 cartes arduino ensemble via la liaison série mais dès les liaisons électriques,
il ne se passe rien... alors que les cartes sont sensées s'envoyer en permanence des infos, les TX/RX ne clignotent pas...
Mais si je retire les RX/TX çà fonctionne correctement! J'ai bien croisé Rx/Tx et la masse est bien reliée entre elles.
Pour mes essais, je fais çà entre une uno et une méga, mais le projet final devrait se faire avec une Pro/Mini et une nano.

Mon projet est d'envoyer l'info provenant de 12 boutons poussoirs (carte du bas) à l'autre carte arduino (carte du haut), qui elle est reliée à des relais, et que celle-ci renvoie l'info vers les BP pour allumer les leds intégrées aux BP.
Il est à noter que le cablage est déjà existant mais pas pour autant de BP; d'ou mon passage via liaison série...

Question :
Les dels (Leds) Tx et Rx sont-elle commandées par le microcontrôleur qui gère la liaison série ou par le circuit qui fait l'interface entre l'USB et Tx et Rx.
Réponse :
Si tu regardes le fichier joint, tu verras que les dels sont commandées par l'atmega8U2 qui fait l'interface USB/Série
arduino-uno-schematic.pdf (32,7 Ko)
Donc si tu n'utilises pas cette interface les dels ne peuvent pas être allumée.

Arduino, c'est nom de marque, ce n'est pas un modèle de carte.
Des cartes arduino il en existe plus de 20 modèles différents avec environ 5 à 10 microcontrôleurs différents.

Il faut être plus précis dans la description de son matériel parce que les solutions ne seront pas forcément les mêmes.
C'est qui est demandé dans le message épinglé en tête de forum.

Bonjour arnaud7380

Pourrais-tu mettre le code des 2 Arduino en ligne?

A+
Cordialement
jpbbricole

Ah effectivement pour les leds tx/rx je n'avais jamais fait attention. Je pensais qu'elles étaient directement mises sur la liaison. Merci d'avoir attiré mon attention sur ce fait :wink:

Pour le matériel, j'ai précisé que je faisais mes essais avec une Uno et une Méga. Je n'avais rien d'autre en stock à part des Due :sweat_smile:

Voici le code du bas (arduino uno (essai)) avec MCP23017:

[code]
//############  SETUP  #####################
void setup() {
  Serial.begin(9600);
  delay(100);

//Detecte si le mcp est présent
  Wire.begin();
  Wire.beginTransmission (32);
  if(Wire.endTransmission () == 0) { 
    Serial.println("MCP OK");   
    etat_mcp = HIGH;
  } else {
    Serial.println("MCP PAS OK"); 
    etat_mcp = LOW;      
  }
  Wire.endTransmission();
  
  mcp.begin();     //Demarre le MCP
  delay(100);
      
  for(byte i = 0; i<6; i++) { //INIT LES ENTREES
    pinMode(i+8, INPUT_PULLUP); 
    pinMode(i+2, OUTPUT);         
    if(etat_mcp) {
      mcp.pinMode(i+2, INPUT);  //2 à 7 
      mcp.pullUp(i+2, HIGH);    // turn on a 100K pullup internally 
      mcp.pinMode(i+8, OUTPUT);        //13 à 8
    }
  }
   
  delay(100);
  
  for(byte i = 0; i<6; i++) {   //ETEINT LES LEDS
    digitalWrite(i+2, HIGH);
    if(etat_mcp)  mcp.digitalWrite(i+8, HIGH);
  } 
   
  Serial.println("Cuisine bas");
  delay(100); 

  etat_serie = HIGH;

}


//#############  PROGRAMME PRINCIPAL  ##################
void loop() {
  lire_serie();

if(etat_serie) {  
//LECTURE DES BOUTONS
  for(byte i = 0; i<6; i++) {
    if(!digitalRead(i + 8)) {   //Si HIGH = pas pressé
      BP[i] = HIGH;
    } else {
      BP[i] = LOW; 
    }
    if(etat_mcp) {
      if(!mcp.digitalRead(i + 2)) {   //Si HIGH = pas pressé
        BP_mcp[i] = HIGH;
      } else {
        BP_mcp[i] = LOW; 
      }
    }       
  }
  
//ENVOI CHAINE SERIE  
  if(millis() - temps >= 500 || change_bp) { //Envoi la chaine toute les 250ms ou si changement sur BP
    Serial.print("A");
    for(byte i = 0; i<6; i++) { 
      Serial.print(BP[i]); 
    }
    Serial.println("E");
    Serial.print("B");
    for(byte i = 0; i<6; i++) { 
      Serial.print(BP_mcp[i]); 
    }
    Serial.println("N");
    change_bp = LOW;
    temps = millis();
  }//fin millis 500  
}//fin etat série

if(millis() - temps_etat >= 500 && (!etat_serie ||! etat_mcp)) { //Fait clignoter le(s) témoins en cas defaut
  cli = !cli;
  if(!etat_serie) digitalWrite(2, cli);
  if(!etat_mcp)   digitalWrite(3, cli); 
  temps_etat =  millis();  
}

  
}//fin loop

//################# LECTURE SERIE ####################
void lire_serie() {          //Sous-routine avec un paramètre
//  Serial.println("lecture serie");
  if(Serial.available() > 0) {     //Teste si des caractères sont reçus sur le port série par defaut
    char SerialData0;              //Variable tampon pour stocker le caractère reçu
    SerialData0 = Serial.read();   //Lire un caractère (un Byte)
  if(SerialData0==13){             //Si c'est <CarriageReturn> --> execute la commande
    traitementserie();
  } else {                         //Sinon, ajoute le caractère à la variable tampon
  buffer_rx += String(SerialData0);
  }
 }
}//Fin sous-routine lecture Serie
//################# TRAITEMENT SERIE ################
void traitementserie() {    //A2
//  Serial.print("TS traitement serie de "); 
//  Serial.println(buffer_rx);
  String temp_serie;
  String chiffre;
   
  temp_serie = buffer_rx.substring(0,1);    //Extrait la première lettre de la chaine serie recue   

//REception de la demande de connexion
  if(temp_serie = "D") {   
    etat_serie = HIGH;
    digitalWrite(2, HIGH);
  }

//Ecriture LED (info depuis série par l'autre carte)  
  if(temp_serie = "R") {   //Retour de l'info des BP/ relais
    erreur_serie = 0; //Reset le compteur d'erreur
    temp_serie = buffer_rx.substring(1,2);    //Extrait la deuxième lettre de la chaine serie recue   
    if(temp_serie == "A") {      //arduino: RA123456E
      for(byte i = 2; i < 8; i++) {
        chiffre = buffer_rx.substring(i,i+1);  
        int conv_chiffre = chiffre.toInt();    //on converti STRING en INT
        digitalWrite(i, !conv_chiffre);    
      }
    }    
    if(temp_serie == "M") {      //mcp: RM123456N   
      for(byte i = 2; i< 8; i++) {
        chiffre = buffer_rx.substring(i,i+1);  
        int conv_chiffre = chiffre.toInt();    //on converti STRING en INT
        mcp.digitalWrite(map(i, 2, 7, 13, 8), !conv_chiffre);   //13 to 8   
      }    
    }   
  }
  
  Serial.flush();  
  buffer_rx ="";
}//fin trait serie
[/code]

Et le code du haut (arduino mega (essai):

[code]
//############  SETUP  #####################
void setup() {
  Serial.begin(9600);
  delay(100);

for(byte i = 0; i<12; i++) {    //INIT LES SORTIES
  pinMode(relais[i], OUTPUT);
}
pinMode(led_etat, OUTPUT);      //Etat série
pinMode(led_erreur, OUTPUT);    //Erreur série
pinMode(led_mcp, OUTPUT);       //Erreur mcp 

Serial.println("Cuisine haut");

etat_serie = 2;
}//fin setup


//#############  PROGRAMME PRINCIPAL  ##################
void loop() {
//Verif connection serie  
if(etat_serie == 0) {
  Serial.println("D");      //Demarrage envoi carte bas
  etat_serie = 1;
}
if(etat_serie == 1 && millis() - temps >= 2000 && essai <= 10) {
  Serial.println("D");      //Demarrage envoi carte bas 
  essai += 1; 
  temps = millis();
}
if(etat_serie == 1 && essai >= 11) {      //echec réponsé série
  Serial.println("Pas de reponse de l autre carte");
  etat_serie = 3;
  digitalWrite(led_erreur, HIGH);  
}
//fin verif connection serie

  lire_serie();

if(etat_serie == 2) { //Ecriture relais
  if(millis() - temps >= 250) {
    for(byte i=0; i<12; i++) {  
      if(lock[i] == LOW && etat_relais[i] == HIGH && old_relais[i] == LOW) { //Enclenche le relais
  //      Serial.println("ici 1");
        old_relais[i] = HIGH;
        digitalWrite(i+2, HIGH);
        lock[i] = HIGH;
      }   
      if(lock[i] == LOW && etat_relais[i] == HIGH && old_relais[i] == HIGH) { //coupe le relais
  //      Serial.println("ici 0");
        old_relais[i] = LOW;
        digitalWrite(i+2, LOW); 
        lock[i] = HIGH;     
      }
      if(lock[i] == HIGH && etat_relais[i] == LOW) {                          //on a relaché le BP
        lock[i] = LOW;  
      }
    }//fin for

  Serial.print("RA");
  for(byte i=0; i<6; i++) {  
    Serial.print(etat_relais[i]);  
  }
  Serial.println("");
  Serial.print("RM");
  for(byte i=6; i<12; i++) {
    if(!etat_mcp) {   //mcp ok
      Serial.print(etat_relais[i]);         
    } else {      //echec mcp
      Serial.print(2);  
    }
  } 
  Serial.println("");
  temps = millis();
  }// fin millis - temps
} else {//fin etat serie = 2
  if(millis() - temps >= 500) {
    cli = !cli;
    digitalWrite(led_etat, cli);
    temps = millis(); 
  } 
}

//delay(500);
}//fin loop

//################# LECTURE SERIE ####################
void lire_serie() {          //Sous-routine avec un paramètre
  if(Serial.available() > 0) {     //Teste si des caractères sont reçus sur le port série par defaut
    char SerialData0;              //Variable tampon pour stocker le caractère reçu
    SerialData0 = Serial.read();   //Lire un caractère (un Byte)
  if(SerialData0==13){             //Si c'est <CarriageReturn> --> execute la commande
    traitementserie();
  } else {                         //Sinon, ajoute le caractère à la variable tampon
  buffer_rx += String(SerialData0);
  }
 }
}//Fin sous-routine lecture Serie
//################# TRAITEMENT SERIE ################
void traitementserie() {    //A2
//  Serial.print("TS traitement serie de "); 
//  Serial.println(buffer_rx);
  String lettre_serie;
  String chiffre;
   
  lettre_serie = buffer_rx.substring(0,1);    //Extrait la première lettre de la chaine serie recue

//Lecture BP (info depuis série par l'autre carte)  
  if(lettre_serie == "A") {      //arduino: A123456E
    for(byte i = 1; i < 7; i++) {
      chiffre = buffer_rx.substring(i,i+1);  
      int conv_chiffre = chiffre.toInt();    //on converti STRING en INT
      etat_relais[i-1] = conv_chiffre;    
    } 
  }    
  if(lettre_serie == "B") {      //mcp: B123456N   
    for(byte i = 1; i< 7; i++) {
      chiffre = buffer_rx.substring(i,i+1);  
      int conv_chiffre = chiffre.toInt();    //on converti STRING en INT
      if(conv_chiffre == 2) {     //Echec du MCP
        Serial.println("Echec du MCP");
        etat_mcp = HIGH;
        digitalWrite(led_mcp, HIGH);
        digitalWrite(relais[i+7], LOW);     //désactive relais en cas d'echec mcp   
      } else {
        etat_mcp = LOW;
        digitalWrite(led_mcp, LOW);   
        etat_relais[i+5] = conv_chiffre; 
      }        
    }    
  }
  if(etat_serie == 1 && (lettre_serie == "A" || lettre_serie == "B")) { //liaison série demarrée !
    etat_serie = 2;  
    digitalWrite(led_etat, HIGH);
  }


  Serial.flush();  
  buffer_rx ="";
}//fin trait serie
[/code]

A priori le code ne semble pas complet, dans le premier programme Wire n'est pas défini et dans le deuxième buffer_rx ne l'est pas non plus.
Il manque aussi le schéma de branchement entre les deux Arduino.

Quand on a un problème, il est souvent bon de tester les éléments un par un avant de tout assembler. Si c'est la liaison série qui ne fonctionne pas, seuls ceux qui ont un MCP23017 peuvent t'aider. Si tu ne teste que la liaison série, même sans MCP23017, on peut faire les essais.

La liaison série Serial est en partie utilisée par la console. Pour faire des essais, il est plus facile de prendre une autre liaison, ce qui permet de garder la console. Sur la Uno, il faut en prendre une logicielle.

La réception des informations n'exploite pas le fait que la trame de données contient des séparateurs connus (D, R, A, B, CR).
Du coup rien ne garanti que le premier caractère dans buffer_rx sera bien l'un des caractères attendu.
Ceci dit étant donné que l'on sort sur la réception de CR et que l'émission du message est relativement courte par rapport à sa recurrence et au temps de traitement on peut espérer que le système se synchronise tout seul.

Il y a aussi des trucs comme ça qui traînent, ça doit pas aider

if(temp_serie = "R")

Dans le second code, temps semble être utilisé avant d'avoir été initialisé.

Bonsoir arnaud7380
C'est difficile de débugger un programme qui utilise le même port série que la console.
Le mieux pour développer est d'utiliser un autre port du Mega et SoftwareSerial sur le Uno.
Mais comme tes entrées sont sont sur bus I2c, pourquoi ne pas avoir qu'un Arduino qui fait tout, quelle est la distance entre les 2 machines?

Cordialement
jpbbricole

Effectivement, je n'ai pas mis les variables...
Bas:

//###########  Declaration librairies  #############
#include <Wire.h>               //Bibliothèque i2c
#include "Adafruit_MCP23017.h"

//###########  Definition Variables E/S #############
//const byte NC = 0;          //[ ] NC
//const byte NC = 1;          //[ ] NC
//const byte BP_in[] = {8,9,10,11,12,13};  //[E] Bouton poussoir 1 à 6
//const byte LED_out[] = {2,3,4,5,6,7};    //[S] LED 1 à 6
//const byte BP_mcp_in[] = {2,3,4,5,6,7};          //[E] Bouton poussoir 1 à 6
//const byte LED_mcp_out[] = {13,12,11,10,9,8};   //[S] LED 1 à 6

 

//##########  Variables  ###################
boolean etat_serie; //Etat série entre les 2 cartes
boolean etat_mcp;   //Etat du mcp
boolean BP[6];      //Etat BP
boolean BP_mcp[6];  //Etat BP du MCP
boolean old_BP[6];      //Etat BP
boolean old_BP_mcp[6];  //Etat BP du MCP
boolean change_bp;   
boolean change_led;  
boolean cli;        //Temoin de clignotement en cas de défaut
byte erreur_serie;  //Comptage du nombre de reception en x sec

unsigned long temps;//Stocke le temps
unsigned long temps_etat;//Stocke le temps
unsigned long temps_serie;//Stocke le temps

//** Autres **


//*** Nécessaire pour USB ***
String buffer_rx;             //Tampon reception serie


//*****    Setup Divers ******



//***** Initialisation Shields, sondes,... *****
Adafruit_MCP23017 mcp;

Haut:

//###########  Declaration librairies  #############
#include <Wire.h>               //Bibliothèque i2c


//###########  Definition Variables E/S #############
//const byte NC = 0;            //[ ] NC
//const byte NC = 1;            //[ ] NC
const byte relais[] = {2,3,4,5,6,7,8,9,10,11,12,13};     //[S] Relais sorties
const byte led_etat = 14;       //[S] Etat série
const byte led_erreur = 15;     //[S] Erreur série
const byte led_mcp = 16;        //[S] Erreur mcp 


//##########  Variables  ###################
boolean etat_relais[12];
boolean old_relais[12];
boolean lock[12];
byte etat_serie;
byte essai;
boolean etat_mcp;
boolean cli;

//** Autres **
unsigned long temps_serie;        //Comptage temps série
unsigned long temps;        //Comptage temps 

//*** Nécessaire pour USB ***
String buffer_rx;             //Tampon reception serie

Ben justement, c'est çà qui est bizarre. J'ai testé chaque carte avec le terminal série du soft arduino. Les données envoyées par la carte sont correctes, et lorsque je tape ma chaine dans le terminal et que je l'envoi à l'arduino, il réagit correctement...

En fait la carte du bas (celle avec le mcp) envoie 2 chaines successives à celle du haut:
A123456E
B123456E
La chaine A, représente l'état des boutons poussoirs directement connectés à l'arduino, où 1-6 (le bouton) est soit 0 soit 1; et la chaine B, les BP du MCP.
La carte du haut, répond aussi par 2 chaines:
RA123456E
RM123456E
Qui représente l'état des relais sur la carte haut, et qui allume les leds des bp sur la carte du bas. La chaine A, les leds reliées sur l'arduino et la B, celles sur le MCP.

Ouuuh, je progresse!

Je me suis servi du serial1 de la mega pour connecter la uno, libérant ainsi le serial pour le PC et j'ai pu constater que les chaines séries sont bien reçues mais qu'elles commencaient par un carriage return. J'ai utilisé la fonction trim() pour nettoyer çà, et maintenant çà commence à fonctionner.

Il me reste à faire pareil sur la uno pour le retour d'info. Je pense que çà doit être le même problème.

OK c'est bon, çà fonctionne!
Grace à la fonction trim()

Merci à vous pour l'aide :wink: