Il peut être pratique, notamment dans des projets de domotique, de communiquer entre plusieurs appareils. Une des techniques couramment utilisée est le protocole I2C (ou TWI). Le protocole I2C est une méthode qui permet de connecter plusieurs cartes « Maîtres » et plusieurs cartes « Esclaves » et de faire communiquer jusqu’à 128 appareils. Elle permet des connexions asynchrones entre plusieurs composants pour partager des informations via un « bus commun ». Nous avions vu la communication via le port Série (dit UART) qui est utilisée pour envoyer le code à l’Arduino par un ordinateur ou pour connecter deux appareils notamment en Bluetooth.
N.B.: Il est bon de noté que la communication I2C est prévue, au départ, pour de la communication carte à carte. De ce fait, elle n’est pas adaptée pour la communication sur de longues distances (>1m)
Matériel
- Ordinateur
- Arduino UNO x2 ou plus
- Jumper cable M/M x3 fois le nombre de carte
Schéma de connexion du bus I2C entre cartes Arduino
Avec le protocole I2C, il est aussi possible de communiquer entre différents systèmes (capteurs, écran LCD, Raspberry Pi, etc.). Un exemple intéressant est la communication entre plusieurs cartes Arduino. Pour cela, il nous faut écrire au moins deux programmes, un pour la carte « Maîtresse » (Master) et l’autre pour les cartes « Esclaves » (Slaves).
Une communication I2C est défini par un bus de deux fils (parfois appelé TWI, Two Wire Interface) et une adresse. Les broches utilisées par la communication I2C sont généralement fixé pour chaque appareil. L’une sur laquelle sont envoyées les données (SDA Serial Data Line) et sur l’autre l’horloge de synchronisation (SLC Serial Clock Line).
Broches I2C/TWI:
- Uno, Ethernet A4 (SDA), A5 (SCL)
- Mega2560 20 (SDA), 21 (SCL)
- Leonardo 2 (SDA), 3 (SCL)
- Due 20 (SDA), 21 (SCL), SDA1, SCL1
Dans cet exemple nous utilisons une carte Arduino Uno, donc, les broches A4 et A5.
Afin que les deux cartes communiquent entre elles il faut les relier correctement (A4 avec A4 et A5 avec A5) et ne pas oublier de relier les masses (GND) comme indiqué sur le schéma suivant.
Attention : Si les broches A4 et A5 sont reliées aux broches d’une carte non alimentée, le code se figera au moment de la transmission.
Généralement, une carte va envoyer des informations (Writer) et une autre va les recevoir (Reader).
Code de configuration du bus I2C
La libraire Wire.h permet de les définir simplement la communication série sur le bus I2C. Les fonctions sont similaires à la librairie Serial.
- Wire.begin() permet d’initialiser l’adresse de l’appareil. L’argument de la fonction peut être vide pour les appareils maître
- Wire.write() permet d’envoyer des bytes.
- Wire.requestFrom() gère la fonction de réception de requête
- Wire.beginTransmission() débute la transmission de donnée et définit le récepteur.
- Wire.endTransmission termine la transmission de donnée
- Wire.onRequest() gère la fonction de réception de requête
- Wire.onRecieve() gère la fonction de réception de donnée
Code de la carte « Maîtresse »
#include <Wire.h> # define I2C_SLAVE1_ADDRESS 11 # define I2C_SLAVE2_ADDRESS 12 #define PAYLOAD_SIZE 2 int n=0; void setup() { Wire.begin(); Serial.begin(9600); Serial.println(F("-------------------------------------I am the Master")); delay(1000); //Request value of n to slave Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1); n = Wire.read(); Serial.print(F("recieved value : ")); Serial.println(n); //Send value 12 to slave Wire.beginTransmission(I2C_SLAVE1_ADDRESS); Wire.write(12); Serial.print(F("sending value : ")); Serial.println(12); Wire.endTransmission(); Serial.print(" "); //Request value of n to slave after change Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1); n = Wire.read(); Serial.print(F(" new recieved value : ")); Serial.println(n); } void loop() { delay(100); }
Code de la carte « Esclave »
#include <Wire.h> # define I2C_SLAVE_ADDRESS 11 // 12 pour l'esclave 2 et ainsi de suite #define PAYLOAD_SIZE 2 void setup() { Wire.begin(I2C_SLAVE_ADDRESS); Serial.begin(9600); Serial.println("-------------------------------------I am Slave1"); delay(1000); Wire.onRequest(requestEvents); Wire.onReceive(receiveEvents); } void loop(){} int n = 0; void requestEvents() { Serial.println(F("---> recieved request")); Serial.print(F("sending value : ")); Serial.println(n); Wire.write(n); } void receiveEvents(int numBytes) { Serial.println(F("---> recieved events")); n = Wire.read(); Serial.print(numBytes); Serial.println(F("bytes recieved")); Serial.print(F("recieved value : ")); Serial.println(n); }
Ouvrez le moniteur série des cartes esclaves avant le moniteur de la carte maître.
Dans le moniteur série de la carte « Maîtresse »:
Dans le moniteur série de la carte « Esclave 1 »:
Nous pouvons voir que les deux cartes échangent des informations. Il est très facile d’étendre cet exemple à plusieurs cartes Arduino (Leonardo, Mini, etc.) en adaptant le câblage et l’adresse du composants dans le code « Esclave ».
Code pour identifier les périphériques branchés sur le bus I2C
Un bon test pour savoir si vos appareils communiquent bien entre eux est d’utiliser le code ci-dessous (I2CScanner) qui retourne toutes les adresses des appareils branchés à la carte Maîtresse.
#include <Wire.h> void setup() { Wire.begin(); Serial.begin(9600); while (!Serial); // Leonardo: wait for serial monitor Serial.println(F("\nI2C Scanner")); } void loop() { byte error, address; int nDevices; Serial.println(F("Scanning...")); nDevices = 0; for(address = 1; address < 127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address<16) Serial.print("0"); Serial.print(address,HEX); Serial.println(" !"); nDevices++; } else if (error==4) { Serial.print("Unknown error at address 0x"); if (address<16) Serial.print("0"); Serial.println(address,HEX); } } if (nDevices == 0) Serial.println(F("No I2C devices found\n")); else Serial.println(F("done\n")); delay(5000); // wait 5 seconds for next scan }
Si vous avez des difficultés pour mettre en place une communication I2C entre différents appareils n’hésitez pas à nous laisser un commentaire ou à nous contacter.
Sources
- La référence sur la librairie Wire d’Arduino
- Note sur le concept I2C Master Writer et Master Reader
Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie