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
Ne fonctionne pas avec trois cartes ou plus….
Bonjour, le protocole I2C fonctionne pourtant pour plusieurs cartes (j’ai testé jusqu’à 5 esclaves). Qu’avez-vous essayé?
bonjour,
je suis en train de réaliser une petite machine.
pour ce faire j’ai besoin de deux arduino. Par manque de place et pour gain d’argent je shouaite utiliser que le microcontroller (ATMEGA328). es ce que le protocole I2C fonctionnerais?
Oui, le protocole I2C est présent sur le microcontrôleur. Il faut vérifier l’électronique à rajouter pour que le bus fonction correctement (résistance pullup, pulldown, etc.)
Bonjour,
existe il un tuto en vidéo qui détails plus la mise en œuvre de cette méthode.
j’étais sur le point d’investir dans une dizaine de shield Ethernet quand je suis tomber par hasard sur cette article qui pourrais me simplifier énormément la vie.
Je dois faire communiquer environ 3 uno et 8 nano.
Bonjour, je n’ai pas encore eu le temps de faire des tuto vidéo sur ces différents sujets. De quels genres de détails avez-vous besoin?
Il suffit de relier les différentes cartes par 3 fils comme indiqué sur le schéma et donner à chaque carte esclave une adresse différente.
Ce qu’il faut retenir:
– il ne peut y avoir qu’un seul maître
– la communication I2C n’est pas faite pour de longues distances.
Bonjour,
J’ai besoin de connecter 240 pins issus d’interrupteurs REED pour mon projet, c-a-d que je dois acheter 5/6 ARDUINO MEGA pour avoir le nombre suffisant de pins. Cette méthode présentée peut-elle donc faire communiquer toutes ces cartes entre elles pour récupérer les informations DISTINCTS de mes REED sur le pc ? (Information individuelle par interrupteur REED).
Merci d’avance pour votre réponse.
C’est une solution appropriée. Une solution peut-être plus simple et moins coûteuse serait d’utiliser des registres à décalage ou des multiplexeurs afin d’augmenter le nombre d’entrée de la carte Arduino.
bonjour,
une matrice de 16 x 16 serai peut être une solution plus simple
si la distance dépasse 1m, et j’ai besoin de faire la communication entre les cartes. Quelles est donc la solution?
Il y a la possibilité d’utiliser:
Ça dépend de la distance et des obstacles entre deux cartes
n’y a t’il pas un moyen d’intégrer un protocole de communication pour le cryptage des données?
Qu’entendez-vous par cryptage? pour quel objectif?
Sans le code sous les yeux, il est difficile de savoir à quoi servent les données envoyées.
Mais il est possible de modifier les données avant envoie et après réception avec une clé de cryptage contenu dans le code.
Aussi pour une communication avec des modules de communication distants le code ci-dessus est toujours valides?
Les modules de communication distants(bluetooth, RF, Wifi, lora, ethernet) utilisent généralement des protocoles différents (i.e communication série) donc des codes différents.
Sauf si le module uitlisé communique via I2C avec la carte Arduino
Bonjour, je voudrais savoir s’il vous plait, je veux faire communiquer deux cartes Arduino Uno chacune reliée avec LoRa pour une communication Radio.
Dans ma première carte Arduino Uno, j’ai relié un capteur et un Gps plus le module LoRa
Dans ma deuxième carte Arduino il y’aura que le module LoRa qui est relié avec cette dernière,
Ma question est : est ce que je dois brancher tous les composants comme d’habitude (sans i2c) et les cartes Arduino avec le branchement i2c ? ou bien dés le départ avec tout les composants je travaille avec I2C ? car je ne sais pas quel composant est Master et quel est le Slave ?
j’espère avoir une réponse
Merci
Bonjour,
quel module Lora utilisez-vous?
Si les cartes Arduino communiquent via LoRa, il n’y a normalement pas besoin de les connecter en I2C
bonjour monsieur,
j’ai besion de piloter un cnc par grbl, je veux utiliser arduino mega pour grbl avec ramp 1.4 , est ce que c ‘est possible de faire la communication avec une autre carte arduino ? merci d’avance
Bonjour, vous souhaitez faire la communication entre quelles cartes?