Retour

Maîtrisez Serial, I2C et SPI sur Arduino avec Velxio

Introduction

Les protocoles de communication sont le pilier des systèmes embarqués. Que vous lisiez un capteur, dialoguiez avec une carte SD ou imprimiez des messages de débogage, vous utilisez l’un des trois protocoles majeurs : Serial (UART), I2C (TWI) ou SPI. Dans ce tutoriel, nous allons exécuter les trois simultanément sur un Arduino Uno en utilisant le simulateur en ligne Velxio. Vous verrez comment balayer le bus I2C, lire/écrire une EEPROM, effectuer des transferts SPI et journaliser le tout via Serial.

Schéma du circuit multi-protocole sur le canevas du simulateur Velxio

Présentation du circuit

Cet exemple utilise uniquement la carte Arduino Uno elle-même — aucun composant externe n’est nécessaire. Les périphériques intégrés de l’Arduino fournissent tout ce dont nous avons besoin :

Aucun câblage n’est nécessaire car toutes les connexions sont internes à l’Arduino. Le canevas Velxio affiche l’Uno avec ses étiquettes de broches, et vous pouvez inspecter les composants virtuels en ouvrant le sélecteur de composants.

Fenêtre modale du sélecteur de composants Velxio parcourant les pièces par catégorie

Explication du code

Décortiquons le sketch étape par étape.

Bibliothèques et définitions

#include <Wire.h>
#include <SPI.h>

#define DS1307_ADDR 0x68
#define EEPROM_ADDR 0x50
#define SS_PIN 10

Nous incluons la bibliothèque Wire pour I2C et la bibliothèque SPI pour SPI. Deux adresses I2C sont définies : 0x68 pour un RTC DS1307 (bien que non présent physiquement, nous allons le rechercher) et 0x50 pour une EEPROM 24Cxx. La broche de sélection esclave SPI est définie sur la broche numérique 10.

Fonctions auxiliaires

byte bcdToDec(byte val) {
  return ((val >> 4) * 10) + (val & 0x0F);
}

void readRTC(byte &hr, byte &min, byte &sec) {
  Wire.beginTransmission(DS1307_ADDR);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDR, 3);
  sec = bcdToDec(Wire.read() & 0x7F);
  min = bcdToDec(Wire.read());
  hr  = bcdToDec(Wire.read() & 0x3F);
}

La fonction bcdToDec convertit le décimal codé en binaire (BCD) en décimal. readRTC lit les secondes, minutes et heures d’un RTC DS1307. Les masques & 0x7F et & 0x3F effacent les bits inutilisés.

void writeEEPROM(byte reg, byte value) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write(reg);
  Wire.write(value);
  Wire.endTransmission();
  delay(5);
}

byte readEEPROM(byte reg) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(EEPROM_ADDR, 1);
  return Wire.available() ? Wire.read() : 0xFF;
}

Ces fonctions écrivent et lisent un seul octet depuis une EEPROM I2C à l’adresse 0x50. Le delay(5) garantit que l’EEPROM a le temps de terminer le cycle d’écriture.

byte spiTransfer(byte data) {
  digitalWrite(SS_PIN, LOW);
  byte result = SPI.transfer(data);
  digitalWrite(SS_PIN, HIGH);
  return result;
}

Cette fonction effectue un transfert SPI full-duplex : elle abaisse SS, envoie un octet, reçoit la réponse et remonte SS.

Setup

