Das beliebte I2C-Protokoll ermöglicht die Kommunikation zwischen zwei oder mehr Arduino-Boards. Entdecken Sie, wie Sie sie verbinden und codieren können.

Während ein einzelnes Arduino viele Aufgaben erfüllen kann, erfordern einige Projekte möglicherweise die Verwendung von mehr als einem Board, um unterschiedliche Funktionalitäten zu bewältigen. Um die Datenübertragung zwischen den beiden Mikrocontrollern zu ermöglichen, muss also ein Kommunikationsprotokoll wie CAN, SPI, I2C oder UART eingerichtet werden.

In diesem Handbuch behandeln wir die Grundlagen der Funktionsweise von I2C, die Hardwareverbindungen und die Softwareimplementierung, die zum Einrichten von zwei Arduino-Boards als I2C-Master- und -Slave-Geräte erforderlich sind.

Was ist I2C?

Inter-Integrated Circuit (I2C) ist ein weit verbreitetes Kommunikationsprotokoll in eingebetteten Systemen und Mikrocontrollern, um die Datenübertragung zwischen elektronischen Geräten zu ermöglichen. Im Gegensatz zu SPI (Serial Peripheral Interface) können Sie mit I2C mehr als ein Master-Gerät mit einem oder mehreren Slave-Geräten an einen Bus anschließen. Es wurde zuerst von Philips verwendet und ist auch als Kommunikationsprotokoll Two Wire Interface (TWI) bekannt.

instagram viewer

Wie funktioniert die I2C-Kommunikation?

I2C verwendet zwei bidirektionale Leitungen: Serial Data (SDA) und Serial Clock (SCL), um Daten zu übertragen und die Kommunikation zwischen Geräten zu synchronisieren. Jedes an den I2C-Bus angeschlossene Gerät hat eine eindeutige Adresse, die es während der Kommunikation identifiziert. Das I2C-Protokoll ermöglicht es mehreren Geräten, denselben Bus zu teilen, und jedes Gerät kann als Master oder Slave fungieren.

Die Kommunikation wird vom Master-Gerät initiiert, und eine falsche Adressierung von Slave-Geräten kann zu Übertragungsfehlern führen. Sehen Sie sich unseren ausführlichen Leitfaden an wie die serielle UART-, SPI- und I2C-Kommunikation funktioniert um Ihnen einen Kontext zu geben.

Ein nennenswerter Vorteil der I2C-Kommunikation ist die Flexibilität, die sie bei der Energieverwaltung bietet. Geräte, die mit unterschiedlichen Spannungspegeln arbeiten, können mithilfe von Spannungswandlern dennoch effektiv kommunizieren. Dies bedeutet, dass Geräte, die mit 3,3 V betrieben werden, Spannungsumsetzer benötigen, um an einen 5-V-I2C-Bus angeschlossen zu werden.

Die Drahtbibliothek

Die Wire-Bibliothek ist eine integrierte Arduino-Bibliothek, die Funktionen zur Kommunikation über I2C bereitstellt. Es verwendet zwei Pins – SDA und SCL – auf dem Arduino-Board für die I2C-Kommunikation.

I2C-Pins auf dem Arduino Uno:

Arduino Nano I2C-Pins:

Um die Bibliothek verwenden zu können, müssen Sie die Draht.h Header-Datei am Anfang Ihres Arduino-Sketch.

#enthalten

Die Wire-Bibliothek bietet Funktionen zum Initiieren der Kommunikation mit einem I2C-Gerät, zum Senden von Daten und zum Empfangen von Daten. Einige wichtige Funktionen, die Sie kennen sollten, sind:

  • Wire.begin(): Wird verwendet, um dem I2C-Bus beizutreten und die Kommunikation zu initiieren.
  • Wire.beginTransmission(): Wird verwendet, um die Slave-Adresse anzugeben und eine Übertragung zu beginnen.
  • Wire.write (): Wird verwendet, um Daten an das I2C-Gerät zu senden.
  • Wire.endTransmission(): Wird verwendet, um die Übertragung zu beenden und auf Fehler zu prüfen.
  • Wire.requestFrom(): Wird verwendet, um Daten vom I2C-Gerät anzufordern.
  • Wire.verfügbar (): Wird verwendet, um zu prüfen, ob Daten zum Lesen vom I2C-Gerät verfügbar sind.
  • Wire.read(): Wird verwendet, um Daten vom I2C-Gerät zu lesen.

Verwenden Sie die Wire.beginTransmission() Funktion zum Setzen der Adresse des Sensors, die als Argument eingefügt wird. Wenn beispielsweise die Adresse des Sensors lautet 0x68, würden Sie verwenden:

