La manière la plus simple de communiquer avec une carte Arduino est d’utiliser le moniteur série. C’est d’ailleurs l’outil le plus puissant pour tester et pour débugger votre programme. La communication série peut aussi servir à échanger des données avec d’autres appareils (Arduino, Raspberry ou autre).
Matériel
- Ordinateur
- Arduino UNO x2
- Jumper cable M/M x3
Communication via le moniteur série
Vous pouvez utiliser le moniteur série, lorsque l’arduino est connecté à l’ordinateur via le port USB. Les fonctions suivantes s’appliquent aussi si vous utilisez les broches (Rx-0,Tx-1) de l’Arduino.
Les fonctions à connaitre sont:
- Serial.begin() permet d’initialiser la vitesse de communication du port. Si cette fonction est mal paramétrée, la communication ne fonctionnera pas
- Serial.print() et Serial.println() permettent d’envoyer des chaînes de caractères (String) sur le port série. La dernière permet de finir l’envoie par un saut de ligne
- Serial.write() permet d’envoyer un byte à la fois.
- Serial.available() permet de vérifier que le port série a reçu des données
- Serial.read() permet de recevoir les données du le port série
Chargez le code suivant pour tester la communication entre l’ordinateur et la carte Arduino.
char cmd; char old_cmd; boolean enable=false; void setup(){ // Initialize serial port Serial.begin(9600); Serial.println("ENTER Commands:"); } void loop(){ old_cmd=cmd; if (Serial.available()){ // Verify that data are available cmd=Serial.read(); // Read data on serial port } if(cmd!=old_cmd){ if(cmd=='O'){ Serial.println("Set to ON"); // Send data to serial port enable=true; }else if(cmd=='F'){ Serial.println("Set to OFF"); // Send data to serial port enable=false; } } if(enable){ Serial.println("System is running"); delay(200); } }
Si vous tapez O puis F dans la barre de commande du moniteur série, ceci devrait s’afficher:
Communication série entre deux Cartes Arduino
Il est possible d’utiliser le port série (Rx0,Tx1) utilisé par le port USB pour communiquer entre deux cartes Arduino. Pour cela, il suffit de relier les broches comme suis
- Arduino 1 Rx -> Arduino 2 Tx
- Arduino 1 Tx -> Arduino 2 Rx
- Arduino 1 GND -> Arduino 2 GND
ATTENTION : Si vous utilisez des cartes différentes, les niveaux de tension peuvent ne pas être compatibles. Dans ce cas, il faut utiliser un convertisseur de tension. Vérifiez bien la documentation de chacune des cartes.
Comme nous l’avons dit, les broches 0 et 1 sont utilisées par le port USB. Pour éviter des conflits avec le moniteur série, nous allons nous intéresser à la librairie SoftwareSerial qui utilise d’autres broches du microcontrôleur. Les exemples suivants sont aussi réalisable avec le port série matériel. Il suffit, pour cela, de remplacer « ArduinoSlave » et « ArduinoMaster » par « Serial » dans les codes suivants.
De manière générale, les techniques sur les échanges de données discutées si-après, sont applicables à toutes communications séries.
Communication entre deux cartes Arduino avec SoftwareSerial
Il est aussi possible de communiquer entre différents systèmes en utilisant le port série. Un exemple intéressant est la communication entre deux cartes Arduino. Pour cela, il nous faut écrire deux programmes, un pour la carte « Maîtresse » (Master) et l’autre pour la carte « Esclave » (Slave).
Un port série est défini par deux pins et une vitesse de communication. La libraire SoftwareSerial.h permet de les définir simplement. Dans cet exemple nous choisissons les pins 2 et 3 (SoftwareSerial ArduinoSlave(2,3); )et une vitesse de communication de 9600bps (ArduinoSlave.begin(9600);).
ATTENTION : Nous utilisons ici, les broches 2 et 3 de l’Arduino UNO. Selon le microcontrôleur utilisé, les broches utilisables pour la communication série peuvent être différentes. Notamment pour les cartes Arduino Mega, Micro, Leonardo. Vérifiez la documentation.
Afin que les deux cartes communiquent entre elles il faut les relier correctement et ne pas oublier de relier les masses (GND) comme indiqué sur le schéma suivant.
Généralement, une carte va envoyer des informations et une autre va les recevoir. Dans notre exemple, pour vérifier que les deux cartes communiquent, la carte « Esclave » renvoie ce qu’elle a reçu de la carte « Maîtresse ».
Ce qui suit reste valable pour toute communication série! Il est possible de transformer cette communication filaire en une communication sans fil avec les modules Bluetooth HC-06 et HC-05.
Code de la carte « Maîtresse »
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); char cmd; char old_cmd; char answer; char old_answer; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ old_cmd=cmd; old_answer=answer; //Read command from monitor if (Serial.available()){ cmd=Serial.read(); } //Read answer from slave if (ArduinoSlave.available()){ answer=ArduinoSlave.read(); } //Send data to slave if(cmd!=old_cmd){ Serial.print("Master sent : "); Serial.println(cmd); ArduinoSlave.write(cmd); } //Send answer to monitor if(answer!=old_answer){ Serial.print("Slave received : "); Serial.println(answer); } }
Code de la carte « Esclave »
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); char cmd; char old_cmd; void setup(){ ArduinoMaster.begin(9600); } void loop(){ old_cmd=cmd; // Read data from master if (ArduinoMaster.available()){ cmd=ArduinoMaster.read(); } // Send answer to master if(cmd!=old_cmd){ ArduinoMaster.write(cmd); } }
Dans le moniteur série de la carte « Maîtresse », tapez la commande que vous voulez vous devriez voir la carte « Esclave » vous répondre comme dans l’image suivante.
Ce code permet d’envoyer un seul byte à la fois. Les caractères sont codé en ASCII. Vérifiez la table ASCII pour vérifier comment recevoir vos données. Certains caractères ne peuvent être envoyé comme le signe degré »° » ou les accents « é », etc.
Jouez avec les données
Dans certains cas, vous aurez besoin d’utiliser d’autres types de données qu’un entier ou un caractère et envoyer plusieurs informations. Une solution qui peut aider dans la plupart des cas est de convertir les données en chaîne de caractères et de les envoyer à l’aide de la fonction print().
Code de la carte Maîtresse
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String msg; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read command from monitor readSerialPort(); //Send data to slave if(msg!=""){ Serial.print("Master sent : "); Serial.println(msg); ArduinoSlave.print(msg); msg=""; } } void readSerialPort(){ while (Serial.available()) { delay(10); if (Serial.available() >0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; //add to String } } Serial.flush(); //clean buffer }
Code de la carte Esclave
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); String msg; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); } void loop(){ readMasterPort(); // Send answer to master if(msg!=""){ ArduinoMaster.print(msg); Serial.print("Master sent : " ); Serial.println(msg); msg=""; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString Serial.println(msg); } } ArduinoMaster.flush(); }
Ce code vous permet d’envoyer tout type ou chaine de caractères.
Une fois que la communication et en place et que les cartes peuvent échanger des données l’important est de savoir quoi en faire.
Envoyer et recevoir la valeur d’un capteur
Un bon exemple d’application est de modifier la luminosité d’une LED branchée sur la carte Esclave à l’aide d’un capteur branché sur la carte Maître. Comme nous récupérons les données sous la forme d’un String il nous faut le convertir en entier. La fonction pour effectuer conversion est atoi(). La valeur de PWM de la led est comprise entre 0 et 255, il faut donc convertir la valeur du capteur, comprise entre 0 et 1023 avec la fonction map().
Code de la carte Maitre pour lire et envoyer la valeur d’un capteur
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String answer; String msg; int intVal=0,oldIntVal=0; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read sensor intVal=analogRead(A0); //Read answer from slave readSlavePort(); //Send data to slave if(oldIntVal!=intVal){ Serial.print("Master sent : "); Serial.println(intVal); ArduinoSlave.print(intVal); oldIntVal=intVal; } //Send answer to monitor if(answer!=""){ Serial.print("Slave LED PWM value : "); Serial.println(answer); answer=""; } delay(1000); } void readSlavePort(){ while (ArduinoSlave.available()) { delay(10); if (ArduinoSlave.available() >0) { char c = ArduinoSlave.read(); //gets one byte from serial buffer answer += c; //makes the string readString } } }
Code de la carte Esclave pour recevoir et utiliser la valeur d’un capteur
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); #define ledPin 11 String msg=""; int ledVal=0; int intVal=0,oldIntVal=0; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); pinMode(ledPin,OUTPUT); } void loop(){ readMasterPort(); convertMsgToCmd(); // Send answer to master if(intVal!=oldIntVal){ Serial.print("Master sent : " ); Serial.println(intVal); ledVal=map(intVal,0,1023,0,255); Serial.print("led value : "); Serial.println(ledVal); ArduinoMaster.print(ledVal); analogWrite(ledPin,ledVal); oldIntVal=intVal; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } ArduinoMaster.flush(); } void convertMsgToCmd(){ if (msg.length() >0) { Serial.print("message length : "); Serial.println(msg.length()); char carray1[6]; //magic needed to convert string to a number msg.toCharArray(carray1, sizeof(carray1)); intVal = atoi(carray1); msg=""; } }
Envoyer et recevoir deux valeurs de capteurs
Pour recevoir des valeurs différentes, l’idée est de définir un séparateur. Dans ce cas, nous utilisons le caractère « x ». Il suffit ensuite de repérer le caractère dans la chaine à l’aide de la fonction indexOf().
Code de la carte Maitre pour envoyer deux valeurs distinctes
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String answer; String msg; int intVal1=0,oldIntVal1=0; int intVal2=0,oldIntVal2=0; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read sensors intVal1=analogRead(A0); intVal2=analogRead(A1); //Send data to slave if(oldIntVal1!=intVal1 || oldIntVal2!=intVal2 ){ Serial.print("Master sent : "); Serial.print(intVal1); Serial.print("x"); Serial.println(intVal2); ArduinoSlave.print(intVal1); ArduinoSlave.print("x"); ArduinoSlave.print(intVal2); oldIntVal1=intVal1; oldIntVal2=intVal2; } delay(1000); //Read answer from slave readSlavePort(); //Send answer to monitor if(answer!=""){ Serial.println("Slave received : "); Serial.println(answer); answer=""; } } void readSerialPort(){ while (Serial.available()) { delay(10); if (Serial.available() >0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } Serial.flush(); } void readSlavePort(){ while (ArduinoSlave.available()) { delay(10); if (ArduinoSlave.available() >0) { char c = ArduinoSlave.read(); //gets one byte from serial buffer answer += c; //makes the string readString } } }
Code de la carte Esclave pour recevoir deux valeurs distinctes
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); String msg="",m1="",m2=""; int num1=-1,num2=-1; int sep; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); } void loop(){ readMasterPort(); convertMsgToMultiCmd(); // Send answer to master if(num1!=-1 && num2!=-1){ Serial.print("Sensor 1 : " ); Serial.println(num1); Serial.print("Sensor 2 : " ); Serial.println(num2); ArduinoMaster.print("Sensor 1 : " ); ArduinoMaster.println(num1); ArduinoMaster.print("Sensor 2 : " ); ArduinoMaster.println(num2); num1=-1; num2=-1; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } ArduinoMaster.flush(); } void convertMsgToMultiCmd(){ if (msg.length() >0) { Serial.print("message length : "); Serial.println(msg.length()); sep = msg.indexOf('x'); //Serial.println(sep); // expect a string like 0x0021 containing the two servo positions m1 = msg.substring(0, sep); //get servo id m2 = msg.substring(sep+1, msg.length()); //get servo pos char carray1[6]; //magic needed to convert string to a number m1.toCharArray(carray1, sizeof(carray1)); num1 = atoi(carray1); char carray2[6]; m2.toCharArray(carray2, sizeof(carray2)); num2 = atoi(carray2); msg=""; } }
Envoyer et recevoir plusieurs données
Il est possible que dans votre application vous ayez besoin d’une multitude de données à échanger entre deux cartes. Dans ce cas il faut modifier un peu la fonction de conversion. Dans notre exemple, nous supposons que nous voulons piloter l’état d’une led, la vitesse et la direction d’un moteur.
Code de la carte Maitre pour envoyer plusieurs données
#include <SoftwareSerial.h> SoftwareSerial ArduinoSlave(2,3); String answer; String msg; int intVal1=0,oldIntVal1=0; int intVal2=0,oldIntVal2=0; void setup(){ Serial.begin(9600); Serial.println("ENTER Commands:"); ArduinoSlave.begin(9600); } void loop(){ //Read command from monitor readSerialPort(); //Read answer from slave readSlavePort(); //Send data to slave if(msg!=""){ Serial.print("Master sent : "); Serial.println(msg); ArduinoSlave.print(msg); msg=""; } //Send answer to monitor if(answer!=""){ Serial.print("Slave received : "); Serial.println(answer); answer=""; } delay(1000); } void readSerialPort(){ while (Serial.available()) { delay(10); if (Serial.available() >0) { char c = Serial.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } Serial.flush(); } void readSlavePort(){ while (ArduinoSlave.available()) { delay(10); if (ArduinoSlave.available() >0) { char c = ArduinoSlave.read(); //gets one byte from serial buffer answer += c; //makes the string readString } } }
Code de la carte Esclave pour recevoir plusieurs données
#include <SoftwareSerial.h> SoftwareSerial ArduinoMaster(2,3); String msg=""; int ledVal=0; int sep; String data[3]; unsigned int data_count=0; void setup(){ Serial.begin(9600); ArduinoMaster.begin(9600); } void loop(){ readMasterPort(); convertMsgToMultiCmd(); //Use data if(data_count==3){ for(int i=0;i<(data_count+1);i++){ switch(i){ case 0: //led status if(data[0]=="ON"){ Serial.println("Switch led ON"); }else if(data[0]=="OFF"){ Serial.println("Switch led OFF"); }else{ Serial.println("Led wrong command"); } break; case 1: //motor PWM Serial.print("Set motor power to : "); Serial.println(stringToInt(data[1])); break; case 2: //motor direction if(data[2]=="forward"){ Serial.println("Motor direction forward"); }else if(data[2]=="backward"){ Serial.println("Motor direction backward"); }else{ Serial.println("Motor wrong command"); } break; } } data_count=0; } } void readMasterPort(){ while (ArduinoMaster.available()) { delay(10); if (ArduinoMaster.available() >0) { char c = ArduinoMaster.read(); //gets one byte from serial buffer msg += c; //makes the string readString } } ArduinoMaster.flush(); } void convertMsgToMultiCmd(){ if (msg.length() >0) { data_count=0; Serial.print("Master sent : "); Serial.println(msg);//Serial.println(msg.length()); do{ sep = msg.indexOf('x'); // expect a string like 0x0021 containing the two servo positions String m1 = msg.substring(0, sep); //get servo id msg = msg.substring(sep+1, msg.length()); //get servo pos data[data_count]=m1; data_count++; } while(sep!=-1); Serial.println("data received : "); for(int i=0;i<(data_count+1);i++) Serial.println(data[i]); msg=""; } } int stringToInt(String s){ char carray1[6]; //magic needed to convert string to a number s.toCharArray(carray1, sizeof(carray1)); return atoi(carray1); }
Une fois que les données sont correctement échangées, il suffit de convertir en entier les grandeurs si besoin et effectuer les actions voulues en fonction des données reçues.
Avec ses connaissances de base, vous pouvez communiquer avec d’autres modules comme des contrôleurs série de servomoteurs, d’autres microcontrôleurs ou encore des modules Bluetooth.
Si vous avez un problème pour établir une communication série avec votre projet ou si vous souhaitez d’autres exemples dans ce tutoriel n’hésitez pas à laisser un commentaire ou à m’envoyer un message.
Applications
- Communiquez avec Arduino et les modules Bluetooth HC-06 et HC-05.
- Créer un moniteur série avec Python
Sources
Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie
Bonjour,
Les codes donnés dans cet article sont très utiles et détaillés. Malheureusement ils donnent presque tous lieu à un échec de compilation pour le motif ‘\stray302 dans ce code’.
observation qu’on n’arrive pas à corriger. Merci
Cordialement
Bonjour,
il semble que ce soit un problème de copier-coller dû au navigateur.
ça devrait être corrigé