Académique Documents
Professionnel Documents
Culture Documents
TP N° :02
1. Introduction
L’I2C est un protocole de communication qui fut tout d’abord propriétaire (inventé par
Philips) et né de la nécessité d’interfacer de plus en plus de microcontrôleurs. En effet, à ce
moment là une voie série "classique" ne suffisait plus car elle ne pouvait relier que deux à deux
les microcontrôleurs. La particularité de cette liaison est qu’elle transporte son propre signal
d’horloge. Ainsi, la vitesse n’a pas besoin d’être connu d’avance. Les données sont transportées
en même temps que l’horloge grâce à deux fils : SDA (Data) et SCL (Clock). Comme pour
l’USB, la communication se fait sur un système de maître/esclave.[1]
Il peut être pratique, notamment dans des projets de domotique, de communiquer entre
plusieurs appareils. Une des techniques couramment utilisées 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.[4]
N.B. : Il est bon de noter 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)[4]
• Le bus I2C permet de faire communiquer entre eux des composants électroniques très
divers grace à seulement trois fils : Un signal de donnée ( SDA ), un signal d’horloge ( SCL ),
et un signal de référence électrique ( Masse ).
• Les données sont transmises en série à 100Kbits/s en mode standard et jusqu’à 400Kbits/s
en mode rapide.
• chaque périphérique sur le bus I2C est adressable, avec une adresse unique pour chaque
périphérique du bus
Les périphériques utilisant le protocole I2C ont une adresse unique et on communique avec
eux grâce à cette adresse. En outre, I2C permet un contrôle multi-maître.
Avant de commencer la transmission, le bus doit être en repos avec SDA et SCL mis à 1 (ou
HIGH). Ensuite, SDA passe à 0 et SCL garde l’état 1, et après la transmission SDA revient à 1
et SCL garde l’état 1 [1]. Le protocole I2C est basé sur MSBFirst, où il transmet le premier bit
puis le valide en passant SCL à 0 et revient à 1 pour transmettre le bit suivant. A la fin, le maître
transmet un bit d’acquittement 1 et l’esclave répond avec 0 pour signaler la bonne transmission.
La transmission d’une adresse se fait comme la transmission d’une donnée, sauf elle est
codée sur 7 bits et le 8ème bit définit s’il s’agit d’une lecture ou d’une écriture. En outre, après
la transmission de la commande, le maître garde l’état 1 dans l’acquittement jusqu’à la réception
de la donnée de l’esclave en cas d’une lecture de donnée. Puis le remet à 0 pour continuer la
lecture ou à 1 pour mettre fin à la transmission [2].
• Ordinateur
4 TP2 : Gérez plusieurs Arduino avec un bus I2C
• Arduino UNO x2 ou plus
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:
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. [4]
Généralement, une carte va envoyer des informations (Writer) et une autre va les recevoir
(Reader).[4]
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.
• begin()
o Description : Initialise la librairie Wire et se connecte au bus I2C en tant que maître ou
esclave. L’argument de la fonction peut être vide pour les appareils maître Cette instruction
ne doit normalement n’être appelée qu’une seule fois au début du programme.
o Syntaxe :
▪ Wire.begin()
▪ Wire.begin(adresse)
o Paramètres :
▪ addresse : l’adresse 7-bit esclave (optionnel); si non spécifiée, la connexion au
bus se fait en mode maître.
• read()
o Description : Lit un octet qui a été transmis d’un périphérique esclave à un maître après
un appel à requestFrom () ou a été transmis d’un maître à un esclave.
o Syntaxe :
▪ Wire.read ()
o Paramètres : Aucun
• write()
o Description : Cette fonction écrit le paramètre qu’on lui donne (le premier) sur le bus de
communication (permet d’envoyer des bytes). Elle est commune aux deux types de
périphériques .
▪ le maître écrit sur le bus ,fonction utilisée entre beginTransmission()
et endTransmission() .
▪ l’esclave écrit sur le bus mais après requête du maître, il ne peut pas écrire de son
propre chef.
6 TP2 : Gérez plusieurs Arduino avec un bus I2C
o Syntaxe :
▪ Wire.write(value)
▪ Wire.write(string)
▪ Wire.write(data, length)
o Paramètres :
▪ value : une valeur à envoyer en un seul octet .
▪ string : une chaîne à envoyer en tant que série d’octets.
▪ data : un tableau de données à envoyer en octets
▪ length : le nombre d’octets à transmettre
• requestFrom()
o Description : Fonction utilisée par le périphérique maître, elle sert à demander une
information à un esclave (gère la fonction de réception de requête). L’argument de cette
fonction est l’adresse de l’esclave à interroger.
o Syntaxe :
▪ Wire.requestFrom(address, quantity)
▪ Wire.requestFrom(address, quantity, stop)
o Paramètres :
• beginTransmission()
o Description : Cette fonction commence la transmission vers un esclave sur le bus de
communication. L’adresse de ce périphérique doit être passée en argument.
o Syntaxe :
▪ Wire.beginTransmission(adresse)
o Paramètres :
• endTransmission()
o Description : Termine une transmission à un périphérique esclave qui a été commencée
par beginTransmission () et transmet les octets qui ont été mis en file d’attente par write () .
o Syntaxe :
▪ Wire.endTransmission()
▪ Wire.endTransmission(stop)
o Paramètres :
• onRequest()
o Description : Enregistrer une fonction à appeler lorsqu’un maître demande des données
à ce périphérique esclave.
o Syntaxe : Wire.onRequest(handler)
o Paramètres :
• onReceive()
#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.print(" ");
void loop()
{
delay(100);
}
8 TP2 : Gérez plusieurs Arduino avec un bus I2C
Code de la carte « Esclave »[4]
#include <Wire.h>
#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);
}
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 ».
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. [4]
10 TP2 : Gérez plusieurs Arduino avec un bus I2C
#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);
}
11 TP2 : Gérez plusieurs Arduino avec un bus I2C
}
if (nDevices == 0)
Serial.println(F("No I2C devices found\n"));
else
Serial.println(F("done\n"));
Références
[1] ] https://zestedesavoir.com/tutoriels/686/arduino-premiers-pas-en-informatique-embarquee/744_la-
communication-avec-arduino/3426_generalites-sur-la-voie-serie/#3-10740_connexion-serie-entre-arduino-et
[2] Polycopié de Travaux Pratiques Module : Bus de communication et réseaux locaux industriels, Réalisé
par Mr. ABAINIA Kheireddine, Année universitaire 2019/2020
[3] https://www.aranacorp.com/fr/gerez-plusieurs-arduino-avec-un-bus-i2c/
[4] https://www.redohm.fr/2018/02/tutoriel-arduino-communication-i2c-1-maitre-2-esclaves/(14/11/2022)