Kabel.beginÜbertragung(0x68);

Arduino I2C-Hardware-Setup

Um zwei Arduino-Boards mit I2C zu verbinden, benötigen Sie die folgenden Hardwarekomponenten:

  • Zwei Arduino-Boards (Master und Slave)
  • Brotschneidebrett
  • Überbrückungsdrähte
  • Zwei 4,7-kΩ-Pull-up-Widerstände

Verbinden Sie die SDA Und SCL Pins beider Arduino-Boards zu einem Steckbrett. Schließen Sie die Pull-up-Widerstände zwischen den an SDA Und SCL Stifte und die 5V Stromschiene auf dem Steckbrett. Verbinden Sie schließlich die beiden Steckbretter mit Jumperdrähten miteinander.

Arduino Uno-Schaltung

Arduino Nano-Schaltung

Bildnachweis: Arduino I2C-Dokumentation

Einrichten der Arduino-Boards als I2C-Master- und Slave-Geräte

Verwenden Sie die Wire.requestFrom() Funktion, um die Adresse des Slave-Geräts anzugeben, mit dem wir kommunizieren möchten. Dann nutzen Sie die Wire.read() Funktion, um Daten vom Slave-Gerät zu erhalten.

Master-Gerätecode:

#enthalten
Leereaufstellen(){
Kabel.Start(); // dem i2c-Bus beitreten
Seriell.Start(9600); // Serien für Ausgabe starten
}
Leereempfange Daten(){
int Adresse = 8;
int bytesToRead = 6;
Kabel.Anfrage von(Adresse, bytesToRead);
während (Kabel.verfügbar()) {
verkohlen Daten = Kabel.lesen();
Seriell.drucken(Daten);
}
Verzögerung(500);
}
LeereSchleife(){
empfange Daten();
}

Der Wire.onReceive() Funktion wird verwendet, um anzugeben, was zu tun ist, wenn der Slave Daten vom Master-Gerät empfängt. Im obigen Code ist die Wire.verfügbar () Funktion prüft, ob Daten verfügbar sind, und die Wire.read() Funktion liest die vom Mastergerät gesendeten Daten.

Slave-Gerätecode:

#enthalten
Leereaufstellen(){
Kabel.Start(8); // dem I2C-Bus mit Adresse 8 beitreten
Kabel.onReceive(Empfangsereignis); //receiveEvent aufrufen, wenn Daten empfangen werden
}
LeereSchleife(){
Verzögerung(100);
}
LeereEmpfangsereignis(int Bytes){
Kabel.schreiben("Hallo "); // mit einer Nachricht von 6 Bytes antworten, wie vom Master erwartet
}

Senden und Empfangen von Daten mit I2C

In diesem Beispiel lesen wir die Temperatur von einem DHT11-Temperatursensor, der mit dem Slave-Arduino verbunden ist, und drucken sie auf dem seriellen Monitor des Master-Arduino aus.

Ändern wir den Code, den wir zuvor geschrieben haben, um die Temperaturmessung einzuschließen, die wir dann über den I2C-Bus an die Hauptplatine senden. Das Masterboard kann dann den von uns gesendeten Wert lesen und ihn dann auf dem seriellen Monitor anzeigen.

Master-Gerätecode:

#enthalten
Leereaufstellen(){
Kabel.Start();
Seriell.Start(9600);
Seriell.println("Master initialisiert!");
}
LeereSchleife(){
Kabel.Anfrage von(8, 1); // Temperaturdaten vom Slave anfordern
Wenn (Kabel.verfügbar()) {
Byte Temperatur = Kabel.lesen(); // Temperaturdaten vom Slave lesen
Seriell.drucken("Temperatur: ");
Seriell.drucken(Temperatur);
Seriell.println(" °C");
}
Verzögerung(2000); // Warten Sie 2 Sekunden, bevor Sie die Temperatur erneut anfordern
}

Slave-Gerätecode:

#enthalten
#enthalten

#definieren DHTPIN 4 // Pin mit DHT-Sensor verbunden
#definieren DHTTYP DHT11 // DHT-Sensortyp
DHT dht(DHTPIN, DHTTYP);
Byte Temperatur;

Leereaufstellen(){
Kabel.Start(8); // Slave-Adresse ist 8
Kabel.auf Anfrage(Anforderungsereignis);
dht.Start();
}

LeereSchleife(){
Verzögerung(2000); // Warten Sie 2 Sekunden, bis sich DHT stabilisiert hat
Temperatur = dht.readTemperature(); // Temperatur vom DHT-Sensor lesen
}

LeereAnfrageEreignis(){
Kabel.schreiben(Temperatur); // Temperaturdaten an Master senden
}

