Zurück

Meistern Sie Serial, I2C und SPI auf Arduino mit Velxio

Einleitung

Kommunikationsprotokolle sind das Rückgrat eingebetteter Systeme. Ob Sie einen Sensor auslesen, mit einer SD-Karte kommunizieren oder Debug-Nachrichten ausgeben – Sie verwenden eines der drei wichtigsten Protokolle: Serial (UART), I2C (TWI) oder SPI. In diesem Tutorial werden wir alle drei gleichzeitig auf einem Arduino Uno im browserbasierten Velxio-Simulator ausführen. Sie werden sehen, wie man den I2C-Bus scannt, ein EEPROM liest/schreibt, SPI-Übertragungen durchführt und alles über die serielle Schnittstelle protokolliert.

Schaltplan der Multi-Protokoll-Schaltung auf der Velxio-Simulator-Leinwand

Schaltungsdurchlauf

Dieses Beispiel verwendet nur das Arduino Uno-Board selbst – es werden keine externen Komponenten benötigt. Die integrierten Peripheriegeräte des Arduino bieten alles, was wir brauchen:

Es ist keine Verkabelung erforderlich, da alle Verbindungen intern im Arduino erfolgen. Die Velxio-Leinwand zeigt den Uno mit seinen Pin-Beschriftungen, und Sie können die virtuellen Komponenten durch Öffnen der Komponentenauswahl inspizieren.

Velxio Komponentenauswahl-Modal zum Durchsuchen von Teilen nach Kategorie

Code-Durchlauf

Lassen Sie uns den Sketch Schritt für Schritt aufschlüsseln.

Bibliotheken und Definitionen

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

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

Wir binden die Wire-Bibliothek für I2C und die SPI-Bibliothek für SPI ein. Zwei I2C-Adressen werden definiert: 0x68 für eine DS1307 RTC (obwohl nicht physisch vorhanden, werden wir danach scannen) und 0x50 für ein 24Cxx-EEPROM. Der SPI-Slave-Select-Pin wird auf digitalen Pin 10 gesetzt.

Hilfsfunktionen

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);
}

Die Funktion bcdToDec konvertiert binär codierte Dezimalzahlen (BCD) in Dezimalzahlen. readRTC liest die Sekunden, Minuten und Stunden von einer DS1307 RTC. Die Masken & 0x7F und & 0x3F löschen ungenutzte Bits.

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;
}

Diese Funktionen schreiben und lesen ein einzelnes Byte von einem I2C-EEPROM an Adresse 0x50. Die delay(5) stellt sicher, dass das EEPROM Zeit hat, den Schreibzyklus abzuschließen.

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

Diese Funktion führt eine Vollduplex-SPI-Übertragung durch: Sie zieht SS auf LOW, sendet ein Byte, empfängt die Antwort und zieht SS wieder auf HIGH.

Setup

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

  Serial.println("===================================");
  Serial.println(" Multi-Protocol Demo");
  Serial.println(" Serial (USART) + I2C (TWI) + SPI");
  Serial.println("===================================");
  Serial.println();

  // ── I2C: Scan bus ──
  Serial.println("[I2C] Scanning bus...");
  int found = 0;
  for (byte addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print("  Found device at 0x");
      if (addr < 16) Serial.print("0");
      Serial.println(addr, HEX);
      found++;
    }
  }
  Serial.print("  ");
  Serial.print(found);
  Serial.println(" device(s) on I2C bus.");
  Serial.println();

  // ── I2C: Write/read EEPROM ──
  Serial.println("[I2C] EEPROM write/read test:");
  writeEEPROM(0, 42);
  writeEEPROM(1, 99);
  byte v0 = readEEPROM(0);
  byte v1 = readEEPROM(1);
  Serial.print("  Wrote 42, read ");
  Serial.print(v0);
  Serial.println(v0 == 42 ? " [OK]" : " [FAIL]");
  Serial.print("  Wrote 99, read ");
  Serial.print(v1);
  Serial.println(v1 == 99 ? " [OK]" : " [FAIL]");
  Serial.println();

  // ── SPI: Transfer test ──
  Serial.println("[SPI] Transfer test:");
  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("Setup complete. Reading RTC...");
  Serial.println();
}

In setup() initialisieren wir alle drei Protokolle. Dann führen wir folgende Schritte durch:

  1. Den I2C-Bus scannen nach Geräten von Adresse 1 bis 126.
  2. EEPROM testen, indem wir die Werte 42 und 99 an die Adressen 0 und 1 schreiben, sie dann zurücklesen und überprüfen.
  3. SPI testen, indem wir drei Bytes (0xAA, 0x55, 0x42) senden und die empfangenen Bytes ausgeben.

Loop

void loop() {
  // ── Serial: Print RTC time every 2 seconds ──
  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("  |  Uptime: ");
  Serial.print(millis() / 1000);
  Serial.println("s");

  delay(2000);
}

Alle zwei Sekunden liest die Schleife die RTC-Zeit und gibt sie zusammen mit der Systemlaufzeit aus. Dies demonstriert die kontinuierliche serielle Ausgabe, während I2C und SPI im Leerlauf sind.

Schlüsselkonzepte

Häufige Fallstricke & Debugging-Tipps

Vorgeschlagene Erweiterungen

  1. Echte Sensoren hinzufügen: Schließen Sie eine DS1307 RTC und ein 24Cxx-EEPROM an den I2C-Bus sowie ein SD-Kartenmodul über SPI an.
  2. Daten im EEPROM protokollieren: Speichern Sie Sensorwerte und rufen Sie sie nach einem Reset ab.
  3. Interrupts verwenden: Lösen Sie eine SPI-Übertragung durch einen Tastendruck aus.
  4. Eine Befehlsschnittstelle implementieren: Parsen Sie serielle Befehle, um I2C- und SPI-Operationen zu steuern.

Probieren Sie es selbst aus

Bereit, alle drei Protokolle in Aktion zu sehen? Öffnen Sie das Live-Beispiel in Velxio, kompilieren Sie es und führen Sie es aus. Beobachten Sie die Ausgabe des seriellen Monitors, während der Arduino den I2C-Bus scannt, das EEPROM testet, SPI-Übertragungen durchführt und dann kontinuierlich die RTC-Zeit ausgibt.

Starten Sie die Multi-Protokoll-Demo auf Velxio

Velxio Editor-Symbolleiste mit Compile- und Run-Steuerelementen Velxio Leinwand-Symbolleiste über dem Simulations-Viewport

Viel Spaß beim Hacken!


Teilen auf:
David Montero

Geschrieben von

David Montero

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

GitHub velxio.dev

Ähnliche Artikel


Vorheriger Artikel
Eine LED auf dem Raspberry Pi Pico mit dem Velxio Simulator blinken lassen
Nächster Artikel
SPI-Loopback-Test: Meistern Sie das Protokoll mit Velxio