Der Inter-Integrated Circuit (I2C) – Bus ist ein serieller Kommunikationsmechanismus auf Chipebene, der über nur zwei Drähte arbeitet. Einige Entwickler sprechen den Namen des Busses Eye-two-see aus, andere eye-squared-see, aber beide beziehen sich auf dasselbe. Entwickelt von Philips in den frühen 1980er Jahren wurde I2C gegründet, um die Kommunikation zwischen den Chips des Unternehmens zu standardisieren, aber es ist seitdem ein De-facto-Standard geworden, der von vielen Mikrocontrollergeräten unterstützt wird, von Arduino-Boards bis zum Raspberry Pi und natürlich IMPS.,
Der physische Bus
I2C selbst besteht aus zwei Drähten. Eine I2C-Leitung überträgt Daten, die andere die Taktsignale, die die Konversation zwischen Geräten synchronisieren. Die Datenleitung heißt ‚SDA‘, die Taktleitung’SCL‘.
Typischerweise sind sowohl SDA als auch SCL jeweils über einen einzelnen Pull-up-Widerstand an eine 3,3-oder 5-V-Stromleitung angeschlossen, einen an jeder Leitung. Dies ist erforderlich, da die SDA-und SCL-Anschlüsse der Geräte „Open Drain“ – Leitungen sind: Sie können die Spannung an der Leitung auf 0 V oder „niedrig“ drücken, sie jedoch nicht auf 3,3 V oder „hoch“ erhöhen., Hoch und niedrig sind die elektrischen Darstellungen der 1s und 0s, die die grundlegenden Komponenten digitaler Informationen sind. Das Hinzufügen dieser beiden Widerstände — und der Bus benötigt nur zwei, unabhängig davon, wie viele Geräte daran angeschlossen sind — stellt sicher, dass die Spannung ohne Kurzschluss auf 3,3 V ansteigt.
I2C besteht darauf, dass Geräte über offene Abflussleitungen verfügen, um sicherzustellen, dass keine komponentenschädlichen hohen Ströme fließen können, wenn zwei Geräte gleichzeitig versuchen, ein Signal zu senden.
In den meisten Fällen wird erwartet, dass Sie diese Widerstände selbst hinzufügen, aber einige Geräte, in der Regel solche, die bei 3 arbeiten.,3V, schließen Sie sie ein, um mit Geräten kompatibel zu sein, die 5V liefern. Denken Sie daran, dass Sie nur ein Paar Pull-up-Widerstände pro Bus benötigen, sodass es möglicherweise erforderlich ist, Pull-up-Widerstände zu entfernen, die an anderen Geräten im Bus angebracht sind. Obwohl der Imp über eigene interne Pull-up-Widerstände verfügt, sind diese zu schwach, um für I2C nützlich zu sein, und werden daher automatisch deaktiviert, wenn seine Pins auf die Verarbeitung von I2C-Signalen eingestellt sind.
Controller und Peripheriegeräte
Der I2C-Bus trennt Geräte in ‚ Controller ‚und’Peripheriegeräte‘., Nur ein Gerät kann Timing-Impulse auf der SCL-Leitung gleichzeitig senden, und das ist derjenige, der als Controller ausgewählt wurde. Alle anderen synchronisieren ihre Timings mit dem Controller und gelten somit als Peripheriegeräte. Der Controller-normalerweise der Imp — und seine Peripheriegeräte können alle Daten senden und empfangen, aber nur der Controller kann einem Peripheriegerät mitteilen, wann Daten zurückgesendet werden sollen.
Adressierung
Damit ein I2C-Gerät eins zu eins mit einem anderen kommunizieren kann, müssen beide Geräte eindeutig identifizierbar sein. Diese Identität ist die I2C-Adresse des Geräts., I2C-Adressen sind normalerweise 7-Bit-Nummern, sodass ein Bus insgesamt bis zu 127 Geräte umfassen kann. Ein Byte besteht aus acht Bits; Das zusätzliche Bit wird verwendet, um anzuzeigen, ob das Signal von der Steuerung an das Peripheriegerät gesendet wird — ein „Schreiben“ — oder in die andere Richtung — ein „Lesen“. Dieses achte Bit ist tatsächlich das Bit Null im Adressbyte, das an den Bus gesendet wird. Die 7-Bit-Adresse wird in Bits eins bis sieben des Adressbyte platziert.
In Übereinstimmung mit diesem Format verwendet die IMP-API eine I2C-Adresse als 8-Bit-Wert., Gerätelieferanten geben normalerweise die Adressen ihrer Produkte als 7-Bit-Nummer an, daher muss die Adresse von sieben Bits in acht konvertiert werden. Dies wird mit dem Operator <<
von Squirrel erreicht, der die einzelnen Bitwerte einer Zahl nach links verschiebt. Dieser Vorgang entspricht der Multiplikation mit zwei. Im Code sieht dieser Prozess folgendermaßen aus:
local sevenBitAddress = 0x39;local eightBitAddress = sevenBitAddress << 1;
Squirrel setzt das Bit automatisch auf den richtigen I2C-definierten Wert: 0 für einen Schreibvorgang, 1 für einen Lesevorgang., Jetzt können Sie eine der i2c-Methoden des imp verwenden, um Daten in den Bus zu schreiben:
i2c.write(eightBitAddress, dataInStringForm);
Die 7-Bit-Adresse des Geräts, mit dem Ihr imp kommunizieren soll, wird vom Hersteller der Komponente bereitgestellt und im Datenblatt des Geräts aufgeführt. Es kann nicht fixiert sein, sondern aus einem Adressbereich entsprechend der Spannung ausgewählt werden, die an einen anderen der Geräte-Pins angelegt wird., Ein TAOS TSL2561 – Lichtsensor hat beispielsweise drei mögliche Adressen: 0x29
, 0x49
oder 0x39
, je nachdem, ob sein ADDR-Pin auf 0V, 3.3 V oder ‚floating‘ zwischen den beiden festgelegt ist. Wir sagen, der Wert schwebt, weil er nicht aktiv für den Betrieb mit einer bestimmten Spannung ausgewählt wurde.Es könnte alles von 0 bis einschließlich 3,3 V sein.
Signalisierung
Der Controller des I2C-Busses verwendet die 7-Bit-Adresse eines Peripheriegeräts, um die Komponente zu identifizieren, mit der er sprechen möchte., Tatsächlich ist die Signalisierung komplexer, aber glücklicherweise werden alle Details vom imp verarbeitet, sodass Sie die Adresse nur als 8-Bit-Wert angeben müssen.
Wenn Sie an das Peripheriegerät schreiben, müssen Sie auch die zu schreibenden Daten angeben, die häufig Registerwerte enthalten, die das Peripheriegerät anweisen, was mit den Daten zu tun ist. Die imp-API-Dokumentation bezieht sich auf diese Register als ‚Subadressen‘:
i2c.write(eightBitAddress, dataString);
write() benötigt Daten in Zeichenfolgenform. Daher müssen Sie möglicherweise den in anderen Variablentypen gespeicherten Wert in eine Zeichenfolgenform konvertieren.,
Das Lesen von Informationen von einem Gerät erfordert möglicherweise einen Befehl, um dem Gerät mitzuteilen, welche Daten abgerufen werden sollen. Wenn Sie dem imp mitteilen, dass er Daten aus dem I2C-Bus lesen soll, müssen Sie auch einen dritten Parameter angeben, die Anzahl der Bytes, die Sie erwarten:
i2c.read(eightBitAddress, controlDataString, numberOfBytesToRead);
Hinter diesen Operationen befinden sich die elektrischen Signale des I2C, die an die SDA-Leitung angelegt werden und mit den an die SCL-Leitung angewendeten Zeitpulsen synchronisiert sind. Das Schreiben in den Bus beinhaltet eine Startmarkierung: Das Ablegen von SDA auf 0 V, während SCL 3,3 V beträgt.Das Ändern der SDA-Spannung, wenn die Spannung der SCL hoch ist, definiert Start-und Stoppmarkierungen., Wenn sich die SDA-Spannung nicht ändert, während die SCL hoch ist, wissen I2C-Geräte, dass Daten anstelle von Markern gesendet werden.
SDA geht jetzt hoch oder niedrig, um jedes Bit des Adressbyte zu senden: die 7-Bit-Geräteadresse gefolgt vom Lese – / Schreibbit. Die Bits des Bytes werden zuerst das am weitesten links liegende Bit-das „höchstwertige Bit“ — ausgesendet, wobei SDA hoch wird, wenn der Wert des Bits 1 oder niedrig ist, wenn es Null ist. Das Zielperipheriegerät zieht nun SDA low, um eine Empfangsbestätigung der Daten zu signalisieren, und dann gehen acht Bits von Steuerinformationen oder Daten aus, gefolgt von weiteren Daten, falls erforderlich., Es gibt eine ACK-Bestätigungspause für einen einzelnen Impuls auf SDA zwischen allen acht gesendeten Bits, zeitlich auf einen neunten SCL-Impuls eingestellt. Wenn das Peripheriegerät den Empfang auf diese Weise nicht bestätigt, erkennt der Controller, dass der SDA hoch geblieben ist, und signalisiert einen Fehler.,
Wenn Daten vom Peripheriegerät zum Controller fließen, bestätigt dieser ebenfalls den Empfang von acht Bits, indem er SDA am neunten SCL-Impuls niedrig zieht, es sei denn, dies ist das letzte Byte eines Batches, in diesem Fall zieht der Controller SDA nicht niedrig — es macht ein ’nak‘ — Signal oder ‚keine Bestätigung‘ -, um das Peripheriegerät wissen zu lassen, dass es fertig ist.
Wenn wir fertig sind, geht SDA als Stop-Marker hoch.,
Der Beginn der Übertragung wird angezeigt, indem SDA von Hoch-auf Niederspannung fällt (das Rechteck links),
stoppt durch die Rückseite (das rechte Rechteck). SCL muss hoch sein, wenn dies geschieht
Timing
Die Standardtaktgeschwindigkeit für I2C — Kommunikation beträgt 100kHz-100.000 SCL-Impulse pro Sekunde. Es ist möglich, schneller zu gehen, bis zu 400 kHz. Einige Geräte können diese Geschwindigkeit möglicherweise nicht unterstützen; Überprüfen Sie das Datenblatt, das dem Gerät beiliegt, das Sie mit Ihrem Imp verbinden möchten., Viele langsame Geräte verwenden jedoch eine Technik namens „Clock Stretching“, um schnellere Geräte zu zwingen, auf ihre Geschwindigkeit zu arbeiten. Der imp unterstützt Geräte, die diese Technik nutzen. Im Wesentlichen halten sie die SCL niedrig, während sie die Daten abrufen, die sie an den Imp senden sollen. Der Imp erkennt dies, gibt die SCL-Linie frei und wartet, bis die SCL wieder hoch geht, bevor er fortfährt.
Möglicherweise müssen Sie die I2C-Geschwindigkeit jedoch selbst senken, wenn die elektrischen Eigenschaften Ihres Setups die Geschwindigkeit des Übergangs zwischen 0 V und 3,3 V verlangsamen, die als „Anstiegszeit“ bezeichnet wird., Dies wird oft durch lange Drähte verursacht, die die Kapazität der Schaltung erhöhen. Damit die Geräte die Übertragung jedes Bits erfolgreich erkennen können, muss der Bus langsamer laufen. Datenbeschädigung oder unerwartete Ergebnisse sind die Hinweise, auf die Sie achten sollten. Reduzieren Sie die I2C-Busgeschwindigkeit, bis die Daten erfolgreich gelesen werden.
Die imp-API bietet derzeit vier vordefinierte Taktwerte: 10, 50 100 und 400 kHz., Sie werden ausgewählt, indem eine Konstante als Parameter an die I2C-Konfigurationsmethode übergeben wird:
i2c.configure(speedConstant);
wobei der Wert von speedConstant einer von
- CLOCK_SPEED_10_KHZ
- CLOCK_SPEED_50_KHz
- CLOCK_SPEED_100_KHZ
- CLOCK_SPEED_400_KHZ
Einrichten eines imp für I2C
Das i2c-Objekt in den obigen Beispielzeilen wird nicht direkt vom imp bereitgestellt, sondern von Ihnen entsprechend den Pins Ihres ausgewählten imp ausgewählt Sie werden für die I2C-Kommunikation verwenden., Jeder IMP – Typ verfügt über mehrere I2C-Busse, die alle beim Start verfügbar sind. Überprüfen sie die pin mux für die art von imp sie verwenden, um zu sehen, welche I2C objekte sind für sie. Hier nehmen wir an, dass Sie ein imp001 verwenden. Die beiden I2C-Busse des impp befinden sich auf den Pins 1 und 2 sowie auf den Pins 8 und 9, die beim Start des imp als Eigenschaften i2c12 und i2c89 des Hardwareobjekts instanziiert werden. Die Pins 1 und 8 sind SCL, 2 und 9 SDA zugeordnet.,
Es ist üblich, Ihre Wahl mit einer globalen Variablen zu referenzieren:
i2c <- hardware.i2c12;i2c.configure(CLOCK_SPEED_100_KHZ);
Beispielcode
Der folgende Code funktioniert mit dem sichtbaren und Infrarot-Lichtsensor TAOS TSL2561, einem 3,3-V-Gerät, das I2C zur Kommunikation mit seinem Host-Mikrocontroller verwendet. Das Datenblatt des Chips kann von der Adafruit-Website heruntergeladen werden. Adafruit verkauft den Chip auf einer kostengünstigen Breakout-Platine, die geeignete Pull-up-Widerstände am Power Pin VCC enthält. Dies bedeutet, dass es bereit ist, direkt an die I2C-Pins eines imp anzuschließen.,
Adafruit der TSL2561 breakout board
Hinweis Nach diesem artikel wurde geschrieben, Adafruit aktualisiert seine TSL2561 sensor board. Die neue Version funktioniert mit dem aktuellen Code.
Hier ist der Code für den Agenten und dann das Gerät:
Was der Code tut
Der Agentencode antwortet auf eine eingehende HTTP-Anfrage, indem er das Gerät darüber informiert, dass es gelesen werden muss. Der Einfachheit halber wird das Lesen einfach im Protokoll angezeigt.
Der Gerätecode liest den Sensor und berechnet einen Lux-Wert gemäß der im TSL2561-Datenblatt festgelegten Mathematik., Der erste Teil des Programms richtet Konstanten für die Schlüsselregister und-einstellungen des TSL2561 ein, einschließlich der I2C-Adressoptionen. Andere Konstanten werden im Luminositäts-Umwandlungsprozess verwendet.
Verdrahtung des imp
Am Programmstartpunkt benennt der Code einen der I2C-Pins des imp als globale Variable, konfiguriert die Busgeschwindigkeit auf 100 kHz und verschiebt dann die I2C-Adresse des TSL2561 ein Bit nach links, damit sie mit den imp I2C-Funktionen verwendet werden kann. Es richtet dann den Sensor ein., Um zu überprüfen, ob dies funktioniert hat, lesen wir das Steuerregister: Der Rückgabewert sollte 3 sein, wenn der TSL2561 gerade gestartet wurde, oder 51, wenn das Gerät bereits eingeschaltet wurde.
Als nächstes stellt der Code die ADC-Auflösung des Sensors über das Timing-Register des TSL2561 ein und stellt dann die Signalverstärkung auf hoch ein.
Schließlich teilen wir dem imp mit, wie er auf "sense"
Benachrichtigungen des Agenten reagieren soll. Dies ruft eine Funktion auf, die die beiden Lichtsensoren des TSL2561 liest, deren digitale Werte in den vier 8-Bit-ADC-Registern des Chips gespeichert sind., Die ersten beiden geben einen 16-Bit-kombinierten optischen und Infrarot-Messwert, das zweite Paar einen 16-Bit-IR-Only-Wert. Die Funktionen readSensorAdc0 () und readSensorAdc1 () wandeln die einzelnen Registerwerte in 16-Bit-Zahlen um, indem sie das höchstwertige Byte mit 256 multiplizieren und den Wert des niedrigwertigen Bytes addieren. Die Multiplikation erfolgt durch Verschieben der Bits der Acht-Bit-Zahl um acht Stellen mit dem Operator << von Squirrel.,
Der Code stellt dann beide Messwerte einer dritten Funktion zur Verfügung, um eine endgültige Leuchtkraft, den Lux-Wert, zu berechnen.
Weiterlesen
- I2C-Fehler-So debuggen Sie I2C-Lese-und Schreibprobleme