Croisement obligatoire
TX d’un appareil se connecte au RX de l’autre, et inversement. Un câblage TX→TX ne fonctionne pas.
Les bus de communication
Découvrir les trois bus série les plus courants en électronique embarquée et savoir lequel choisir selon le cas d'usage.
Pré-requis :
Un microcontrôleur est rarement seul : il pilote un écran, interroge un capteur de température, échange avec un module Bluetooth. Encore faut-il que tous ces composants se comprennent - qu’ils parlent la même langue.
Ces langages communs, ce sont les bus de communication. Comme des humains, les composants ont plusieurs façons de discuter : à deux dans un couloir (UART), en petit groupe où chacun répond à son nom (I2C), ou par une ligne dédiée très rapide (SPI). Ce concept présente ces trois « dialectes » et t’aide à choisir le bon.
À la fin de ce concept, tu sauras :
Relier chaque périphérique au CPU par une broche dédiée serait impraticable : un écran 240×240 nécessiterait des milliers de fils. Les bus de communication permettent de transmettre des données sur un petit nombre de fils en les envoyant bit par bit ou octet par octet.
graph LR
CPU["ESP32-S3"] -->|"2 fils"| I2C["Capteur I2C"]
CPU -->|"4 fils"| SPI["Écran SPI"]
CPU -->|"2 fils"| UART["PC / GPS / Bluetooth"]
UART est le bus le plus simple : deux fils, point à point (une liaison directe entre deux appareils seulement), sans horloge partagée.
| Fil | Rôle |
|---|---|
| TX | Transmission (sortie du µC) |
| RX | Réception (entrée du µC) |
La vitesse est fixée à l’avance des deux côtés (baud rate, en bits/s). Valeur standard : 115 200 baud.
flowchart LR
subgraph ESP[ESP32-S3]
ETX[TX]
ERX[RX]
end
subgraph PER[Périphérique]
PRX[RX]
PTX[TX]
end
ETX -->|données| PRX
PTX -->|données| ERX
Sans horloge partagée, comment le récepteur sait-il quand lire ? Par convention : la ligne est au repos à HIGH, et chaque octet est encadré de bits de synchronisation.
LOW) annonce le début ;HIGH).C’est ce que résume la notation 8N1 : 8 bits de données, No parité, 1 bit de stop. Les deux extrémités doivent partager exactement le même format et la même vitesse, sinon les octets sont mal découpés.
Serial.begin(115200); // initialise UART0 (USB)
Serial.println("Hello !"); // envoie une ligne
int v = analogRead(A0);
Serial.println(v); // affiche la valeur dans le moniteur série
I2C relie plusieurs périphériques sur seulement 2 fils grâce à un système d’adressage.
| Fil | Rôle |
|---|---|
| SDA | Données (bidirectionnel) |
| SCL | Horloge (générée par le maître) |
Chaque composant I2C possède une adresse 7 bits unique (ex : 0x3C pour un écran OLED SSD1306). Le maître (l’appareil qui dirige les échanges - ici l’ESP32-S3) initie toujours la communication ; les autres, les esclaves, ne répondent que lorsqu’il les sollicite.
graph LR
M["ESP32-S3\n(Maître)"] -->|"SDA + SCL"| C1["Capteur 0x40"]
M -->|"même bus"| C2["OLED 0x3C"]
M -->|"même bus"| C3["RTC 0x68"]
Un échange I2C suit toujours le même rituel, orchestré par le maître :
C’est ce système d’accusé de réception qui permet au scanner d’adresses (plus bas) de savoir « qui est là ».
| Mode | Vitesse |
|---|---|
| Standard | 100 kHz |
| Fast | 400 kHz |
| Fast+ | 1 MHz |
#include <Wire.h>
Wire.begin(SDA_PIN, SCL_PIN); // démarre I2C
// Les bibliothèques de capteurs utilisent Wire en arrière-plan
Les lignes SDA et SCL sont en open-drain (voir GPIO & monde numérique) : les composants ne peuvent que tirer la ligne vers LOW ou la relâcher. Il faut donc deux résistances de pull-up (typiquement 4,7 kΩ) reliant SDA et SCL au 3,3 V - sans elles, le bus reste bloqué et rien ne communique.
On ne connaît pas toujours l’adresse d’un composant. Un petit programme balaie toutes les adresses possibles et affiche celles qui répondent :
#include <Wire.h>
void setup() {
Wire.begin(SDA_PIN, SCL_PIN);
Serial.begin(115200);
for (byte adr = 1; adr < 127; adr++) {
Wire.beginTransmission(adr);
if (Wire.endTransmission() == 0) { // 0 = un composant a répondu
Serial.printf("Trouvé à 0x%02X\n", adr);
}
}
}
void loop() {}
C’est le premier réflexe de débogage quand un capteur I2C « ne répond pas ».
SPI est le bus le plus rapide des trois. Il utilise 4 fils et une logique maître/esclave.
| Fil | Rôle |
|---|---|
| MOSI | Master Out Slave In (données vers le périphérique) |
| MISO | Master In Slave Out (données depuis le périphérique) |
| SCK | Horloge (générée par le maître) |
| CS | Chip Select - sélectionne l’esclave actif (1 fil par esclave) |
La transmission est synchrone (l’horloge SCK cadence chaque bit) et full-duplex (MOSI et MISO actifs simultanément).
graph LR
M["ESP32-S3"] -->|"MOSI + SCK"| E1["Écran TFT"]
M -->|"MOSI + SCK"| E2["Carte SD"]
E1 -->|"MISO"| M
E2 -->|"MISO"| M
M -->|"CS1"| E1
M -->|"CS2"| E2
De quelques MHz à 80 MHz sur ESP32-S3 - bien plus rapide que I2C.
#include <SPI.h>
SPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);
En pratique, la bibliothèque TFT_eSPI gère entièrement SPI pour l’écran - tu n’as pas à appeler SPI.begin() manuellement.
| Critère | UART | I2C | SPI |
|---|---|---|---|
| Fils | 2 | 2 | 4+ |
| Vitesse | ~1 Mbit/s | 100 k–1 Mbit/s | 10–80 Mbit/s |
| Multi-périphériques | Non (point à point) | Oui (adressage) | Oui (CS par esclave) |
| Full-duplex | Non | Non | Oui |
| Complexité | Faible | Moyenne | Moyenne |
| Usage type | Debug, modules | Capteurs, OLED | Écrans, SD |
flowchart TD
A["Quel périphérique ?"] --> B{"Besoin de vitesse élevée ?"}
B -->|Oui| C["SPI\n(écran, SD)"]
B -->|Non| D{"Plusieurs composants\nsur peu de fils ?"}
D -->|Oui| E["I2C\n(capteurs, OLED)"]
D -->|Non| F["UART\n(debug, GPS, BT)"]
1. Combien de fils pour l’UART, l’I2C et le SPI ?
2. Pourquoi faut-il des pull-ups sur un bus I2C ?
3. Quel bus choisir pour un écran TFT rapide ?
8N1) ; un échange I2C = start → adresse+R/W → ACK → données → stop.