Introduction
Les communications I2C sont devenues la méthode de communication de facto entre les microcontrôleurs, les micro-ordinateurs et une variété de circuits intégrés et de capteurs. Il existe depuis 1982 et a été initialement développé pour être utilisé dans les récepteurs de télévision.
Bien que nous ayons utilisé de nombreux capteurs et affichages I2C dans les articles précédents, nous n’avons pas réellement examiné le fonctionnement de l’I2C et comment il peut être utilisé pour communiquer entre microcontrôleurs.
Aujourd’hui, nous allons corriger cela et en apprendre davantage sur I2C. Nous verrons également comment il peut être utilisé pour échanger des informations entre deux Arduinos et comment il peut être utilisé pour permettre à un Arduino d’en contrôler un autre.
Ce sera le premier de quatre articles sur I2C. Dans les prochains articles, nous verrons comment nous pouvons construire nos propres périphériques I2C, comment interfacer un Raspberry Pi et un Arduino en utilisant I2C et comment faire des configurations I2C avancées, y compris l’utilisation de plusieurs maîtres sur un bus I2C.
Commençons!
Communications I2C
I2C est un protocole série utilisé sur une interface 2 fils à basse vitesse. Il a été développé à l’origine par Phillips en 1982 pour permettre aux circuits intégrés dans les récepteurs de télévision de communiquer entre eux.
Les temps ont changé, Phillips est maintenant NXP et I2C est devenu un standard de communication pris en charge par pratiquement tous les principaux fabricants de semi-conducteurs.
I2C est l’abréviation de « Circuit inter-intégré ». Il est également appelé « IIC » ou « I C au carré ».
Utilisations et limitations
I2C est utilisé avec des microcontrôleurs comme l’Arduino et avec des micro-ordinateurs comme le Raspberry Pi. De nombreux écrans et capteurs s’interfacent avec leur contrôleur hôte à l’aide d’I2C.
I2C a cependant plusieurs limitations. Il n’est pas particulièrement rapide, bien que pour la plupart de ses utilisations prévues, il soit suffisamment rapide.
I2C ne peut être utilisé que sur de courtes distances, après tout, il était à l’origine destiné à communiquer entre des circuits intégrés sur la même carte de circuit imprimé. La distance maximale d’une transmission fiable diminue à mesure que la vitesse augmente, à la vitesse la plus lente (100 Kbaud ou une fréquence d’horloge de 100 kHz), la distance maximale est d’environ un mètre.
Vitesses I2C
Le bus I2C d’origine avait une vitesse maximale de 100 kHz. La plupart des applications courantes utilisent encore cette vitesse, car elle est tout à fait suffisante pour transférer des données à partir de capteurs et vers de simples écrans.
I2C et a des modes de vitesse plus élevés. Tous les périphériques I2C ne prennent pas en charge ces modes :
- Mode rapide – La vitesse d’horloge maximale est de 400 kHz.
- Mode Haute vitesse – Une fréquence d’horloge maximale de 3,4 MHz
- Mode Ultra rapide – Fréquence d’horloge maximale de 5 MHz
Sur un bus I2C, c’est le maître qui détermine la vitesse d’horloge.
Comment fonctionne I2C
Un bus I2C a deux signaux, ainsi qu’une connexion d’alimentation et de masse.
Les deux lignes de signal sont les suivantes:
- SDA – Il s’agit de la ligne de données bidirectionnelle.
- SCL – C’est le signal d’horloge.
Il y a deux résistances de traction attachées à chaque ligne de signal, elles tirent le bus jusqu’à la tension d’alimentation lorsqu’il est inactif.
Notez que la tension d’alimentation n’est pas standard, elle peut être de 3,3 ou 5 volts. Il peut également s’agir d’une tension inférieure pour certaines implémentations I2C à grande vitesse.
Cette différence de tensions d’alimentation peut entraîner des problèmes lorsque vous interfacez des périphériques I2C qui utilisent différents niveaux logiques. Nous en discuterons plus dans un prochain article lorsque je vous montrerai comment interfacer un Raspberry Pi (3.logique 3 volts) avec un Arduino Uno (logique 5 volts).
Il existe deux types de périphériques qui peuvent être interfacés au bus I2C : les maîtres et les esclaves.
Le périphérique maître contrôle le bus et fournit le signal d’horloge. Il demande des données aux esclaves individuellement. Il peut y avoir plus d’un périphérique maître sur le bus, mais un seul peut être le maître actif à un moment donné.
Aucune adresse n’est attribuée aux périphériques maîtres.
Les périphériques esclaves ont une adresse, et cette adresse doit être unique sur le bus. Ils utilisent un schéma d’adressage 7 bits, de sorte que jusqu’à 128 esclaves peuvent être sur un bus I2C. Dans la vraie vie, cette grande collection d’appareils n’est jamais utilisée, il est rare de voir plus d’une douzaine d’appareils I2C sur un bus.
Un schéma d’adressage 10 bits plus récent a été implémenté, il est rétrocompatible avec la méthode d’adressage 7 bits existante.
Les périphériques I2C commerciaux reçoivent une adresse I2C par NXP, qui gère les spécifications du bus. Bien qu’I2C soit open source depuis 2006, des frais sont facturés pour l’obtention d’une adresse esclave auprès de NXP. Aucun frais n’est requis pour les appareils maîtres ou pour les appareils qui ne sont pas destinés à une fabrication commerciale.
Certains périphériques I2C se voient attribuer plusieurs adresses, généralement des variances dans les bits d’adresse inférieurs. Ces périphériques peuvent être configurés manuellement pour différentes adresses, ce qui permet d’utiliser plusieurs périphériques du même type sur un seul bus I2C.
Autres dérivés d’I2C
Il existe d’autres bus dérivés du bus I2C, et qui sont à bien des égards compatibles avec I2C.
- TWI – L’interface à deux fils est pratiquement identique au bus I2C. C’est en fait le bus qu’utilise l’Arduino, TWI a été développé lorsque le bus I2C n’était pas open source et Atmel ne voulait pas risquer une violation du nom commercial. La seule différence majeure entre TWI et I2C est que TWI ne prend pas en charge une technique avancée appelée « étirement de l’horloge”.
- SMBus est un autre bus équivalent à I2C, développé par Intel. Comme TWI, il prend en charge la plupart des fonctionnalités I2C.
Dans un prochain article, je vais expliquer comment les données sur le bus I2C sont structurées. Mais maintenant, nous avons des informations de base sur I2C, suffisantes pour commencer à expérimenter.
Bibliothèque de fils Arduino
L’Arduino dispose d’une bibliothèque intégrée pour travailler avec I2C appelée Bibliothèque de fils. Il facilite la communication sur le bus I2C et peut configurer l’Arduino pour qu’il devienne maître ou esclave.
La bibliothèque de fils a plusieurs fonctions utiles pour travailler avec I2C.
- begin() – Cela initie la bibliothèque et configure l’Arduino pour qu’il soit maître ou esclave.
- requestFrom() – Cette fonction est utilisée par le maître pour demander des données à un esclave.
- beginTransmission() – Cette fonction est utilisée par le maître pour envoyer des données à un esclave spécifié.
- endTransmission() – Cette fonction est utilisée par le maître pour mettre fin à une transmission commencée avec la fonction beginTransmission.
- write() – Utilisé à la fois par le maître et l’esclave pour envoyer des données sur le bus I2C.
- disponible() – Utilisé à la fois par le maître et l’esclave pour déterminer le nombre d’octets dans les données qu’ils reçoivent.
- read() – Lit un octet de données à partir du bus I2C.
- SetClock() – Utilisé par le maître pour définir une fréquence d’horloge spécifique.
- onReceive() – Utilisé par l’esclave pour spécifier une fonction appelée lorsque des données sont reçues du maître.
- onRequest() – Utilisé par l’esclave pour spécifier une fonction appelée lorsque le maître a demandé des données.
Nous utiliserons certaines de ces fonctions dans nos esquisses.
Connexions Arduino I2C
Les connexions SDA et SCL pour I2C sont différentes entre les modèles Arduino. Les expériences que je suis sur le point de vous montrer ont été faites en utilisant deux Arduino Unos, mais vous pouvez utiliser d’autres modèles de l’Arduino à condition de changer les broches en conséquence.
J’ai mis en place un tableau pour vous aider à le comprendre. Il comprend des cartes Arduino courantes, ainsi que quelques-unes des puces discrètes. Les brochages pour les puces que je liste (ATTiny et ATmega328P) sont avec le paquet DIP, pas ceux montés en surface.
Arduino Board or Chip | SDA | SCL |
Uno | A4 | A5 |
Mega2560 | 20 | 21 |
Nano | A4 | A5 |
Pro Mini | A4 | A5 |
Leonardo | 2 | 3 |
Due (has two I2C) | 20 + SDA1 | 20 + SCL1 |
ATTiny85 & ATTiny45 | 5 | 7 |
ATmega328P | 27 | 28 |
Certains clones Arduino Uno ont des broches SDA et SCL séparées et vous pouvez les utiliser à la place des deux broches analogiques si vous le souhaitez. Ils sont connectés en interne au même endroit.
Notez que l’Arduino Due possède en fait deux ports I2C.
Sachez également qu’il existe des diagrammes de branchement incorrects sur Internet pour le Pro Mini. Utilisez les deux broches analogiques, A4 et A5, comme indiqué dans le tableau ci-dessus.
I2C Entre 2 Arduino
Pour notre première expérience, nous allons hoo deux Arduinos ensemble et échanger des données entre eux. Un Arduino sera le maître, l’autre sera l’esclave.
J’utilise deux Arduino Unos, mais vous pouvez remplacer d’autres Arduino si vous n’en avez pas deux. Utilisez le tableau précédent pour les connexions.
Brancher 2 Arduino
Voici comment j’ai connecté mes deux Arduino Unos ensemble:
C’est une connexion assez simple, essentiellement vous attachez simplement le sol et les deux broches I2C ensemble.
Une chose à savoir est que mon diagramme ne montre pas l’utilisation de résistances de traction, j’ai trouvé que tout semblait fonctionner correctement sans elles. Cependant, vous voudrez peut-être les inclure, surtout si vous rencontrez des erreurs ou un fonctionnement intermittent.
Pour brancher des résistances pull-up, attachez quelques résistances 10k aux lignes SDA et SCL. Fixez l’autre extrémité à la sortie 5 volts de l’un des Arduino.
Croquis de démonstration du maître
Voici le croquis qui sera utilisé sur l’Arduino que vous avez désigné comme étant le maître.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
div> 50
51
52
53
|
/*
I2C Master Demo
i2c-master-demo.ino
Demonstrate use of I2C bus
Master sends character and gets reply from Slave
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define Slave answer size
#define ANSWERSIZE 5
void setup() {
// Initialize I2C communications as Master
Wire.begin();
// Configuration du moniteur série
Série.begin(9600);
Série.println(« Démonstration maître I2C »);
}
boucle vide() {
delay(50);
Série.println(« Écrire des données sur l’esclave »);
// Écrire un charatre sur le fil esclave
.beginTransmission(SLAVE_ADDR);
Fil.write(0); Fil
.endTransmission();
Série.println(« Recevoir des données »);
// Lire la réponse de l’esclave
// Lire 5 caractères
Fil.requestFrom(SLAVE_ADDR, ANSWERSIZE);
// Ajouter des caractères à la chaîne
String response= » »;
while(Wire.disponible()) {
char b = Fil.read();
réponse +=b;
}
// Imprimer sur le moniteur série
Série.println(response);
}
|
Comme pour tous les croquis I2C, nous commençons par inclure la bibliothèque de fils.
Ensuite, nous définissons quelques constantes pour représenter l’adresse I2C de l’esclave et le nombre d’octets de données que nous comptons en extraire.
Dans la configuration, nous initialisons les communications I2C en tant que maître. Nous savons que c’est un maître car il n’y a pas de paramètre d’adresse dans la fonction begin. Nous configurons également un moniteur série et y imprimons une ligne de texte.
Maintenant à la boucle.
Nous commençons avec un petit délai, principalement pour ralentir suffisamment les choses afin que nous puissions lire l’affichage sur le moniteur série.
Ensuite, nous utilisons la fonction beginTransmission pour envoyer des données à l’esclave. Dans ce cas, les données que nous envoyons ne sont qu’un chiffre zéro. Nous terminons l’envoi par un appel à la fonction endTransmission.
Ensuite, nous demandons des données à l’esclave en utilisant la fonction requestFrom.
Après cela, nous formulons une chaîne de réponse en lisant les données, un octet à la fois, de l’esclave.
Nous imprimons les détails de ce que nous faisons et des données que nous recevons sur le moniteur série. Et puis nous terminons la boucle et recommençons.
Esquisse de démonstration de l’esclave
Maintenant sur l’esquisse utilisée par l’esclave.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
div> 50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
/*
I2C Slave Demo
i2c-slave-demo.ino
Demonstrate use of I2C bus
Slave receives character from Master and responds
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h >
//Define Slave I2C Address
#define SLAVE_ADDR 9
//Define Slave answer size
# define ANSWERSIZE 5
//Define string with response to Master
String answer= »Hello »;
void setup() {
// Initialise les communications I2C en tant que fil esclave
.begin(SLAVE_ADDR);
// Fonction à exécuter lorsque les données sont demandées au fil maître
.onRequest(requestEvent);
// Fonction à exécuter lorsque les données reçues du fil maître
.Onrecevoir (Recevoir un événement);
// Configuration du moniteur série
Série.begin(9600);
Série.println(« Démonstration de l’esclave I2C »);
}
void receiveEvent() {
// Lecture des données reçues
while(0 < Fil.available()) {
octet x= Fil.read();
}
// Imprimer sur le moniteur série
Série.println(« Receive event »);
}
void requestEvent() {
// Variable d’octet de configuration à la bonne taille
réponse d’octet;
// Formatez la réponse sous forme de tableau
pour (octet i = 0; i <ANSWERSIZE; i++) {
réponse = (octet) réponse.charAt(i);
}
// Renvoie la réponse au fil maître
.write(response, sizeof(response));
// Imprimer sur le moniteur série
Série.println(« Événement de requête »);
}
boucle vide() {
// Délai dans la boucle
delay(50);
}
|
Encore une fois, nous commençons par inclure la bibliothèque de fils. Comme pour l’esquisse précédente, nous définissons également l’adresse I2C de l’esclave, ainsi que le nombre d’octets que nous prévoyons de renvoyer au maître.
Ensuite, nous définissons la chaîne que nous allons renvoyer au maître, dans ce cas juste le mot « Bonjour”. Si vous décidez de changer cela, assurez-vous d’ajuster la constante ANSWERSIZE dans les deux esquisses pour qu’elle soit correcte.
Dans la configuration, nous initialisons la connexion au bus I2C avec une fonction begin. Prenez note de la manière différente dont nous procédons, car il s’agit d’un esclave, nous spécifions l’adresse I2C que nous allons utiliser. En faisant cela, la bibliothèque de fils sait que nous voulons fonctionner en mode esclave.
Maintenant, nous devons définir les noms des fonctions que nous appellerons lorsque deux événements se produiront – une demande de données reçue du maître et des données reçues du maître. Nous configurons et imprimons également sur le moniteur série.
La fonction receiveEvent est appelée lorsque nous recevons des données du maître. Dans cette fonction, nous lisons les données pendant que les données sont disponibles et les affectons à un octet (rappelez-vous, les données seront reçues un octet à la fois).
La fonction requestEvent est appelée chaque fois que nous recevons une demande de données du maître. Nous devons renvoyer notre chaîne « Bonjour » au maître. Comme nous devons envoyer les données un octet à la fois, nous divisons les caractères de « Bonjour” en éléments individuels dans un tableau, puis les envoyons un par un.
Nous signalons tous nos progrès dans les deux fonctions au moniteur série.
La boucle de cette esquisse ajoute simplement un délai, qui correspond à celui utilisé dans l’esquisse principale.
Exécution des esquisses de démonstration
Pour exécuter ces esquisses, vous devez pouvoir afficher le moniteur série sur chaque Arduino. Si vous avez deux ordinateurs avec l’ Arduino Arduino installé, cela le rendra beaucoup plus facile.
Sous Microsoft Windows, il est possible d’ouvrir deux instances de l’ Arduino Arduino. Si cela est fait, vous pouvez afficher les deux moniteurs série côte à côte sur le même écran.
Alternativement, vous pouvez utiliser un ordinateur et alimenter le deuxième Arduino avec sa propre alimentation. Vous devrez commuter l’ordinateur et l’alimentation entre les deux Arduino.En faisant cela, vous pouvez surveiller les deux écrans un par un.
Arduino Remote Utilisant I2C
Dans la prochaine démonstration, nous accrocherons un potentiomètre à l’Arduino maître et une LED à l’esclave. Nous utiliserons le potentiomètre pour contrôler le taux de clignotement de la LED.
Ceci est une autre démonstration simple, vous pouvez vous en inspirer pour créer quelque chose de plus pratique.
Connexion de démonstration à distance
Voici comment cette expérience est mise en place.
Il s’agit essentiellement du même branchement que l’expérience précédente, avec l’ajout du potentiomètre sur le maître et de la LED sur l’esclave.
Notez que la LED de l’esclave a été fixée à la broche 13. Comme l’Arduino Uno a une LED intégrée sur la broche 13, vous pouvez éliminer la LED et sa résistance de chute si vous le souhaitez.
Les remarques sur les résistances de traction s’appliquent également à ce branchement.
Esquisse de démonstration à distance
L’esquisse du côté maître de cette expérience est très simple, à certains égards, le côté I2C est encore plus simple que celui utilisé dans la première démonstration. En effet, nous envoyons simplement des données à l’esclave et ne nous attendons pas à en récupérer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/*
I2C Master Control Demo
i2c-master-demo-control.ino
Demonstrate use of I2C bus
Master sends potentimeter position data
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Analog pin for potentiometer
int analogPin = 0;
// Integer to hold potentiometer value
int val = 0;
void setup() {
// Initialise les communications I2C en tant que fil maître
.begin();
}
void loop() {
delay(50);
// Lire la valeur du pot
// Mapper sur une plage de 1 à 255 pour la vitesse de flash
val = map(analogRead(analogPin), 0, 1023, 255, 1);
// Écrire un charatre sur le fil esclave
.beginTransmission(SLAVE_ADDR);
Fil.write(val); Fil
.endTransmission();
}
|
Comme toujours, nous devons inclure la bibliothèque de fils au début de l’esquisse. Nous allons également définir une constante pour contenir l’adresse esclave.
Comme nous utilisons un potentiomètre, nous devrons définir à la fois la broche à laquelle il est connecté et une variable pour maintenir sa valeur.
Tout ce que nous faisons dans la configuration est d’initialiser la connexion I2C en tant que maître.
Dans la boucle, nous lisons la valeur du potentiomètre et la mappons à une plage de 01-255. Nous devons le faire car nous envoyons un octet d’informations et ne pouvons contenir que autant de valeurs dans un seul octet.
Notez que nous inversons la séquence de numérotation dans la fonction Carte Arduino, ceci est fait pour que le système se comporte comme nous l’attendons – tourner le potentiomètre vers la droite augmente le taux de flash. Comme le « taux de flash » est spécifié par un délai, un plus grand nombre envoyé équivaut à un taux de flash plus long.
Notez également que nous n’envoyons pas la valeur 0, qui maintiendrait simplement la LED à un état. Nous définissons notre plage pour qu’elle se termine à 1 à la place.
Maintenant, il s’agit juste d’envoyer l’octet à l’esclave et de répéter la boucle à nouveau.
Croquis de réception de démonstration à distance
Le côté esclave doit recevoir des données du maître et les utiliser pour faire clignoter la LED.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
div> 50
51
52
53
54
55
56
57
58
59
60
|
/*
Démo de contrôle esclave I2C
i2c-slave-demo-control.ino
Demonstrate use of I2C bus
Receives potentimeter position data
Controls LED blink rate
DroneBot Workshop 2019
https://dronebotworkshop.com
*/
// Include Arduino Wire library for I2C
#include <Wire.h>
// Define Slave I2C Address
#define SLAVE_ADDR 9
// Define LED Pin
int LED = 13;
// Variable for received data
int rd;
// Variable for blink rate
int br;
void setup() {
pinMode(LED, SORTIE);
// Initialise les communications I2C en tant que fil esclave
.begin(SLAVE_ADDR);
// Fonction à exécuter lorsque les données reçues du fil maître
.onReceive(receiveEvent);
// Configuration du moniteur série
Série.begin(9600);
Série.println(« Démonstration de l’esclave I2C »);
}
void receiveEvent() {
// lit un caractère du fil I2C
rd=.read();
// Valeur d’impression des données entrantes
Série.println (rd);
}
boucle vide() {
delay(50);
//Calculer la valeur de clignotement
br = map(rd, 1, 255, 100, 2000);
digitalWrite(LED, HAUT);
delay(br);
digitalWrite(LED, BAS);
delay(br);
}
|
Nous commençons avec l’inclusion habituelle de la bibliothèque de fils, ainsi que la définition de l’adresse esclave. Nous définissons également une broche pour la LED.
Quelques variables supplémentaires sont définies, l’une contenant les données reçues tandis que l’autre porte la valeur de retard du taux de clignotement.
Dans la configuration, nous définissons la broche d’E / S de la LED comme sortie et initialisons le bus I2C. Comme nous utilisons l’adresse esclave dans la fonction begin, la bibliothèque de fils sait que nous agissons en tant qu’esclave.
Il suffit de définir une fonction onReceive, contrairement à la dernière démo, nous n’attendons aucune demande du maître. Nous configurons et imprimons également sur le moniteur série, nous utiliserons le moniteur pour afficher les données entrantes.
La fonction receiveEvent lit les données entrantes et les affecte à la variable I. Il imprime également la valeur sur le moniteur série.
Enfin, dans la boucle, nous utilisons les données entrantes pour clignoter la LED. Encore une fois, nous utilisons la fonction de carte pour accomplir cela, en changeant les valeurs entrantes de 1-255 à une plage plus large. Vous pouvez expérimenter en modifiant cette plage pour que la LED clignote plus rapidement ou plus lentement si vous le souhaitez.
Les dernières déclarations sont essentiellement le croquis Arduino Blink déguisé! Nous allumons et éteignons la LED pendant une période que nous avons déterminée à la dernière étape.
Et puis on répète la boucle.
Exécution de la démo à distance
Chargez le code et alimentez les deux Arduino.Vous pouvez utiliser votre moniteur série sur l’Arduino esclave pour afficher les données entrantes.
Tourner le potentiomètre devrait maintenant faire varier le taux de clignotement de la LED sur l’esclave.
Conclusion
Ceci conclut notre premier regard détaillé sur I2C. Dans la prochaine tranche, nous en apprendrons plus sur la structure des données échangées. Nous allons également prendre un capteur ordinaire et le transformer en capteur I2C.
Bonne communication !
Ressources
Croquis – Tous les croquis I2C utilisés dans cet article.
Informations I2C – Informations concernant le protocole I2C