Débuter avec le bus I2C sur Arduino ESP8266 ESP32. Librairie Wire.h • Domotique et objets connectés à faire soi-même

Le bus I2C est très utilisé pour récupérer des mesures ou piloter des équipements sur les projets Arduino, ESP32, ESP8266 et Raspberry Pi à l’aide de la librairie standard Wire.h. Le bus I2C est un bus de communication série mis au point par Philips à partir de 1982 qui permet à deux appareils (ou plus) de communiquer. Plus précisément, c’est un bus de données série synchrone bidirectionnel half-duplex. Les appareils connectés au bus peuvent agir en tant qu’équipement principal – c’est à dire l’appareil qui «contrôle» le bus – ou secondaire. 

Dans cet article, nous allons aborder le principe de fonctionnement de la librairie Wire.h qui permet de faire communiquer simplement des Arduino entre eux. Par contre nous aborderons pas le fonctionnement technique du bus I2C qui est déjà très bien expliqué sur cette page Wikipedia.

Présentation rapide du bus I2C

Le bus I2C est donc une amélioration de la communication série destinée à faire communiquer des accessoires domotiques développé à partir des années 1980 par Philipps. La plupart du temps le bus I2C est constitué d’un équipement principal et un ou plusieurs équipements secondaires, mais la norme permet des organisations plus complexes.

Le bus I2C ne nécessite que deux lignes de communication (fils) pour connecter les appareils entre eux :

  • SDA (Serial Data Line), ligne de données bidirectionnelle,
  • SCL (Serial Clock Line), ligne d’horloge de synchronisation bidirectionnelle. Le signal est généré uniquement par l’équipement principal

D’un point de vue électrique, tous les équipements doivent être connectés à la même masse électrique GND.

Les deux lignes doivent être connectées à une tension de référence (Vdd) via des résistances pull-up.

Voici un exemple de réseau I2C. Un Arduino Uno constitue l’équipement principal du réseau. Deux équipements secondaires sont connectés au bus I2C. A l’adresse 0x76 est connecté un capteur BME280. A l’adresse 0x5A se trouve un capteur d’intensité lumineuse BH1750FVI.

Le nombre maximum d’équipements est limité par le nombre d’adresses disponibles. Comme l’adressage des périphériques est constitué par un mot de 7 bits, on pourra adresser jusqu’à 128 périphériques (27). Le nombre de périphériques I2C dépend également de la qualité du circuit (sa capacité) ainsi que de la vitesse de transmission désirée.

Cinq vitesses de transmission sont possibles :

  • Standard mode (Sm)  ≤ 100 kbit/s
  • Fast mode (Fm)  ≤ 400 kbit/s
  • Fast plus mode (Fm+) ≤ 1 Mbit/s
  • High-speed mode (Hs-mode) ≤ 3,4 Mbit/s
  • Ultra-fast mode (UFm) ≤ 5 Mbit/s, unidirectionnel uniquement.

La vitesse maximale est imposée par le fabricant. La plupart du temps, la vitesse est inférieure à 1 Mbit/s, en général elle se situe entre 100 et 400 kbit/s pour les capteurs.

Les adresses I2C

Chaque équipement secondaire dispose donc d’une adresse unique qui prend la forme d’une chaîne hexadécimale, par exemple 0x69.

Cette adresse est attribuée par le fabricant du composant. Il n’existe pas de norme mais les fabricants s’organisent pour ne pas utiliser une adresse déjà utilisée par un composant existant. En général, une adresse I2C secondaire est disponible. Elle est attribuable par programmation (rarement) ou en modifiant le circuit (à l’aide d’un jumper à souder ou en appliquant une tension pré-définie).

Voici deux exemples

Pour attribuer l’adresse i2c 0x77, il faut souder un jumper entre les deux broches de droite et couper la piste entre les deux broches de gauche Pour attribuer l’adresse 0x5C, il faut appliquer une tension supérieur à 0,7V sur la broche ADDR

En cas de doute sur l’adresse I2C du breakout, vous pouvez consulter cette liste des modules les plus courant pour les projets Arduino, ESP32, ESP8266 et Raspberry Pi

A LIRE AUSSI :

Adresses I2C des capteurs et actionneurs les plus courants

Broches i2c par défaut des cartes de développement les plus courantes

Il est possible d’attribuer manuellement par programmation (nous verrons comment au prochain paragraphe) les broches du bus I2C. La plupart des fabricants de cartes de développements (Arduino, ESP32, ESP8266, STM32, Raspberry Pi…) exposent les broches I2C standards.

Voici la liste des broches par défaut des cartes de développement les plus courantes

SDA SCL SDA1 SCL1
Bus principal Bus secondaire
Uno* A4 A5
Ethernet A4 A5
Mega2560 20 21
Leonardo 2 3
Due 20 21 SDA1 SCL1
ESP8266 D1 D2
ESP32 DevkitC v4 21 22 Utilisateur Utilisateur
ESP32 (anciennes générations) IO21 IO22 Utilisateur Utilisateur
STM32 PB7 ou PB9 PB6 ou PB8 PB11 PB10
Raspberry Pi (toute génération) 3 5    

