- Was ist das I2C-Kommunikationsprotokoll?
- Wie funktioniert I2C-Kommunikation?
- Wo kann ich die I2C-Kommunikation nutzen?
- I2C in Arduino
- Erforderliche Komponenten
- Schaltplan
- Arbeitserklärung
- I2C-Programmierung in Arduino
- Erklärung zur Master-Arduino-Programmierung
- Erklärung zur Slave-Arduino-Programmierung
In unserem vorherigen Tutorial haben wir etwas über die SPI-Kommunikation in Arduino gelernt. Heute lernen wir ein anderes serielles Kommunikationsprotokoll kennen: I2C (Inter Integrated Circuits). Im Vergleich von I2C mit SPI hat I2C nur zwei Drähte, während SPI vier verwendet und I2C mehrere Master und Slave haben kann, während SPI nur einen Master und mehrere Slaves haben kann. Es gibt also mehr als einen Mikrocontroller in einem Projekt, die Master sein müssen, dann wird I2C verwendet. Die I2C-Kommunikation wird im Allgemeinen zur Kommunikation mit Gyroskop, Beschleunigungsmesser, Luftdrucksensoren, LED-Anzeigen usw. verwendet.
In diesem Arduino I2C-Tutorial verwenden wir die I2C-Kommunikation zwischen zwei Arduino-Karten und senden mithilfe eines Potentiometers (0 bis 127) Werte aneinander. Die Werte werden auf dem 16x2-LCD angezeigt, das an jeden Arduino angeschlossen ist. Hier wird ein Arduino als Meister und ein anderer als Sklave fungieren. Beginnen wir also mit der Einführung in die I2C-Kommunikation.
Was ist das I2C-Kommunikationsprotokoll?
Der Begriff IIC steht für " Inter Integrated Circuits ". Es wird normalerweise an einigen Stellen als I2C oder I im Quadrat C oder sogar als 2-Draht-Schnittstellenprotokoll (TWI) bezeichnet, aber alles bedeutet dasselbe. I2C ist ein synchrones Kommunikationsprotokoll, dh beide Geräte, die die Informationen gemeinsam nutzen, müssen ein gemeinsames Taktsignal gemeinsam nutzen. Es gibt nur zwei Drähte zum Teilen von Informationen, von denen einer für das Hahnsignal und der andere zum Senden und Empfangen von Daten verwendet wird.
Wie funktioniert I2C-Kommunikation?
Die I2C-Kommunikation wurde erstmals von Phillips eingeführt. Wie bereits erwähnt, hat es zwei Drähte, diese beiden Drähte werden über zwei Geräte verbunden. Hier wird ein Gerät als Master und das andere Gerät als Slave bezeichnet. Die Kommunikation sollte und wird immer zwischen einem Master und einem Slave stattfinden. Der Vorteil der I2C-Kommunikation besteht darin, dass mehr als ein Slave mit einem Master verbunden werden kann.
Die vollständige Kommunikation erfolgt über diese beiden Drähte, nämlich Serial Clock (SCL) und Serial Data (SDA).
Serial Clock (SCL): Teilt das vom Master erzeugte Taktsignal mit dem Slave
Serielle Daten (SDA): Sendet die Daten zum und vom Master und Slave.
Zu jedem Zeitpunkt kann nur der Master die Kommunikation initiieren. Da sich mehr als ein Slave im Bus befindet, muss der Master auf jeden Slave mit einer anderen Adresse verweisen. Bei einer Adressierung antwortet nur der Slave mit dieser bestimmten Adresse mit den Informationen, während die anderen weiterhin aufhören. Auf diese Weise können wir denselben Bus verwenden, um mit mehreren Geräten zu kommunizieren.
Die Spannungspegel von I2C sind nicht vordefiniert. Die I2C-Kommunikation ist flexibel, dh das Gerät, das mit 5 V Volt betrieben wird, kann 5 V für I2C und die 3,3 V-Geräte 3 V für die I2C-Kommunikation verwenden. Was aber, wenn zwei Geräte, die mit unterschiedlichen Spannungen betrieben werden, über I2C kommunizieren müssen? Ein 5-V-I2C-Bus kann nicht mit einem 3,3-V-Gerät verbunden werden. In diesem Fall werden Spannungsschieber verwendet, um die Spannungspegel zwischen zwei I2C-Bussen anzupassen.
Es gibt einige Bedingungen, die eine Transaktion bestimmen. Die Initialisierung der Übertragung beginnt mit einer fallenden SDA-Flanke, die im folgenden Diagramm als "START" -Zustand definiert ist, bei der der Master die SCL hoch lässt, während der SDA niedrig eingestellt wird.
Wie im obigen Diagramm unten gezeigt, Die fallende Flanke von SDA ist der Hardware-Trigger für die START-Bedingung. Danach wechseln alle Geräte am selben Bus in den Abhörmodus.
Auf die gleiche Weise stoppt eine steigende Flanke von SDA die Übertragung, die im obigen Diagramm als "STOP" -Zustand dargestellt ist, wobei der Master SCL hoch verlässt und auch SDA freigibt, um auf HIGH zu gehen. Eine steigende Flanke von SDA stoppt also die Übertragung.
Das R / W-Bit gibt die Übertragungsrichtung der folgenden Bytes an. Wenn es HIGH ist, sendet der Slave, und wenn es niedrig ist, sendet der Master.
Jedes Bit wird in jedem Taktzyklus übertragen, daher dauert es 8 Taktzyklen, um ein Byte zu übertragen. Nach jedem gesendeten oder empfangenen Byte wird der neunte Taktzyklus für das ACK / NACK gehalten (bestätigt / nicht bestätigt). Dieses ACK-Bit wird je nach Situation entweder vom Slave oder vom Master generiert. Für ACK - Bit wird SDA bei 9 bis niedrig - Master oder Slave gesetzt ten Taktzyklus. Es ist also niedrig, es wird als ACK angesehen, sonst NACK.
Wo kann ich die I2C-Kommunikation nutzen?
Die I2C-Kommunikation wird nur für die Kurzstreckenkommunikation verwendet. Es ist sicherlich bis zu einem gewissen Grad zuverlässig, da es einen synchronisierten Takt hat, um es intelligent zu machen. Dieses Protokoll wird hauptsächlich zur Kommunikation mit Sensoren oder anderen Geräten verwendet, die Informationen an einen Master senden müssen. Dies ist sehr praktisch, wenn ein Mikrocontroller mit nur wenigen Kabeln mit vielen anderen Slave-Modulen kommunizieren muss. Wenn Sie nach einer Kommunikation über große Entfernungen suchen, sollten Sie RS232 ausprobieren. Wenn Sie nach einer zuverlässigeren Kommunikation suchen, sollten Sie das SPI-Protokoll ausprobieren.
I2C in Arduino
Das Bild unten zeigt die in Arduino UNO vorhandenen I2C-Pins.
I2C-Leitung | Pin in Arduino |
SDA | A4 |
SCL | A5 |
Bevor wir mit der Programmierung von I2C mit zwei Arduino beginnen. Wir müssen etwas über die in Arduino IDE verwendete Wire-Bibliothek lernen.
Die Bibliothek
1. Wire.begin (Adresse):
Verwendung: Diese Bibliothek wird für die Kommunikation mit I2C-Geräten verwendet. Dadurch wird die Wire-Bibliothek initiiert und der I2C-Bus als Master oder Slave verbunden.
Adresse: Die 7-Bit-Slave-Adresse ist optional. Wenn die Adresse nicht angegeben wird, wird sie wie folgt als Master an den Bus angeschlossen.
2. Wire.read ():
Verwendung: Mit dieser Funktion wird ein Byte gelesen, das vom Master- oder Slave-Gerät empfangen wurde, entweder das nach einem Aufruf von requestFrom () von einem Slave-Gerät an ein Master-Gerät gesendet oder von einem Master an einen Slave gesendet wurde.
3. Wire.write ():
Verwendung: Mit dieser Funktion werden Daten auf ein Slave- oder Master-Gerät geschrieben.
Slave zu Master: Slave schreibt Daten in einen Master, wenn Wire.RequestFrom () im Master verwendet wird.
Master to Slave: Für die Übertragung von einem Master zu einem Slave-Gerät wird Wire.write () zwischen den Aufrufen von Wire.beginTransmission () und Wire.endTransmission () verwendet.
Wire.write () kann geschrieben werden als:
- Wire.write (Wert)
value: Ein Wert, der als einzelnes Byte gesendet werden soll.
- Wire.write (Zeichenfolge):
Zeichenfolge: Eine Zeichenfolge, die als eine Reihe von Bytes gesendet werden soll.
- Wire.write (Daten, Länge):
Daten: Ein Array von Daten, die als Bytes gesendet werden sollen
Länge: Die Anzahl der zu sendenden Bytes.
4. Wire.beginTransmission (Adresse):
Verwendung: Mit dieser Funktion wird eine Übertragung zum I2C-Gerät mit der angegebenen Slave-Adresse gestartet. Erstellen Sie anschließend mit der Funktion write () eine Warteschlange mit Bytes für die Übertragung und übertragen Sie diese dann durch Aufrufen der Funktion endTransmission () . Die 7-Bit-Adresse des Geräts wird übertragen.
5. Wire.endTransmission ();
Verwendung: Mit dieser Funktion wird eine Übertragung an ein Slave-Gerät beendet, die von beginTransmission () gestartet wurde, und die von Wire.write () in die Warteschlange gestellten Bytes übertragen .
6. Wire.onRequest ();
Verwendung: Diese Funktion wird aufgerufen, wenn ein Master Daten mit Wire.requestFrom () vom Slave-Gerät anfordert. Hier können wir die Funktion Wire.write () einfügen , um Daten an den Master zu senden.
7. Wire.onReceive ();Verwendung: Diese Funktion wird aufgerufen, wenn ein Slave-Gerät Daten von einem Master empfängt. Hier können wir Wire.read () einschließen; Funktion zum Lesen der vom Master gesendeten Daten.
8. Wire.requestFrom (Adresse, Menge);
Verwendung: Diese Funktion wird im Master verwendet, um Bytes von einem Slave-Gerät anzufordern. Mit der Funktion Wire.read () werden die vom Slave-Gerät gesendeten Daten gelesen.
Adresse: Die 7-Bit-Adresse des Geräts, von dem Bytes angefordert werden sollen
Menge: Die Anzahl der anzufordernden Bytes
Erforderliche Komponenten
- Arduino Uno (2-Nr.)
- 16X2 LCD-Anzeigemodul
- 10K-Potentiometer (4-Nr.)
- Steckbrett
- Kabel anschließen
Schaltplan
Arbeitserklärung
Hier zur Demonstration der I2C-Kommunikation in Arduino verwenden wir zwei Arduino UNO mit zwei aneinander angeschlossenen 16X2-LCD-Displays und verwenden zwei Potentiometer an beiden Arduino, um die Sendewerte (0 bis 127) von Master zu Slave und von Slave zu Master durch Variieren der zu bestimmen Potentiometer.
Wir nehmen den analogen Eingangswert am Arduino-Pin A0 mit einem Potentiometer von (0 bis 5 V) und wandeln ihn in einen analogen in einen digitalen Wert (0 bis 1023) um. Dann werden diese ADC-Werte weiter in (0 bis 127) umgewandelt, da wir nur 7-Bit-Daten über die I2C-Kommunikation senden können. Die I2C-Kommunikation erfolgt über zwei Drähte an Pin A4 und A5 beider Arduino.
Die Werte am LCD des Slave Arduino werden geändert, indem der POT auf der Masterseite variiert wird und umgekehrt.
I2C-Programmierung in Arduino
Dieses Tutorial enthält zwei Programme, eines für Master Arduino und eines für Slave Arduino. Komplette Programme für beide Seiten finden Sie am Ende dieses Projekts mit einem Demonstrationsvideo.
Erklärung zur Master-Arduino-Programmierung
1. Zunächst müssen wir die Drahtbibliothek für die Verwendung von I2C-Kommunikationsfunktionen und die LCD-Bibliothek für die Verwendung von LCD-Funktionen einbeziehen. Definieren Sie auch LCD-Pins für 16x2-LCD. Weitere Informationen zur Verbindung von LCD mit Arduino finden Sie hier.
#einschließen
2. In void setup ()
- Wir starten die serielle Kommunikation mit einer Baudrate von 9600.
Serial.begin (9600);
- Als nächstes starten wir die I2C-Kommunikation an Pin (A4, A5).
Wire.begin (); // Startet die I2C-Kommunikation an Pin (A4, A5)
- Als nächstes initialisieren wir das LCD-Anzeigemodul im 16X2-Modus und zeigen die Begrüßungsnachricht an und löschen sie nach fünf Sekunden.
lcd.begin (16,2); // LCD-Anzeige initialisieren lcd.setCursor (0,0); // Setzt den Cursor in die erste Zeile von Display lcd.print ("Circuit Digest"); // druckt CIRCUIT DIGEST in LCD lcd.setCursor (0,1); // Setzt den Cursor in die zweite Zeile von Display lcd.print ("I2C 2 ARDUINO"); // druckt I2C ARDUINO in LCD- Verzögerung (5000); // Verzögerung um 5 Sekunden lcd.clear (); // Löscht die LCD-Anzeige
3. In void loop ()
- Zuerst müssen wir Daten vom Slave abrufen, damit wir requestFrom () mit der Slave-Adresse 8 verwenden und ein Byte anfordern
Wire.requestFrom (8,1);
Der empfangene Wert wird mit Wire.read () gelesen
Byte MasterReceive = Wire.read ();
- Als nächstes müssen wir den Analogwert vom Master-Arduino-POT lesen, der an Pin A0 angeschlossen ist
int potvalue = analogRead (A0);
Wir konvertieren diesen Wert in Form eines Bytes als 0 in 127.
Byte MasterSend = map (potvalue, 0,1023,0,127);
- Als nächstes müssen wir diese konvertierten Werte senden, damit wir die Übertragung mit Slave Arduino mit 8 Adressen beginnen
Wire.beginTransmission (8); Wire.write (MasterSend); Wire.endTransmission ();
- Als nächstes zeigen wir diese vom Slave-Arduino empfangenen Werte mit einer Verzögerung von 500 Mikrosekunden an und empfangen und zeigen diese Werte kontinuierlich an.
lcd.setCursor (0,0); // Setzt Currsor in Zeile eins von LCD lcd.print (">> Master <<"); // druckt >> Master << am LCD lcd.setCursor (0,1); // Setzt den Cursor in Zeile zwei von LCD lcd.print ("SlaveVal:"); // druckt SlaveVal: in LCD lcd.print (MasterReceive); // druckt MasterReceive in LCD, das vom Slave Serial.println empfangen wurde ("Master vom Slave empfangen"); // Druckt in Serial Monitor Serial.println (MasterReceive); Verzögerung (500); lcd.clear ();
Erklärung zur Slave-Arduino-Programmierung
1. Wie beim Master müssen wir zunächst die Wire-Bibliothek für die Verwendung von I2C-Kommunikationsfunktionen und die LCD-Bibliothek für die Verwendung von LCD-Funktionen einbeziehen. Definieren Sie auch LCD-Pins für 16x2-LCD.
#einschließen
2. In void setup ()
- Wir starten die serielle Kommunikation mit einer Baudrate von 9600.
Serial.begin (9600);
- Als nächstes starten wir die I2C-Kommunikation an Pin (A4, A5) mit der Slave-Adresse 8. Hier ist es wichtig, die Slave-Adresse anzugeben.
Wire.begin (8);
Als nächstes müssen wir die Funktion aufrufen, wenn der Slave einen Wert vom Master erhält und wenn der Master einen Wert vom Slave anfordert
Wire.onReceive (receiveEvent); Wire.onRequest (requestEvent);
- Als nächstes initialisieren wir das LCD-Anzeigemodul im 16X2-Modus und zeigen die Begrüßungsnachricht an und löschen sie nach fünf Sekunden.
lcd.begin (16,2); // LCD-Anzeige initialisieren lcd.setCursor (0,0); // Setzt den Cursor in die erste Zeile von Display lcd.print ("Circuit Digest"); // druckt CIRCUIT DIGEST in LCD lcd.setCursor (0,1); // Setzt den Cursor in die zweite Zeile von Display lcd.print ("I2C 2 ARDUINO"); // druckt I2C ARDUINO in LCD- Verzögerung (5000); // Verzögerung um 5 Sekunden lcd.clear (); // Löscht die LCD-Anzeige
3. Als nächstes haben wir zwei Funktionen, eine für das Anforderungsereignis und eine für das Empfangsereignis
Für Anfrage Ereignis
Beim Master-Anforderungswert vom Slave wird diese Funktion ausgeführt. Diese Funktion nimmt den Eingabewert vom Slave-POT und konvertiert ihn in 7-Bit und sendet diesen Wert an den Master.
void requestEvent () { int potvalue = analogRead (A0); Byte SlaveSend = map (Potvalue, 0,1023,0,127); Wire.write (SlaveSend); }}
Für Empfangsereignis
Wenn der Master Daten mit der Slave-Adresse (8) an den Slave sendet, wird diese Funktion ausgeführt. Diese Funktion liest den vom Master empfangenen Wert und speichert ihn in einer Variablen vom Typ Byte .
void receiveEvent (int howMany { SlaveReceived = Wire.read (); }
4. In der Leerenschleife ():
Wir zeigen den vom Master empfangenen Wert kontinuierlich im LCD-Anzeigemodul an.
void loop (void) { lcd.setCursor (0,0); // Setzt Currsor in Zeile eins von LCD lcd.print (">> Slave <<"); // druckt >> Slave << am LCD lcd.setCursor (0,1); // Setzt den Cursor in Zeile zwei von LCD lcd.print ("MasterVal:"); // druckt MasterVal : in LCD lcd.print (SlaveReceived); // Gibt den SlaveReceived-Wert auf dem LCD aus, der vom Master Serial.println empfangen wurde ("Vom Master empfangener Slave:"); // Druckt im seriellen Monitor Serial.println (SlaveReceived); Verzögerung (500); lcd.clear (); }}
Durch Drehen des Potentiometers auf einer Seite können Sie die unterschiedlichen Werte auf dem LCD auf einer anderen Seite sehen:
So findet die I2C-Kommunikation in Arduino statt. Hier haben wir zwei Arduinos verwendet, um nicht nur das Senden von Daten, sondern auch das Empfangen der Daten mithilfe der I2C-Kommunikation zu demonstrieren. Jetzt können Sie jeden I2C-Sensor an Arduino anschließen.
Die vollständige Codierung für Master und Slave Arduino finden Sie unten mit einem Demonstrationsvideo