I2C-Bus mit Arduino verstehen: I2C-Scanner, Adresskonflikte lösen & mehrere Sensoren an zwei Kabeln
Ein OLED-Display, ein Luftdrucksensor, ein Gyroskop und eine Echtzeituhr – vier Module, und trotzdem brauchst du am Arduino nur zwei Datenleitungen. Möglich macht das der I2C-Bus, der wahrscheinlich wichtigste Standard in der Maker-Elektronik. Solange alles funktioniert, denkt niemand darüber nach. Aber sobald zwei Module dieselbe Adresse haben, das Display nach dem vierten Sensor schwarz bleibt oder ein längeres Kabel alles zerlegt, hilft nur noch: verstehen, was auf diesen zwei Drähten eigentlich passiert. Genau das machen wir hier – mit fertigem I2C-Scanner, einer Lösung für Adresskonflikte und den Pull-Up-Regeln, die dir stundenlange Fehlersuche ersparen.
Was I2C überhaupt ist
I2C (gesprochen „I-Quadrat-C“, von Inter-Integrated Circuit) wurde in den 1980ern von Philips erfunden, um Chips auf einer Platine mit möglichst wenigen Leitungen zu verbinden. Das Ergebnis: Ein Bus mit exakt zwei Signalleitungen, an dem theoretisch bis zu 127 Geräte hängen dürfen.
| Leitung | Bedeutung | Wer treibt sie? |
|---|---|---|
| SDA | Serial Data – die Nutzdaten | Master und Slave abwechselnd |
| SCL | Serial Clock – der Takt | immer der Master |
| VCC | Versorgungsspannung | – |
| GND | gemeinsame Masse (Pflicht!) | – |
Ein Gerät ist der Master (dein Arduino oder ESP32) und gibt den Takt vor. Alle anderen sind Slaves und antworten nur, wenn sie mit ihrer Adresse angesprochen werden. Die Kommunikation läuft immer nach demselben Muster ab: Der Master zieht SDA auf Low, während SCL noch High ist (das ist die Start-Bedingung), schickt dann die 7-Bit-Adresse des gewünschten Slaves plus ein Bit für Lesen oder Schreiben. Das angesprochene Gerät antwortet mit einem ACK – einem einzelnen Low-Impuls, der „ja, ich bin da“ bedeutet. Danach fließen die Datenbytes.
ℹ️ Das ACK ist der Schlüssel zu allem: Dieses eine Bestätigungsbit ist der Grund, warum ein I2C-Scanner überhaupt funktioniert. Der Master ruft nacheinander jede mögliche Adresse auf und schaut, ob jemand antwortet. Kommt ein ACK, existiert dort ein Gerät. Kommt keins, ist die Adresse leer. Mehr steckt hinter dem Scanner-Sketch nicht – und genau deshalb ist er dein wichtigstes Diagnosewerkzeug.
Open-Drain: Warum Pull-Up-Widerstände Pflicht sind
Hier steckt der wichtigste Unterschied zu allem, was du bisher am Arduino gemacht hast. Ein normaler GPIO-Pin kann aktiv High und aktiv Low ausgeben. I2C-Pins können das nicht – sie arbeiten im Open-Drain-Modus: Jedes Gerät kann die Leitung nur nach Masse ziehen (Low), aber niemals aktiv auf High treiben.
Wer macht dann High? Die Pull-Up-Widerstände. Sie ziehen die Leitung nach VCC, solange niemand sie nach unten zerrt. Ohne Pull-Ups hängt der Bus in der Luft, und nichts funktioniert.
💡 Warum dieser Umweg? Weil so nie ein Kurzschluss entstehen kann. Zieht Gerät A die Leitung auf Low, während Gerät B sie loslassen will, passiert genau nichts Schlimmes – die Leitung ist eben Low. Würden beide aktiv treiben, käme High gegen Low, und einer der beiden Chips würde durchbrennen. Open-Drain macht den geteilten Bus überhaupt erst möglich.
Wie groß müssen die Pull-Ups sein?
| Situation | Empfohlener Wert | Anmerkung |
|---|---|---|
| 1–2 Breakout-Module, kurze Kabel | 4,7 kΩ | meist schon auf den Modulen verbaut |
| Mehrere Module, > 30 cm Kabel | 2,2 kΩ | schnellere Flanken |
| 400 kHz Fast Mode, längerer Bus | 1,5–2,2 kΩ | Untergrenze beachten |
| Sehr viele Module am Bus | 1,0 kΩ | nicht kleiner – sonst zu viel Strom |
⚠️ Die Pull-Up-Falle bei fertigen Modulen: Fast jedes Breakout-Board – OLED, BMP280, MPU-6050, DS3231 – hat bereits eigene Pull-Ups von meist 4,7 kΩ oder 10 kΩ an Bord. Das ist bequem, solange du ein Modul nutzt. Hängst du vier Module parallel an denselben Bus, liegen deren Pull-Ups parallel. Vier mal 4,7 kΩ parallel ergeben rund 1,2 kΩ – damit fließt schon ordentlich Strom, und manche Chips schaffen es nicht mehr, die Leitung sauber auf Low zu ziehen. Symptom: Der Bus läuft mit zwei Modulen, mit vier bleibt das Display schwarz. Lösung: Auf allen bis auf einem Modul die Pull-Up-Widerstände entfernen oder deren Lötbrücke auftrennen. Auf vielen Boards ist dafür extra ein Jumper vorgesehen.
Für eigene Pull-Ups eignen sich die 4,7-kΩ- und 2,2-kΩ-Werte aus dem 600er Widerstands-Sortiment. Je ein Widerstand von SDA nach VCC und von SCL nach VCC – mehr braucht es nicht.
Was du brauchst
Wo liegen die I2C-Pins?
Jedes Board hat seine eigenen. Diese Tabelle klebst du dir am besten an die Wand:
| Board | SDA | SCL | Logikpegel |
|---|---|---|---|
| Arduino UNO R3 | A4 | A5 | 5 V |
| Arduino Nano V3 | A4 | A5 | 5 V |
| Arduino UNO R4 Minima | A4 / SDA | A5 / SCL | 5 V |
| ESP32 WROOM-32 | GPIO 21 | GPIO 22 | 3,3 V |
| ESP32-C3 Mini | frei wählbar (Standard 8) | frei wählbar (Standard 9) | 3,3 V |
| Wemos D1 Mini (ESP8266) | D2 (GPIO 4) | D1 (GPIO 5) | 3,3 V |
| RP2040-Zero | GPIO 4 (Standard) | GPIO 5 (Standard) | 3,3 V |
ℹ️ Vorteil ESP32: Auf ESP-Boards sind SDA und SCL nicht fest verdrahtet, sondern frei zuweisbar. Mit Wire.begin(sdaPin, sclPin); legst du sie auf beliebige GPIOs. Praktisch, wenn dir ein anderes Modul die Standardpins wegnimmt.
1Der I2C-Scanner – dein wichtigstes Werkzeug
Bevor du auch nur eine Zeile Sensorcode schreibst, läuft dieser Sketch. Er klopft jede Adresse von 1 bis 126 ab und meldet, wer antwortet. Findet der Scanner dein Modul nicht, ist jede Bibliothek zwecklos – dann ist die Verkabelung schuld.
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
while (!Serial) delay(10);
Serial.println("\nI2C-Scanner gestartet");
}
void loop() {
byte fehler;
int gefunden = 0;
Serial.println("Suche Geraete...");
for (byte adresse = 1; adresse < 127; adresse++) {
// Uebertragung starten und sofort beenden.
// endTransmission() liefert 0, wenn jemand mit ACK geantwortet hat.
Wire.beginTransmission(adresse);
fehler = Wire.endTransmission();
if (fehler == 0) {
Serial.print(" Geraet gefunden bei 0x");
if (adresse < 16) Serial.print("0");
Serial.print(adresse, HEX);
Serial.print(" (dezimal ");
Serial.print(adresse);
Serial.println(")");
gefunden++;
}
else if (fehler == 4) {
Serial.print(" Unbekannter Fehler bei 0x");
if (adresse < 16) Serial.print("0");
Serial.println(adresse, HEX);
}
}
if (gefunden == 0) {
Serial.println("Kein I2C-Geraet gefunden!");
Serial.println("-> SDA/SCL vertauscht? GND verbunden? Pull-Ups da?");
} else {
Serial.print("Fertig. ");
Serial.print(gefunden);
Serial.println(" Geraet(e) am Bus.\n");
}
delay(5000);
}
Die Adressen, die dir ständig begegnen
| Adresse | Modul | Alternative |
|---|---|---|
| 0x3C | OLED SSD1306 128x64 / 128x32 | 0x3D (Lötbrücke) |
| 0x68 | MPU-6050 (GY-521) | 0x69 (AD0 auf High) |
| 0x68 | DS3231 RTC – Konflikt mit MPU-6050! | nicht änderbar |
| 0x57 | AT24C32 EEPROM auf dem DS3231-Modul | 0x50–0x57 (Jumper) |
| 0x76 | BMP280 / BME280 | 0x77 (SDO auf High) |
| 0x29 | VL53L0X ToF-Sensor | per Software änderbar |
| 0x27 | LCD mit PCF8574-Backpack | 0x20–0x27 (Lötbrücken) |
| 0x70 | TCA9548A Multiplexer | 0x70–0x77 |
⚠️ Der Klassiker – 0x68 doppelt belegt: MPU-6050 und DS3231 nutzen beide ab Werk die Adresse 0x68. Hängst du beide an denselben Bus, antworten sie gleichzeitig, und du bekommst Datenmüll oder gar nichts. Glück im Unglück: Der MPU-6050 lässt sich umadressieren – leg seinen AD0-Pin auf VCC, und er hört fortan auf 0x69. Der DS3231 bleibt stur auf 0x68, seine Adresse ist im Chip festverdrahtet.
2Verkabelung: Vier Module an zwei Leitungen
Das Schöne am Bus: Alle Module hängen parallel an denselben zwei Leitungen. Auf dem Breadboard nutzt du dafür am besten zwei freie Reihen als SDA- und SCL-Schiene.
| Modul | VCC | GND | SDA | SCL | Adresse |
|---|---|---|---|---|---|
| OLED SSD1306 | 5V | GND | A4 | A5 | 0x3C |
| BMP280 | 3V3 oder 5V* | GND | A4 | A5 | 0x76 |
| MPU-6050 (AD0 auf VCC) | 5V | GND | A4 | A5 | 0x69 |
| DS3231 RTC | 5V | GND | A4 | A5 | 0x68 |
| VL53L0X | 3V3 oder 5V* | GND | A4 | A5 | 0x29 |
* Diese Breakouts haben einen eigenen Spannungsregler und einen Pegelwandler an Bord und vertragen deshalb beides. Der nackte Chip darunter läuft nur mit 3,3 V – häng also nie einen blanken BMP280-Chip ohne Breakout an 5 V.
ℹ️ Gemeinsame Masse nicht vergessen: Wenn du Module aus einer separaten Stromquelle versorgst, müssen die Massen von Arduino und Netzteil verbunden sein. Ohne gemeinsamen GND hat der Bus keine Bezugsspannung, und du misst nur Zufall. Das ist der zweithäufigste Grund für „Scanner findet nichts“ – gleich nach vertauschtem SDA/SCL.
3Alle Sensoren gleichzeitig auslesen
Jetzt der Beweis, dass es funktioniert: BMP280, MPU-6050 und DS3231 gleichzeitig am Bus, Ausgabe auf dem OLED. Installiere vorher über den Bibliotheksverwalter Adafruit BMP280 Library, Adafruit MPU6050, RTClib, Adafruit SSD1306 und Adafruit GFX Library.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_MPU6050.h>
#include <RTClib.h>
Adafruit_SSD1306 display(128, 64, &Wire, -1);
Adafruit_BMP280 bmp;
Adafruit_MPU6050 mpu;
RTC_DS3231 rtc;
bool bmpOk = false, mpuOk = false, rtcOk = false;
void setup() {
Serial.begin(9600);
Wire.begin();
// --- OLED auf 0x3C ---
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED (0x3C) nicht gefunden!");
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
// --- BMP280 auf 0x76 (manche Module: 0x77) ---
bmpOk = bmp.begin(0x76);
if (!bmpOk) bmpOk = bmp.begin(0x77);
if (!bmpOk) Serial.println("BMP280 nicht gefunden (0x76/0x77)");
// --- MPU-6050 auf 0x69, weil AD0 auf VCC liegt ---
mpuOk = mpu.begin(0x69);
if (!mpuOk) Serial.println("MPU-6050 nicht gefunden (0x69)");
// --- DS3231 auf 0x68 ---
rtcOk = rtc.begin();
if (!rtcOk) Serial.println("DS3231 nicht gefunden (0x68)");
// Uhrzeit beim ersten Start setzen
if (rtcOk && rtc.lostPower()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
Serial.println("RTC neu gestellt.");
}
Serial.println("Setup fertig.");
}
void loop() {
display.clearDisplay();
display.setCursor(0, 0);
// --- Uhrzeit ---
if (rtcOk) {
DateTime jetzt = rtc.now();
display.printf("%02d:%02d:%02d %02d.%02d.\n",
jetzt.hour(), jetzt.minute(), jetzt.second(),
jetzt.day(), jetzt.month());
} else {
display.println("RTC ?");
}
// --- Luftdruck & Temperatur ---
if (bmpOk) {
display.printf("T: %.1f C\n", bmp.readTemperature());
display.printf("p: %.0f hPa\n", bmp.readPressure() / 100.0F);
} else {
display.println("BMP280 ?");
}
// --- Lage ---
if (mpuOk) {
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
display.printf("aX:%5.1f aY:%5.1f\n", a.acceleration.x, a.acceleration.y);
display.printf("aZ:%5.1f\n", a.acceleration.z);
} else {
display.println("MPU6050 ?");
}
display.display();
delay(500);
}
Vier I2C-Geräte, vier Adressen, zwei Kabel. Genau dafür wurde der Bus erfunden. Beachte das Muster mit den bmpOk/mpuOk/rtcOk-Flags: So läuft der Sketch weiter, auch wenn ein Modul fehlt – statt in einer while(true)-Endlosschleife hängenzubleiben, siehst du auf dem Display ein Fragezeichen und weißt sofort, wer fehlt.
4Bus-Geschwindigkeit anpassen
Standardmäßig läuft I2C im Standard Mode mit 100 kHz. Das ist konservativ und funktioniert immer. Wenn du ein OLED mit 128x64 Pixeln 20-mal pro Sekunde neu zeichnen willst, wird es damit aber eng – dann lohnt der Fast Mode mit 400 kHz.
void setup() {
Wire.begin();
// Bustakt setzen - NACH Wire.begin()!
Wire.setClock(400000); // 400 kHz Fast Mode
// Wire.setClock(100000); // 100 kHz Standard (Default)
// Wire.setClock(10000); // 10 kHz - fuer lange Kabel
Serial.begin(9600);
}
| Modus | Takt | Wann nutzen? |
|---|---|---|
| Low Speed | 10 kHz | lange Kabel, störige Umgebung |
| Standard Mode | 100 kHz | Default, läuft immer |
| Fast Mode | 400 kHz | Displays, häufige Sensorabfragen |
| Fast Mode Plus | 1 MHz | nur ESP32/RP2040, kurze Leitungen |
⚠️ Der langsamste Teilnehmer gibt den Takt vor: Fast Mode funktioniert nur, wenn alle Geräte am Bus ihn beherrschen. Ein einziges altes Modul, das nur 100 kHz kann, lässt bei 400 kHz den ganzen Bus zusammenbrechen – nicht nur seine eigene Kommunikation. Wenn nach dem Umstellen auf 400 kHz plötzlich gar nichts mehr geht, ist das die erste Verdächtige.
5Adresskonflikte: Wenn Umadressieren nicht geht
Zwei MPU-6050 gleichzeitig? Kein Problem – AD0 des einen auf GND (0x68), des anderen auf VCC (0x69). Aber drei MPU-6050? Oder vier VL53L0X-Sensoren für einen Roboter? Ab hier gehen dir die Adressen aus. Dafür gibt es zwei Lösungen.
Lösung A: Software-Umadressierung (VL53L0X)
Manche Chips lassen sich per Software umadressieren – die neue Adresse gilt allerdings nur bis zum nächsten Stromausfall. Der Trick: Alle Sensoren zunächst über ihren XSHUT-Pin abschalten, dann einen nach dem anderen aufwecken und umadressieren.
#include <Wire.h>
#include <Adafruit_VL53L0X.h>
#define XSHUT_1 2
#define XSHUT_2 3
#define XSHUT_3 4
Adafruit_VL53L0X sensor1, sensor2, sensor3;
void setup() {
Serial.begin(9600);
// Alle Sensoren per XSHUT in den Reset ziehen
pinMode(XSHUT_1, OUTPUT);
pinMode(XSHUT_2, OUTPUT);
pinMode(XSHUT_3, OUTPUT);
digitalWrite(XSHUT_1, LOW);
digitalWrite(XSHUT_2, LOW);
digitalWrite(XSHUT_3, LOW);
delay(10);
// Sensor 1 aufwecken, auf 0x30 umziehen
digitalWrite(XSHUT_1, HIGH);
delay(10);
if (!sensor1.begin(0x30)) Serial.println("Sensor 1 fehlt!");
// Sensor 2 aufwecken, auf 0x31 umziehen
digitalWrite(XSHUT_2, HIGH);
delay(10);
if (!sensor2.begin(0x31)) Serial.println("Sensor 2 fehlt!");
// Sensor 3 bleibt auf der Standardadresse 0x29
digitalWrite(XSHUT_3, HIGH);
delay(10);
if (!sensor3.begin(0x29)) Serial.println("Sensor 3 fehlt!");
Serial.println("Drei ToF-Sensoren bereit.");
}
void loop() {
VL53L0X_RangingMeasurementData_t m1, m2, m3;
sensor1.rangingTest(&m1, false);
sensor2.rangingTest(&m2, false);
sensor3.rangingTest(&m3, false);
Serial.print("Links: ");
Serial.print(m1.RangeStatus != 4 ? m1.RangeMilliMeter : 0);
Serial.print(" mm | Mitte: ");
Serial.print(m2.RangeStatus != 4 ? m2.RangeMilliMeter : 0);
Serial.print(" mm | Rechts: ");
Serial.print(m3.RangeStatus != 4 ? m3.RangeMilliMeter : 0);
Serial.println(" mm");
delay(200);
}
Damit steuerst du drei VL53L0X-Sensoren gleichzeitig – links, Mitte, rechts. Perfekt für einen Roboter, der Hindernissen ausweichen soll. Mehr zum Sensor selbst steht im Artikel VL53L0X Laser-Entfernungssensor mit Arduino.
Lösung B: Der TCA9548A Multiplexer
Wenn sich ein Chip überhaupt nicht umadressieren lässt – acht identische Sensoren mit fester Adresse zum Beispiel – hilft ein I2C-Multiplexer. Der TCA9548A sitzt zwischen Arduino und Sensoren und schaltet acht getrennte Bus-Kanäle durch. Jeder Kanal darf dieselbe Adresse tragen, weil immer nur einer aktiv ist:
#include <Wire.h>
#define TCA_ADDR 0x70
// Kanal 0-7 am Multiplexer aktivieren
void tcaKanal(uint8_t kanal) {
if (kanal > 7) return;
Wire.beginTransmission(TCA_ADDR);
Wire.write(1 << kanal); // Bitmaske: genau ein Kanal an
Wire.endTransmission();
}
void setup() {
Wire.begin();
Serial.begin(9600);
while (!Serial) delay(10);
// Jeden Kanal einzeln scannen
for (uint8_t k = 0; k < 8; k++) {
tcaKanal(k);
Serial.print("--- Kanal ");
Serial.print(k);
Serial.println(" ---");
for (uint8_t adr = 1; adr < 127; adr++) {
if (adr == TCA_ADDR) continue; // den Muxer selbst ueberspringen
Wire.beginTransmission(adr);
if (Wire.endTransmission() == 0) {
Serial.print(" Geraet bei 0x");
Serial.println(adr, HEX);
}
}
}
Serial.println("Scan fertig.");
}
void loop() {
// Beispiel: drei identische Sensoren nacheinander auslesen
for (uint8_t k = 0; k < 3; k++) {
tcaKanal(k);
// ... hier ganz normal den Sensor auslesen,
// als haenge nur er allein am Bus
delay(100);
}
}
💡 Der Denkfehler beim Multiplexer: Viele erwarten, dass der TCA9548A die Adressen übersetzt. Tut er nicht. Er ist schlicht ein elektronischer Umschalter – er verbindet den Hauptbus mit genau einem (oder mehreren) der acht Unterbüsse. Deshalb musst du vor jedem Sensorzugriff tcaKanal() aufrufen. Vergisst du das, redest du mit dem falschen Sensor.
Troubleshooting: Der I2C-Bus schweigt
⚠️ Scanner findet gar nichts: Arbeite diese Liste in dieser Reihenfolge ab. In 95 % der Fälle steckt einer dieser vier Punkte dahinter – (1) SDA und SCL vertauscht, (2) GND nicht verbunden, (3) Modul bekommt keine Versorgungsspannung, (4) Pull-Ups fehlen komplett. Miss mit dem Multimeter: Im Ruhezustand müssen sowohl SDA als auch SCL auf VCC-Niveau liegen. Liegt eine der beiden auf 0 V, hängt der Bus.
⚠️ Scanner findet 0x00 und alle Adressen: Klassisches Zeichen für einen Kurzschluss zwischen SDA und GND oder dafür, dass ein Modul die Leitung dauerhaft nach unten zieht. Zieh alle Module ab und steck sie einzeln wieder an – so findest du den Übeltäter in einer Minute.
⚠️ Es läuft mit zwei Modulen, mit vier nicht mehr: Zu viele parallele Pull-Ups (siehe oben). Rechne nach: Vier Module mit je 4,7 kΩ ergeben 1,2 kΩ Gesamtwiderstand. Entferne die Pull-Ups auf allen Modulen bis auf eines.
⚠️ Kabel länger als 50 cm, dann Aussetzer: Die Buskapazität steigt mit der Kabellänge, die Flanken werden flach. Gegenmaßnahmen in dieser Reihenfolge: Takt auf 50 oder 10 kHz senken, Pull-Ups auf 2,2 kΩ verkleinern, verdrilltes Kabel nehmen (SDA mit GND verdrillen, SCL mit GND). Über zwei Meter wird I2C prinzipiell unzuverlässig – dafür nimmst du besser CAN-Bus.
⚠️ Sketch hängt sich sporadisch auf: Der berüchtigte Bus-Lockup. Wenn der Master mitten in einer Übertragung resettet, kann ein Slave SDA dauerhaft auf Low halten und wartet ewig auf Taktimpulse. Abhilfe: Vor Wire.begin() neun manuelle Taktimpulse auf SCL ausgeben, um den Slave freizuschaufeln – oder pragmatisch: kurz den Strom aller Module trennen.
⚠️ 5-V-Board mit 3,3-V-Sensor: Ein Arduino UNO zieht SDA/SCL auf 5 V. Ein reiner 3,3-V-Chip ohne Pegelwandler nimmt das dauerhaft übel. Fertige Breakouts wie BMP280 oder MPU-6050 haben den Wandler an Bord und sind unkritisch – bei nackten Chips brauchst du einen Level-Shifter.
Praxistipps
- Scanner vor jedem Projekt: Zehn Sekunden Scan sparen dir eine Stunde Bibliotheks-Debugging. Wenn der Scanner das Modul nicht sieht, findet es auch keine Library.
- Adressen dokumentieren: Schreib die Adresse jedes Moduls als Kommentar in den Sketch. Beim nächsten Umbau in sechs Monaten dankst du dir das.
- Ein Modul nach dem anderen: Bau den Bus schrittweise auf und lass nach jedem neuen Modul den Scanner laufen. Dann weißt du sofort, welches Modul den Bus zerlegt.
-
endTransmission()-Rückgabewert prüfen: 0 = alles gut, 2 = keine Antwort auf die Adresse, 3 = keine Antwort auf die Daten, 4 = sonstiger Fehler, 5 = Timeout. Diese Zahl sagt dir mehr als jede Vermutung. -
Mehr Pins auf dem ESP32: Der ESP32 hat zwei komplett getrennte I2C-Controller. Mit
TwoWire zweiterBus = TwoWire(1);undzweiterBus.begin(sda2, scl2);baust du dir einen zweiten Bus – damit löst du Adresskonflikte ganz ohne Multiplexer. - OLED sparsam neu zeichnen: Ein voller Bildschirm-Refresh schiebt 1024 Byte über den Bus. Bei 100 kHz dauert das rund 100 ms. Zeichne nur, was sich ändert, oder geh auf 400 kHz.
🚀 Deine I2C-Bauteile bei MAKEROO
Alle Module aus diesem Tutorial – alle sprechen I2C, alle passen an denselben Bus:
- Arduino UNO R3 (ATmega328P, USB-C)
- 0.96 Zoll OLED Display SSD1306 (0x3C)
- BMP280 Luftdruck- & Temperatursensor (0x76)
- GY-521 MPU-6050 Gyroskop & Beschleunigungssensor (0x68/0x69)
- DS3231 Echtzeituhr mit AT24C32 EEPROM (0x68/0x57)
- GY-530 VL53L0X Laser-Entfernungssensor (0x29)
- 600x Widerstands-Sortiment (für Pull-Ups)
- Solderless Breadboard 400 Kontakte
Fazit
I2C ist der unscheinbare Held fast jedes Maker-Projekts: zwei Kabel, ein Dutzend Module, und der Arduino behält trotzdem seine Pins für Wichtigeres. Wenn du drei Dinge aus diesem Artikel mitnimmst, dann diese: Erstens läuft der I2C-Scanner vor jedem Projekt – er beantwortet in zehn Sekunden die Frage, ob dein Problem in der Hardware oder im Code steckt. Zweitens sind Pull-Ups keine Nebensächlichkeit, sondern der Grund, warum ein Bus mit vier Modulen anders funktioniert als mit einem. Und drittens sind Adresskonflikte kein Weltuntergang: AD0-Pin umlegen, per Software umadressieren oder im Extremfall einen TCA9548A davorsetzen.
Wer diese Zusammenhänge einmal verstanden hat, sucht bei einem schwarzen OLED nicht mehr blind in der Bibliothek, sondern greift zum Scanner und zum Multimeter – und findet die Ursache meist in unter zwei Minuten. Genau das ist der Unterschied zwischen Nachbauen und Verstehen.