(*) Ne pas utiliser les broches repérées SDA et SCL sur l’Arduino Uno.

Présentation de la librairie Wire.h pour Arduino, ESP32 et ESP8266

Le bus i2c est pris en charge par la librairie Wire.h qui a également été portée sur ESP32 et ESP8266.

C’est une librairie standard qui ne nécessite aucune installation complémentaire. La version dédiée aux ESP32 et ESP8266 est installée en même temps que le SDK.

Pour utiliser le bus I2C dans un projet Arduino, il suffit déclarer la librairie wire en début de code.

#include 

On initialise le bus i2c à l’aide de la méthode Wire.begin(adresse).

Sur Arduino, les broches ne sont pas spécifiées, la librairie utilise les broches par défaut pour la carte de développement ciblée. L’adresse correspond à l’adresse que l’on désire attribuer à l’équipement secondaire. On utilisera par exemple ce paramètre lorsqu’on développe un réseau I2C entre plusieurs Arduino. Nous verrons deux exemples juste après.

Wire.begin();

Les modules I2C du commerce disposent d’une librairie qui s’occupe de récupérer les données ce qui facilite grandement de travail de développement puisqu’on n’a pas à s’occuper du décodage des paquets envoyés.

Il est toutefois possible d’utiliser la librairie Wire.h pour développer notre propre protocole de communication entre deux (ou plus) Arduino (ou tout autre micro-contrôleurs d’ailleurs)

Pour faire simple, la librairie Wire.h dispose de 4 méthodes principales. Toutes les méthodes sont détaillées ici.

Wire.beginTransmission(adresse_i2c) permet de démarrer un envoi de données vers l’équipement dont l’adresse est passée en paramètre.

Wire.write(donnees_a_envoyer) permet d’envoyer une donnée vers l’équipement spécifié auparavant. Plusieurs formats de données sont supportés par la librairie

Wire.write(value) une valeur à envoyer sur un octet (byte)

Wire.write(string) une chaîne à envoyer sous forme de série d’octets (byte). La conversion d’une chaîne de caractère en byte est gérée par la librairie

Wire.write(data, length)

  • data un tableau d’octets (bytes)
  • length le nombre d’octets à transmettre

Wire.endTransmission() permet de fermer la communication avec l’équipement

Nous verrons d’autres méthodes utiles dans les exemples suivants

Limitations de la librairie Wire.h pour les cartes Arduino

Pour les cartes Arduino, la méthode Wire.begin() permet de spécifier manuellement l’adresse d’un équipement. Par contre, on ne pourra pas spécifier manuellement les broches SDA et SCL.

Wire.begin(0x09);

Limitations de la librairie Wire.h pour ESP32 et ESP8266

L’adaptation de la librairie Wire.h pour les cartes de développement ESP32 et ESP8266 ne permet pas d’attribuer une adresse à un équipement secondaire. On ne pourra donc pas créer un réseau I2C pour faire communiquer plusieurs ESP32 ou ESP8266 ensembles.

Par contre, on peut spécifier les broches SDA et SCL. Ici par exemple on attribue manuellement les broches 21 (SDA) et 22 (SCL) au bus I2C en appelant la méthode comme ceci Wire.begin(broche_sda,broche_scl).

Wire.begin(21,22);

En résumé

Arduino ESP32 / ESP8266
Attribuer une adresse à un équipement secondaire sur le réseau I2C Oui Non
Créer un réseau I2C Oui Non
Attribuer les broches SDA et SCL Non Oui
Piloter et récupérer des données d’équipements I2C Oui Oui

Scanner I2C compatible Arduino, ESP32 et ESP8266

La plupart du temps, on utilisera le bus I2C pour communiquer avec des capteurs prêt à l’emploi (breakout).

L’adresse I2C des modules les plus courant sont répertoriées dans cet article

A LIRE AUSSI :

Adresses I2C des capteurs et actionneurs les plus courants

Si vous ne trouvez pas l’adresse I2C de votre composant ou que vous rencontrez des problèmes de communication, voici le code source d’un scanner I2C compatible Arduino, ESP32 et ESP8266.

#include 
#include 

#define DISPLAY_ERROR false 
#define LOOP_DELAY    10000
#define USER_PIN      false

// Personnaliser les broches du bus I2C pour ESP8266 ou ESP32 
// Customize I2C bus pins for ESP8266 or ESP32
const int PIN_SCL = D1;
const int PIN_SDA = D2;

String I2Ctest() {
  byte error, address;
  int nDevices;
  String s;
 
  s="Scanning...n";
 
  nDevices = 0;
  for(address = 1; address < 127; address++ ) {  
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0) {
      s+="I2C device found at 0x";
      if (address 0 ) {
      if ( DISPLAY_ERROR ) {
        s+="Unknow error at 0x";
        if (address