Wozu braucht man einen I2C Scanner?
In einigen Beiträgen hatte ich über Bauteile geschrieben die mittels I2C (genauer: I2C) angesprochen werden, wie beispielsweise in meinem letzten Beitrag über den MCP23017. Hier geht es nun um einen I2C Scanner Sketch, mit dem ihr I2C Adressen herausfinden könnt.
Damit ihr mehrere Bauteile über einen einzigen I2C Bus ansprechen könnt, muss jedes der Bauteile eine eigene I2C Adresse besitzen. Der Adressraum beschränkt sich auf die Adressen 1 bis 127. Genau genommen sogar auf 8 bis 127, da die Adressen 0 bis 7 reserviert sind. Da das nicht besonders viel ist, sind doppelt vergebene Adressen ohne weitere Maßnahmen nicht unwahrscheinlich. Deshalb haben die meisten I2C Bauteile zwei oder drei Eingänge, die ihr auf LOW oder HIGH legen könnt, um mehrere Adressen einzustellen. Bei Modulen könnt ihr die Adresse manchmal auch über Jumper wählen.
Idealerweise findet ihr ein Datenblatt, in dem die Adressierung beschrieben ist. Manchmal ist das jedoch nicht der Fall und dann braucht man einen I2C Scanner. Vielleicht funktioniert auch eine Schaltung einfach nicht und ihr wollt überprüfen, ob das verwendete I2C Bauteil überhaupt antwortet. Auch dann ist ein I2C Scanner sinnvoll. Darüber hinaus möchtet ihr vielleicht prüfen, für welche Übertragungsgeschwindigkeit euer I2C Bauteil geeignet ist.
I2C – Übertragungsrate
Der I2C Bus besteht aus zwei Leitungen, die meistens als SDA und SCL bezeichnet werden. SDA überträgt die Daten, SCL gibt den Takt vor und bestimmt so die Datenrate. Es gibt 5 Datenraten:
- Standard Mode, Takt: 100 kHz
- Fast Mode: 400 kHz
- Fast Mode Plus: 1 MHz
- High Speed Mode: 3.4 MHz
- Ultra Fast Mode: 5 MHz (nur unidirektional)
Da bei jedem Takt ein Bit übertragen wird, entspricht die Taktrate der Datenrate in Bit/s.
Welcher Takt eingestellt werden kann, hängt sowohl vom I2C Bauteil wie auch vom verwendeten Microcontroller ab. Der Arduino Uno kann maximal den Fast Mode.
Weitere Informationen über I2C findet Ihr hier auf Wikipedia. Die Wire Bibliothek wird auf den Arduinoseiten hier beschrieben.
Der I2C Scanner Sketch
Der Sketch ist denkbar einfach. Wire.setClock()
stellt die Übertragungsrate ein. Wire.beginTransmission(adresse)
startet die Kommunikation mit dem I2C Bauteil. Wire.endTransmission()
liefert „0“ zurück, wenn es geklappt hat. So arbeitet sich der Sketch sklavisch durch den Adressraum für jede Übertragungsrate.
#include<Wire.h> void setup(){ Wire.begin(); Serial.begin(9600); Serial.println("I2C Scanner ist bereit."); Serial.println(); } void loop() { scanI2C(100000); scanI2C(400000); // scanI2C(1000000); // nur aktivieren, wenn der Microcontroller diese Frequenz unterstützt // scanI2C(3400000); // nur aktivieren, wenn der Microcontroller diese Frequenz unterstützt // scanI2C(5000000); // nur aktivieren, wenn der Microcontroller diese Frequenz unterstützt Serial.println("****************************"); Serial.println(); delay(3000); } void scanI2C(long frequency){ String normal = "standard mode (100 kHz):"; String fast = "fast mode (400 kHz):"; String fastPlus = "fast mode plus (1 MHz):"; String highSpeed = "high speed mode (3.4 MHz):"; String ultraSpeed = "ultra fast mode (5.0 MHz):"; String defaultStr = " !!!!! Unzulässige Frequenz !!!!!"; bool error = true; bool addressFound = false; Serial.print("Scanne im "); switch(frequency){ case 100000: Serial.println(normal); break; case 400000: Serial.println(fast); break; case 1000000: Serial.println(fastPlus); break; case 3400000: Serial.println(highSpeed); break; case 5000000: Serial.println(ultraSpeed); break; default: Serial.println(defaultStr); break; } Wire.setClock(frequency); for(int i=1; i<128; i++){ Wire.beginTransmission(i); error = Wire.endTransmission(); if(error == 0){ addressFound = true; Serial.print("0x"); Serial.println(i,HEX); } } if(!addressFound){ Serial.println("Keine Adresse erkannt"); } Serial.println(); }
Beispielschaltung: MCP23017
Hier eine Beispielschaltung mit dem MCP23017. Falls der Sketch bei euch keine Adresse erkennt, könnte es an fehlenden Pull-Up Widerständen (4.7 kOhm) liegen.
Hallo Wolfgang,
habe den Scanner mit einem Arduino Uno in Verbindung mit der I2C WaveShare PCF8574 Platine betrieben und Hardware/Software funktionieren korrekt wie beschrieben. Als I2C Adresse wird beim Monitor 0x20 angezeigt (die 3 Adress Jumper der WaveShare Platine sind auf 000 gesetzt). Ich hatte gedacht, dass die I2C Adresse beim Monitor sich ändert, wenn eines der Adressbits per Jumper (A0 oder A1 oder A2 ) auf high gesetzt wird. Aber nichts passiert, die I2C Adresse bleibt permanent bei 0x20. Was ist die Ursache?
Hallo Gerhard, das kann ich dir nicht beantworten. Es gibt Bauteile, die ihre Adresse zum Zeitpunkt des Einschaltens behalten, auch wenn man Adresspins ändert. Ob das hier der Fall ist das kann ich nicht sagen. Sonst weiß ich das auch nicht.
VG, Wolfgang
Hallo Wolfgang,
Danke für Deine Bemühungen! Ein Hinweis im WaveShare Datenblatt hat mich auf die Spur geführt. Dort steht nämlich, dass Raubkopierer verschiedene Produkte gleichen Namens auf den Markt gebracht haben, bei denen die Orginal Doku nicht stimmt. So wie ich feststellen konnte, auch bei meiner Platine. Trotz der vorhandenen Programmierjumper sind auf der Platine alle 3 Adressleitungen A0 bis A2 fest (hardwired) mit dem Gnd verbunden. Eine andere Adresse als 000 läßt sich also mit den Jumpern gar nicht einstellen. Ich hätte diesen Fehler auch schon früher feststellen müssen, denn bei versetzen eines Jumpers wurde jedes Mal die Vcc mit Gnd verbunden und somit die ganze Hardware inaktiv. Also Achtung bei Hardware aus China!
Super Idee mit dem I2C Scanner
Vielen Dank