void setup() {
  Serial.begin(9600);
  Wire.begin();
  pinMode(SS_PIN, OUTPUT);
  digitalWrite(SS_PIN, HIGH);
  SPI.begin();

  Serial.println("===================================");
  Serial.println(" Démo Multi-Protocole");
  Serial.println(" Serial (USART) + I2C (TWI) + SPI");
  Serial.println("===================================");
  Serial.println();

  // ── I2C : Balayage du bus ──
  Serial.println("[I2C] Balayage du bus...");
  int found = 0;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("  Périphérique trouvé à 0x");
      if (addr < 16) Serial.print("0");
      Serial.println(addr, HEX);
      found++;
    }
  }
  Serial.print("  ");
  Serial.print(found);
  Serial.println(" périphérique(s) sur le bus I2C.");
  Serial.println();

  // ── I2C : Écriture/lecture EEPROM ──
  Serial.println("[I2C] Test d'écriture/lecture EEPROM :");
  writeEEPROM(0, 42);
  writeEEPROM(1, 99);
  byte v0 = readEEPROM(0);
  byte v1 = readEEPROM(1);
  Serial.print("  Écrit 42, lu ");
  Serial.print(v0);
  Serial.println(v0 == 42 ? " [OK]" : " [ÉCHEC]");
  Serial.print("  Écrit 99, lu ");
  Serial.print(v1);
  Serial.println(v1 == 99 ? " [OK]" : " [ÉCHEC]");
  Serial.println();

  // ── SPI : Test de transfert ──
  Serial.println("[SPI] Test de transfert :");
  byte spiData[] = {0xAA, 0x55, 0x42};
  for (int i = 0; i < 3; i++) {
    byte rx = spiTransfer(spiData[i]);
    Serial.print("  TX=0x");
    if (spiData[i] < 16) Serial.print("0");
    Serial.print(spiData[i], HEX);
    Serial.print(" RX=0x");
    if (rx < 16) Serial.print("0");
    Serial.println(rx, HEX);
  }
  Serial.println();

  Serial.println("Configuration terminée. Lecture du RTC...");
  Serial.println();
}

Dans setup(), nous initialisons les trois protocoles. Ensuite nous :

  1. Balayons le bus I2C pour les périphériques des adresses 1 à 126.
  2. Testons l’EEPROM en écrivant les valeurs 42 et 99 aux adresses 0 et 1, puis en les relisant et en vérifiant.
  3. Testons le SPI en envoyant trois octets (0xAA, 0x55, 0x42) et en affichant les octets reçus.

Loop

void loop() {
  // ── Serial : Affichage de l'heure RTC toutes les 2 secondes ──
  byte hr, min, sec;
  readRTC(hr, min, sec);

  Serial.print("[RTC] ");
  if (hr < 10) Serial.print("0");
  Serial.print(hr);
  Serial.print(":");
  if (min < 10) Serial.print("0");
  Serial.print(min);
  Serial.print(":");
  if (sec < 10) Serial.print("0");
  Serial.print(sec);

  Serial.print("  |  Temps de fonctionnement : ");
  Serial.print(millis() / 1000);
  Serial.println("s");

  delay(2000);
}

Toutes les deux secondes, la boucle lit l’heure RTC et l’affiche avec le temps de fonctionnement du système. Cela démontre une sortie Serial continue pendant que I2C et SPI sont inactifs.

Concepts clés

Pièges courants et conseils de débogage

Extensions suggérées

  1. Ajouter de vrais capteurs : Connectez un RTC DS1307 et une EEPROM 24Cxx au bus I2C, et un module carte SD via SPI.
  2. Journaliser des données dans l’EEPROM : Stockez les lectures des capteurs et récupérez-les après une réinitialisation.
  3. Utiliser des interruptions : Déclenchez un transfert SPI sur une pression de bouton.
  4. Implémenter une interface de commandes : Analysez les commandes Serial pour contrôler les opérations I2C et SPI.

Essayez par vous-même

Prêt à voir les trois protocoles en action ? Ouvrez l’exemple en direct dans Velxio, compilez et exécutez. Observez la sortie du moniteur série pendant que l’Arduino balaie le bus I2C, teste l’EEPROM, effectue des transferts SPI, puis affiche en continu l’heure RTC.

Lancer la démo Multi-Protocole sur Velxio

Barre d'outils de l'éditeur Velxio avec les contrôles de compilation et d'exécution Barre d'outils du canevas Velxio au-dessus de la fenêtre de simulation

Bon bricolage !


Partager sur :
David Montero

Écrit par

David Montero

Creator of Velxio, the open-source circuit and Arduino simulator.

GitHub velxio.dev

Articles liés


Article précédent
Faire clignoter une LED sur Raspberry Pi Pico avec le simulateur Velxio
Article suivant
Test de boucle SPI : Maîtrisez le protocole avec Velxio