Sie können diesen Code an die Sensoren anpassen, die Sie möglicherweise in Ihrem Projekt haben, oder sogar die Sensorwerte auf einem Anzeigemodul anzeigen Stellen Sie Ihr eigenes Raumthermometer und Feuchtigkeitsmessgerät her.

Slave-Adressierung mit I2C auf Arduino

Um in einem solchen Projekt Werte von Komponenten zu lesen, die einem I2C-Bus hinzugefügt wurden, ist es wichtig, dass Sie beim Codieren die richtige Slave-Adresse angeben. Glücklicherweise bietet Arduino eine Scanner-Bibliothek an, die den Prozess der Identifizierung von Slaves vereinfacht Adressen, wodurch das Durchforsten langer Sensordatenblätter und Verwirren im Internet entfällt Dokumentation.

Verwenden Sie den folgenden Code, um die Adresse eines beliebigen Slave-Geräts auf dem I2C-Bus zu identifizieren.

#enthalten // Binden Sie die Wire-Bibliothek für die I2C-Kommunikation ein

Leereaufstellen(){
Kabel.Start(); // Initialisieren Sie die I2C-Kommunikation
Seriell.Start(9600); // Initialisieren Sie die serielle Kommunikation mit einer Baudrate von 9600
während (!Seriell); // Warten Sie, bis die serielle Verbindung hergestellt ist
Seriell.println("\nI2C-Scanner"); // Eine Nachricht drucken, die den Start des I2C-Scannens anzeigt
}

LeereSchleife(){
Byte Fehler, Adresse; // Variablen zum Speichern von Fehlern und Geräteadressen deklarieren
int nGeräte; // Eine Variable deklarieren, um die Anzahl der gefundenen Geräte zu speichern

Seriell.println("Scannen..."); // Eine Nachricht drucken, die den Start des I2C-Scannens anzeigt

nGeräte = 0; // Setze die Anzahl der gefundenen Geräte auf 0
für (Adresse = 1; Adresse < 127; Adresse++) { // Iteriere über alle möglichen I2C-Adressen
Kabel.beginÜbertragung(Adresse); // Starte eine Übertragung an die aktuelle Adresse
Fehler = Kabel.EndeÜbertragung(); // Beenden Sie die Übertragung und speichern Sie alle Fehler

Wenn (Fehler == 0) { // Wenn keine Fehler gefunden wurden
Seriell.drucken("I2C-Gerät an Adresse 0x gefunden"); // Gibt eine Nachricht aus, die angibt, dass ein Gerät gefunden wurde
Wenn (Adresse < 16) Seriell.drucken("0"); // Wenn die Adresse kleiner als 16 ist, fügen Sie zu Formatierungszwecken eine führende 0 hinzu
Seriell.drucken(Adresse, HEX); // Adresse im Hexadezimalformat drucken
Seriell.println(" !"); // Gibt eine Nachricht aus, die angibt, dass ein Gerät gefunden wurde

nGeräte++; // Erhöhen Sie die Anzahl der gefundenen Geräte
}
andersWenn (Fehler == 4) { // Wenn ein Fehler gefunden wurde
Seriell.drucken("Unbekannter Fehler bei Adresse 0x"); // Eine Meldung ausgeben, die angibt, dass ein Fehler gefunden wurde
Wenn (Adresse < 16) Seriell.drucken("0"); // Wenn die Adresse kleiner als 16 ist, fügen Sie zu Formatierungszwecken eine führende 0 hinzu
Seriell.println(Adresse, HEX); // Adresse im Hexadezimalformat drucken
}
}
Wenn (nGeräte == 0) { // Wenn keine Geräte gefunden wurden
Seriell.println("Keine I2C-Geräte gefunden\n"); // Eine Nachricht ausgeben, die besagt, dass keine Geräte gefunden wurden
}
anders { // Wenn Geräte gefunden wurden
Seriell.println("fertig\n"); // Eine Nachricht drucken, die das Ende des I2C-Scannens anzeigt
}
Verzögerung(5000); // 5 Sekunden verzögern, bevor der nächste Scan gestartet wird
}

Erweitern Sie Ihr Projekt noch heute

Die Verbindung zweier Arduino-Boards über das I2C-Kommunikationsprotokoll bietet eine flexible und effiziente Möglichkeit, komplexe Aufgaben zu lösen, die nicht von einem einzigen Board bewältigt werden können. Mit Hilfe der Wire-Bibliothek wird die Kommunikation zwischen den beiden Boards mit I2C vereinfacht, sodass Sie Ihrem Projekt weitere Komponenten hinzufügen können.