I2C Nedir? SDA, SCL, Pull-up Direnci ve Arduino I2C Tarayıcı
I2C nedir, nasıl çalışır? SDA ve SCL hatları, 7 bit adresler, pull-up direnci hesabı, I2C tarayıcı kodu, adres çakışması ve Uno, ESP32, Pico pinleri.
I2C (Inter-Integrated Circuit), yalnızca iki sinyal kablosuyla (SDA ve SCL) bir mikrodenetleyicinin onlarca sensör, ekran ve modülle konuşmasını sağlayan seri haberleşme protokolüdür. "I-kare-C" diye okunur; bazı veri sayfalarında IIC ya da TWI (Two Wire Interface) olarak geçer. Arduino projelerinde kullandığın I2C LCD ekran, OLED ekran, MPU6050 ivmeölçer, BMP280 basınç sensörü ve DS1307 saat modülü bu protokolle çalışır; hepsini aynı iki kabloya paralel bağlayabilir, her birine kendi adresiyle ulaşabilirsin.
Bu rehberde I2C'nin elektriksel olarak nasıl çalıştığını, adreslerin ne anlama geldiğini, pull-up direncinin neden şart olduğunu ve değerinin nasıl hesaplandığını öğreneceksin. Ardından Arduino Uno, ESP32 ve Raspberry Pi Pico için pin tablosunu, hattaki cihazları bulan I2C tarayıcı kodunu, kütüphanesiz yazmaç okuma örneğini ve adres çakışması gibi sık karşılaşılan sorunların çözümlerini adım adım göreceksin.

I2C nedir, nasıl çalışır?
I2C, 1982'de Philips (bugünkü NXP) tarafından aynı devre kartı üzerindeki yongaların az kabloyla haberleşmesi için geliştirildi. Hatta iki rol vardır: iletişimi başlatan ve saati üreten denetleyici (controller, eski adıyla master) ve ona cevap veren hedef cihazlar (target, eski adıyla slave). Arduino projelerinde denetleyici neredeyse her zaman Arduino, ESP32 ya da Pico'dur; sensörler ve ekranlar ise hedef cihazdır.
- SDA (Serial Data): Verinin iki yönde de taşındığı hat. Denetleyici adres ve komut gönderir, sensör ölçüm sonucunu aynı hattan geri yollar.
- SCL (Serial Clock): Saat hattı. Her saat darbesinde SDA üzerindeki bir bit okunur; saati denetleyici üretir.
- GND (ortak toprak): Sinyallerin referansı. Ayrı beslenen modüllerde bile tüm GND'ler birleştirilmelidir.
Hatlar açık akaçlı (open-drain) çalışır: hiçbir cihaz hattı 1'e sürmez, yalnızca 0'a çeker. Hattı 1 seviyesinde tutan şey, SDA ve SCL'yi besleme gerilimine bağlayan pull-up dirençleridir. Bu sayede iki cihaz aynı anda konuşmaya çalışsa bile kısa devre oluşmaz; birinin 0'a çektiği hattı herkes 0 olarak görür. Bir I2C mesajı şu sırayla ilerler:
- START: SCL 1 iken denetleyici SDA'yı 1'den 0'a çeker; hattaki tüm cihazlar dinlemeye başlar.
- Adres ve yön biti: 7 bitlik adres, ardından okuma (1) ya da yazma (0) biti gönderilir.
- ACK: Adres kendisine ait olan cihaz 9. saat darbesinde SDA'yı 0'a çekerek "buradayım" der. Kimse çekmezse buna NACK denir.
- Veri baytları: Her bayt 8 bit olarak gönderilir ve alıcı her birinin ardından ACK verir. Çoğu sensörde ilk bayt, okunacak ya da yazılacak yazmacın (register) numarasıdır.
- STOP: SCL 1 iken SDA 0'dan 1'e çıkar ve hat serbest kalır. Okuma işlemlerinde STOP yerine tekrarlı START (repeated start) kullanılarak hat bırakılmadan yön değiştirilir.
I2C'yi Arduino dünyasındaki diğer iki yaygın protokolle karşılaştırmak, hangi durumda tercih edileceğini netleştirir:
| Özellik | I2C | SPI | UART (Seri) |
|---|---|---|---|
| Sinyal kablosu | 2 (SDA, SCL) | 3 ortak (MOSI, MISO, SCK) + her cihaza ayrı CS | 2 (TX, RX) |
| Cihaz sayısı | Aynı hatta 100'den fazla adres | Boş CS pini kadar | Genellikle 2 cihaz |
| Tipik hız | 100 kHz, 400 kHz, 1 MHz | 10 MHz ve üzeri | 9600 – 115200 baud |
| Cihaz seçimi | Adresle | CS pini ile | Yok, noktadan noktaya |
| Tipik kullanım | Sensör, saat, küçük ekran, EEPROM | SD kart, TFT ekran, RFID | GPS, Bluetooth, bilgisayar bağlantısı |
I2C hızları ve teknik sınırlar
| Mod | En yüksek hız | En uzun yükselme süresi | Nerede kullanılır? |
|---|---|---|---|
| Standart mod (Sm) | 100 kHz | 1000 ns | Varsayılan, uzun kablolar |
| Hızlı mod (Fm) | 400 kHz | 300 ns | OLED, MPU6050, BMP280 |
| Hızlı mod artı (Fm+) | 1 MHz | 120 ns | Pico ve bazı yeni sensörler |
| Yüksek hız modu (Hs) | 3,4 MHz | 80 ns (400 pF), özel sürücü gerekir | Hobi projelerinde nadiren |
Arduino'nun Wire kütüphanesi varsayılan olarak 100 kHz ile başlar; sensörlerin çoğu 400 kHz'i de destekler ve Wire.setClock(400000) satırıyla bu hıza geçebilirsin. Hızı yükseltmek ekranların daha akıcı yenilenmesini sağlar ama hattı kablo uzunluğuna ve pull-up direncine karşı daha hassas hale getirir. Standarda göre hattın toplam kapasitansı (kablolar ve cihaz pinleri) 400 pF'ı geçmemelidir. Sıradan jumper ve şerit kablolar metre başına 50–100 pF, her cihaz pini de 10 pF'a kadar kapasitans ekler; bu yüzden I2C aynı kart üzerinde ya da birkaç on santimlik kablolarla çalışmak için tasarlanmıştır. 1 metreyi aşan mesafelerde hızı düşürmek, daha güçlü pull-up kullanmak ya da P82B715 gibi hat uzatıcılar eklemek gerekir.
I2C adresleri: 7 bit, 8 bit ve ayrılmış adresler
Hattaki her cihazın 7 bitlik bir adresi vardır; bu da teorik olarak 128 adres eder. 0x00–0x07 ve 0x78–0x7F aralıkları özel işler için ayrıldığından kullanılabilecek adresler 0x08 ile 0x77 arasındaki 112 adrestir. Adres genellikle yonganın üreticisi tarafından sabitlenir; birçok modülde ise A0, A1, A2 ya da AD0 gibi lehim köprüleri ve pinlerle adresin son bitlerini değiştirebilirsin.
Kafa karıştıran nokta şudur: bazı veri sayfaları ve modüllerin arkasındaki yazılar adresi yön bitiyle birlikte 8 bit olarak verir. Örneğin OLED kartının arkasında "0x78" yazar ama koddaki adres 0x3C'dir; LCD modülünde 0x4E yazıyorsa koddaki karşılığı 0x27'dir. Kural basittir: 8 bitlik değeri 2'ye böl (bir bit sağa kaydır), 7 bitlik adresi bulursun. Arduino, ESP32 ve MicroPython kütüphanelerinin hepsi 7 bitlik adres bekler.
| Modül | Yonga | Varsayılan adres | Değiştirilebilir mi? |
|---|---|---|---|
| I2C LCD modülü (16x2, 20x4) | PCF8574 / PCF8574A | 0x27 / 0x3F | A0–A2 köprüleriyle 0x20–0x27 ya da 0x38–0x3F |
| 0,96 inç OLED | SSD1306 | 0x3C | Arkadaki dirençle 0x3D |
| İvmeölçer ve jiroskop | MPU6050 | 0x68 | AD0 = 1 ise 0x69 |
| Gerçek zamanlı saat | DS1307 / DS3231 | 0x68 | Hayır |
| Basınç ve sıcaklık | BMP280 / BME280 | 0x76 ya da 0x77 | SDO pinine göre |
| Işık şiddeti | BH1750 | 0x23 | ADDR = 1 ise 0x5C |
| 16 bit ADC | ADS1115 | 0x48 | ADDR pini ile 0x48–0x4B |
| 16 kanallı servo ve PWM sürücü | PCA9685 | 0x40 | A0–A5 köprüleriyle 0x40'tan başlayan onlarca adres |
| EEPROM bellek | AT24C32 / AT24C256 | 0x50 | A0–A2 ile 0x50–0x57 |
| I2C çoklayıcı | TCA9548A | 0x70 | A0–A2 ile 0x70–0x77 |
Pull-up dirençleri: neden gerekli ve değeri nasıl seçilir?
I2C hatlarında cihazlar yalnızca 0'a çekebildiğinden 1 seviyesini pull-up dirençleri sağlar. Direnç çok büyük olursa hat kapasitansı yüzünden 0'dan 1'e geçiş yavaşlar, sinyalin köşeleri yuvarlanır ve yüksek hızda bitler yanlış okunur. Direnç çok küçük olursa cihazın hattı 0'a çekerken akıtması gereken akım artar; standart, bir cihazın 0,4 V'ta en az 3 mA akıtabilmesini şart koşar; bu yüzden pull-up direnci hat akımını bu değerin altında tutmalıdır.
İki sınırı veren formüller şunlardır: en küçük direnç R(min) = (VCC − 0,4 V) / 3 mA, en büyük direnç ise R(max) = t(yükselme) / (0,8473 × C(hat)). 5 V için R(min) = 4,6 V / 0,003 A ≈ 1,53 kΩ, 3,3 V için ≈ 0,97 kΩ çıkar. 100 pF kapasitanslı kısa bir hatta 100 kHz için R(max) ≈ 11,8 kΩ, 400 kHz için ≈ 3,5 kΩ olur. Bu yüzden pratikte 100 kHz için 4,7 kΩ, 400 kHz ve kalabalık hatlar için 2,2 kΩ en sık kullanılan değerlerdir. Direncin renk kodunu çözmek için Direnç Renk Kodu, direnç ve kapasitansın oluşturduğu gecikmeyi görmek için RC Zaman Sabiti araçlarını kullanabilirsin.
| Durum | Önerilen pull-up | Not |
|---|---|---|
| Tek modül, kısa kablo, 100 kHz | 4,7 kΩ – 10 kΩ | Modüllerin çoğunda zaten vardır |
| Birkaç modül, 400 kHz | 2,2 kΩ – 4,7 kΩ | Modüllerdeki dirençler paralel bağlanır |
| 50 cm'den uzun kablo | 2,2 kΩ ve 100 kHz | SDA ve SCL'yi birbiriyle bükme; her birini GND ile bük |
| 3,3 V hat (ESP32, Pico) | 2,2 kΩ – 4,7 kΩ | Dirençleri 5 V'a değil 3,3 V'a bağla |
Arduino Uno'da Wire.begin() çağrıldığında ATmega328P'nin 20–50 kΩ'luk dahili pull-up dirençleri de açılır. Bu dirençler tek bir modül ve 10–20 cm'lik kabloyla çoğu zaman yeter ama güvenilir değildir; harici direnç her zaman daha iyidir. Üzerinde pull-up olmayan çıplak bir sensör kartı kullanıyorsan SDA ve SCL'den VCC'ye birer 4,7 kΩ direnç eklemeyi unutma.
I2C pinleri: Arduino Uno, Mega, ESP32, ESP8266 ve Pico
| Kart | SDA | SCL | Not |
|---|---|---|---|
| Arduino Uno / Nano | A4 | A5 | Uno R3'te AREF yanındaki SDA ve SCL pinleri A4/A5 ile aynı hattır |
| Arduino Mega 2560 | 20 | 21 | Mega'da A4 ve A5 I2C değildir |
| Arduino Leonardo / Micro | D2 | D3 | Dijital pinlerdir |
| ESP32 (DevKit) | GPIO 21 | GPIO 22 | Wire.begin(SDA, SCL) ile başka pinler seçilebilir; ikinci hat Wire1 |
| ESP8266 NodeMCU | D2 (GPIO 4) | D1 (GPIO 5) | Yazılımsal I2C, pinler değiştirilebilir |
| Raspberry Pi Pico | GP4 (I2C0) | GP5 (I2C0) | I2C0 ve I2C1 birçok pin çiftinde kullanılabilir |
Adım adım: I2C tarayıcı kodu ile adres bulma
Yeni bir modül aldığında ilk iş, hattaki cihazların adreslerini öğrenmektir. I2C tarayıcı, 0x08'den 0x77'ye kadar her adrese boş bir mesaj gönderir ve ACK veren adresleri listeler. Böylece hem modülün doğru bağlandığını hem de kodda hangi adresi yazman gerektiğini aynı anda öğrenirsin.
- Modülün GND'sini Arduino'nun GND'sine, VCC'sini 5V'a (yalnızca 3,3 V destekleyen modüllerde 3.3V'a) bağla.
- SDA'yı A4'e, SCL'yi A5'e bağla. Birden fazla modül varsa hepsinin SDA'larını ve SCL'lerini breadboard üzerinde birleştir.
- Aşağıdaki kodu yükle ve Seri Monitör'ü 115200 baud hızında aç.
- Listelenen adresleri not al. Hiçbir şey çıkmıyorsa kabloları, ortak GND'yi ve pull-up dirençlerini kontrol et.
- Modülleri tek tek çıkarıp takarak hangi adresin hangi cihaza ait olduğunu doğrula; tarayıcı her 5 saniyede bir yeniden tarar.
1#include <Wire.h>
2
3void printHex(byte addr) {
4 Serial.print(F("0x"));
5 if (addr < 16) Serial.print('0'); // tek haneliye sıfır ekle / pad single digit
6 Serial.print(addr, HEX);
7}
8
9void setup() {
10 Serial.begin(115200);
11 Wire.begin(); // Uno: A4 = SDA, A5 = SCL
12#if defined(ARDUINO_ARCH_AVR)
13 Wire.setWireTimeout(3000, true); // AVR (Uno, Nano, Mega): hat kilitlenirse 3 ms sonra kurtar / recover a stuck bus after 3 ms
14#endif
15 Serial.println(F("I2C tarayici / I2C scanner"));
16}
17
18void loop() {
19 byte found = 0;
20 for (byte addr = 0x08; addr <= 0x77; addr++) { // geçerli 7 bit adresler / valid 7-bit addresses
21 Wire.beginTransmission(addr);
22 byte err = Wire.endTransmission(); // 0 = cihaz ACK verdi / device acknowledged
23 if (err == 0) {
24 Serial.print(F("Bulundu / found: "));
25 printHex(addr);
26 Serial.println();
27 found++;
28 } else if (err == 4 || err == 5) {
29 Serial.print(F("Hat hatasi / bus error at "));
30 printHex(addr);
31 Serial.println();
32 }
33 }
34 if (found == 0) {
35 Serial.println(F("Cihaz yok: kablolari ve pull-up'lari kontrol et / no devices: check wiring and pull-ups"));
36 } else {
37 Serial.print(found);
38 Serial.println(F(" cihaz bulundu / device(s) found"));
39 }
40 Serial.println();
41 delay(5000); // 5 sn sonra yeniden tara / rescan after 5 s
42}| endTransmission() sonucu | Anlamı | Ne yapmalı? |
|---|---|---|
| 0 | Cihaz adresini tanıdı (ACK) | Bu adresi kodunda kullan |
| 1 | Veri tampona sığmadı | Tarayıcıda görülmez; Uno'da tek seferde 32 bayttan fazla yazma |
| 2 | Adrese NACK geldi | O adreste cihaz yok, tarama sırasında normaldir |
| 3 | Veriye NACK geldi | Cihaz komutu reddetti; yazmaç numarasını kontrol et |
| 4 | Diğer hat hatası | Kısa devre, eksik pull-up ya da gürültü |
| 5 | Zaman aşımı | Hat kilitlendi; kabloları ve beslemeyi kontrol et |
Koddaki setWireTimeout satırı önemlidir: SDA ya da SCL kısa devre olduğunda veya bir cihaz hattı 0'da bırakıp takıldığında, Uno'nun Wire kütüphanesi varsayılan ayarla sonsuza kadar bekleyip programı dondurabilir. Zaman aşımı açıkken kütüphane 3 ms sonra pes eder, I2C donanımını sıfırlar ve tarayıcı sorunu hata koduyla raporlar. Bu satır yalnızca AVR tabanlı kartlarda (Uno, Nano, Mega) derlensin diye #if ile korunmuştur; ESP32 ve ESP8266'nın Wire kütüphaneleri zaten kendi zaman aşımı korumasıyla gelir, bu yüzden aynı kod üç platformda da değiştirmeden derlenir ve çalışır.
Kütüphanesiz I2C: yazmaç okuma ve yazma
Kütüphaneler işi kolaylaştırır ama arka planda hepsi aynı şeyi yapar: cihaza yazmaç numarasını gönderir, sonra o yazmaçtan bayt okur ya da yazar. Bunu bir kez kendin yapmak, yeni bir sensörün veri sayfasını okuyup kütüphane olmadan da kullanabilmeni sağlar. Aşağıdaki örnek MPU6050 sensörünü uyku modundan çıkarır, kimlik yazmacını (WHO_AM_I) okur ve ardından sıcaklık ile Z ekseni ivmesini ham değerlerden hesaplar.

1#include <Wire.h>
2
3const byte MPU_ADDR = 0x68; // AD0 GND'de; AD0 = 3.3V ise 0x69 / AD0 low; 0x69 if AD0 high
4
5void writeReg(byte reg, byte value) {
6 Wire.beginTransmission(MPU_ADDR);
7 Wire.write(reg); // önce yazmaç adresi / register address first
8 Wire.write(value); // sonra veri / then the data
9 Wire.endTransmission(); // STOP gönder / send STOP
10}
11
12int16_t readWord(byte reg) {
13 Wire.beginTransmission(MPU_ADDR);
14 Wire.write(reg);
15 Wire.endTransmission(false); // STOP yok, tekrarlı START / no STOP, repeated START
16 Wire.requestFrom(MPU_ADDR, (byte)2); // 2 bayt iste / request 2 bytes
17 uint8_t hi = Wire.read();
18 uint8_t lo = Wire.read();
19 return (int16_t)(((uint16_t)hi << 8) | lo);
20}
21
22void setup() {
23 Serial.begin(115200);
24 Wire.begin();
25 Wire.setClock(400000); // hızlı mod 400 kHz / fast mode 400 kHz
26 writeReg(0x6B, 0x00); // PWR_MGMT_1: uykudan uyandır / wake up from sleep
27 Wire.beginTransmission(MPU_ADDR);
28 Wire.write(0x75); // WHO_AM_I yazmacı / WHO_AM_I register
29 Wire.endTransmission(false);
30 Wire.requestFrom(MPU_ADDR, (byte)1);
31 Serial.print(F("WHO_AM_I = 0x"));
32 Serial.println(Wire.read(), HEX); // 68 beklenir / expect 68
33}
34
35void loop() {
36 int16_t raw = readWord(0x41); // TEMP_OUT_H ve TEMP_OUT_L / TEMP_OUT_H and TEMP_OUT_L
37 float tempC = raw / 340.0 + 36.53; // veri sayfasındaki formül / datasheet formula
38 int16_t az = readWord(0x3F); // Z ekseni ivmesi / Z-axis acceleration
39 Serial.print(F("Sicaklik / temp: "));
40 Serial.print(tempC, 1);
41 Serial.print(F(" C AccZ: "));
42 Serial.println(az / 16384.0, 2); // +-2g aralığında 16384 = 1 g / 16384 = 1 g at +-2g
43 delay(500);
44}Okuma fonksiyonundaki endTransmission(false) satırına dikkat et: STOP göndermeden tekrarlı START ile yön değiştirir, böylece başka bir cihaz araya giremez ve sensör hangi yazmacın istendiğini unutmaz. WHO_AM_I değeri 0x68 çıkıyorsa iletişim kusursuzdur. Ucuz klon modüllerde bu değer 0x70 ya da başka bir sayı olabilir; bu, yonganın MPU6500 gibi uyumlu ama farklı bir model olduğunu gösterir ve bazı hazır kütüphanelerin "sensör bulunamadı" demesinin sebebi budur. Sıcaklık formülü (ham değer / 340 + 36,53) doğrudan MPU6050 veri sayfasından gelir; ivme için ±2 g aralığında 16384 ham değer 1 g'ye karşılık gelir, yani masada düz duran sensör Z ekseninde yaklaşık 1,00 gösterir.
Aynı hatta birden fazla cihaz ve adres çakışması
I2C'nin en büyük avantajı, adresleri farklı olduğu sürece cihazları aynı iki kabloya paralel bağlayabilmendir. Örneğin bir LCD (0x27), bir OLED (0x3C), bir BMP280 (0x76) ve bir DS3231 saat (0x68) aynı A4 ve A5 pinlerini sorunsuz paylaşır; her kütüphane kendi adresine konuşur, diğer cihazlar sessizce dinler. Sorun, iki cihaz aynı adrese sahip olduğunda başlar: ikisi birden ACK verir, gönderdikleri veriler karışır ve genellikle ikisi de çalışmaz. Çözüm yolları şunlardır:
- Adres pinini değiştir: MPU6050'de AD0 pinini 3,3 V'a bağlarsan adres 0x69 olur ve DS3231 (0x68) ile çakışma biter.
- Lehim köprülerini kullan: LCD modüllerindeki A0–A2 köprüleri 8, ADS1115'in ADDR pini 4 farklı adres sunar.
- İkinci I2C hattı aç: ESP32'de Wire1, Pico'da I2C1 ile çakışan cihazı ayrı pinlere taşı.
- I2C çoklayıcı ekle: TCA9548A tek adresten (0x70) sekiz ayrı alt hat açar; aynı adresli sekiz OLED'i bile bağlayabilirsin.
- Adresi sabit cihazlar: DS1307 ya da HTU21D gibi bazı yongaların adresi hiç değişmez; bunlarda yalnızca ayrı hat ya da çoklayıcı çözüm olur.
ESP32 ile I2C: istediğin pinler ve iki ayrı hat
ESP32'de I2C donanımı pinlere esnek biçimde yönlendirilebilir. Varsayılan pinler GPIO 21 (SDA) ve GPIO 22 (SCL)'dir, ama Wire.begin(SDA, SCL) ile neredeyse istediğin iki GPIO'yu seçebilirsin. Klasik ESP32 ve ESP32-S3'te iki I2C denetleyicisi bulunduğu için aynı adresli iki sensörü iki ayrı hatta çalıştırabilirsin; ESP32-C3'te ise tek denetleyici vardır. GPIO 34–39 yalnızca giriş olduğundan I2C için kullanılamaz. Kartın tam pin haritası için Pinout aracına, ESP32'ye genel bir giriş için ESP32 Nedir? yazısına bakabilirsin.
1#include <Wire.h>
2
3// Klasik ESP32'de iki I2C denetleyicisi vardır: Wire ve Wire1 / the classic ESP32 has two I2C controllers: Wire and Wire1
4
5void scan(TwoWire &bus, const char *name) {
6 Serial.printf("%s:\n", name);
7 for (uint8_t addr = 0x08; addr <= 0x77; addr++) {
8 bus.beginTransmission(addr);
9 if (bus.endTransmission() == 0) {
10 Serial.printf(" bulundu / found 0x%02X\n", addr);
11 }
12 }
13}
14
15void setup() {
16 Serial.begin(115200);
17 Wire.begin(21, 22); // SDA, SCL: varsayılan pinler / default pins
18 Wire1.begin(32, 33, 400000); // SDA, SCL, hız: başka iki GPIO / SDA, SCL, speed: any two other GPIOs
19 scan(Wire, "Wire (SDA 21, SCL 22)");
20 scan(Wire1, "Wire1 (SDA 32, SCL 33)");
21}
22
23void loop() {
24}Raspberry Pi Pico ile I2C (MicroPython)
Pico'nun RP2040 yongasında I2C0 ve I2C1 adlı iki denetleyici vardır ve her biri birkaç farklı pin çiftine yönlendirilebilir. I2C0 için GP0/GP1, GP4/GP5, GP8/GP9, GP12/GP13, GP16/GP17 ve GP20/GP21; I2C1 için GP2/GP3, GP6/GP7, GP10/GP11, GP14/GP15, GP18/GP19 ve GP26/GP27 çiftleri kullanılabilir. Her çiftte çift numaralı pin SDA, tek numaralı pin SCL'dir. MicroPython'da tarayıcı tek satırdır: i2c.scan() ACK veren adreslerin listesini döndürür. Pico 3,3 V ile çalıştığı için modülleri 3V3(OUT) pininden beslemek en güvenli yoldur; RP2040 1 MHz'lik hızlı mod artıyı da desteklese de breadboard üzerinde 400 kHz'te kalmak daha az sürpriz çıkarır. Pico ile ilk adımlar için Raspberry Pi Pico Nedir? yazısına göz atabilirsin.
1from machine import Pin, I2C
2
3i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000) # I2C0: GP4 = SDA, GP5 = SCL
4devices = i2c.scan() # ACK veren adresler / addresses that ACK
5
6if devices:
7 for addr in devices:
8 print("Bulundu / found:", hex(addr))
9else:
10 print("Cihaz yok / no devices")
11
12# MPU6050 varsa WHO_AM_I yazmacını oku / if an MPU6050 is present, read WHO_AM_I
13if 0x68 in devices:
14 i2c.writeto_mem(0x68, 0x6B, b"\x00") # uykudan uyandır / wake up
15 who = i2c.readfrom_mem(0x68, 0x75, 1)[0]
16 print("WHO_AM_I:", hex(who)) # 0x68 beklenir / expect 0x68I2C ile proje fikirleri
- Mini hava istasyonu: BMP280 ile basınç ve sıcaklığı ölç, OLED ekranda göster; iki modül aynı iki kabloyu paylaşır.
- Dijital saat: DS3231 saat modülünden zamanı okuyup I2C LCD ekrana yazdır.
- Eğim göstergesi: MPU6050 ile açıyı hesapla, sonucu OLED'de bir su terazisi gibi çiz.
- Wi-Fi sensör düğümü: ESP8266 NodeMCU kartının D1 ve D2 pinlerine bağladığın sensörün değerlerini telefondan izle.
- 16 servolu robot kol: PCA9685 sürücüsüyle yalnızca iki pinden 16 servoyu kontrol et.
- Veri kaydedici: AT24C256 EEPROM'a dakikada bir ölçüm yaz; elektrik kesilse bile veriler kaybolmasın.
Sık yapılan hatalar ve çözümleri
| Belirti | Olası sebep | Çözüm |
|---|---|---|
| Tarayıcı hiçbir cihaz bulmuyor | SDA ve SCL yer değiştirmiş, ortak GND yok ya da modül beslenmiyor | Kabloları kontrol et; Uno'da A4 = SDA, A5 = SCL |
| Tarayıcı donuyor ya da her adreste hata veriyor | Hat kısa devre ya da pull-up eksik | setWireTimeout ekle; boştaki SDA ve SCL'de besleme gerilimini ölç |
| Kod derleniyor ama ekran boş | Kodda yanlış adres (0x27 yerine 0x3F) | Tarayıcının bulduğu adresi koda yaz |
| Kartın arkasında 0x78 yazıyor, kod çalışmıyor | 8 bitlik adres yazılmış | 2'ye böl: 0x78 → 0x3C |
| İki sensör birlikte çalışmıyor | Adres çakışması | Adres pinini değiştir, ikinci hat ya da TCA9548A kullan |
| Rastgele donmalar, motor çalışınca bozulma | Uzun kablo, gürültü ya da zayıf besleme | Kabloları kısalt, hızı 100 kHz'e düşür, modüllere 100 nF kondansatör ekle |
| ESP32 ya da Pico pini zarar gördü | 5 V'a bağlı pull-up 3,3 V pine bağlanmış | Modülü 3,3 V ile besle ya da seviye dönüştürücü kullan |
I2C, iki kabloyla projene ekran, saat, sensör ve bellek eklemenin en pratik yoludur; adresleri, pull-up dirençlerini ve tarayıcı kodunu öğrendiğinde karşılaşacağın sorunların çoğunu birkaç dakikada çözersin. BlueGrays uygulamasında I2C LCD ekran, OLED ekranlı Pong oyunu, DS1307 saatli dijital saat ve ESP32 hava durumu ekranı gibi I2C kullanan projeleri adım adım devre şemaları ve kodlarıyla bulabilirsin.
Sıkça sorulan sorular
I2C ile SPI arasındaki fark nedir?
I2C iki kabloyla adresleme yaparak yüzden fazla cihazı aynı hatta bağlar ama tipik olarak 100–400 kHz ile sınırlıdır. SPI ise üç ortak kablo ve her cihaz için ayrı bir seçim (CS) pini ister; buna karşılık 10 MHz ve üzeri hızlara çıkar. Sensörler ve küçük ekranlar için I2C, SD kart ve renkli TFT ekranlar için SPI tercih edilir.
I2C hattına en fazla kaç cihaz bağlanabilir?
7 bitlik adreslemede kullanılabilir 112 adres vardır. Pratikte sınırı adres sayısından çok hattın kapasitansı (en fazla 400 pF) ve paralel bağlanan pull-up dirençleri belirler; breadboard üzerinde 5–10 cihaz sorunsuz çalışır. Daha fazlası için TCA9548A çoklayıcı ya da ikinci bir I2C hattı kullanılır.
I2C pull-up direnci kaç ohm olmalı?
100 kHz ve kısa kablolar için 4,7 kΩ, 400 kHz ya da birçok cihazın bulunduğu hatlar için 2,2 kΩ en yaygın değerlerdir. 5 V hatta 1,5 kΩ'un, 3,3 V hatta 1 kΩ'un altına inmemelisin. Modüllerin üzerindeki dirençlerin paralel bağlandığını da hesaba kat.
Arduino Uno'da I2C pinleri hangileri?
Arduino Uno ve Nano'da SDA A4, SCL ise A5 pinidir. Uno R3'te AREF pininin yanında SDA ve SCL yazan iki pin daha vardır ama bunlar kart üzerinde A4 ve A5'e bağlıdır, ayrı bir hat değildir. Mega'da I2C pinleri 20 (SDA) ve 21 (SCL)'dir.
I2C kablo uzunluğu en fazla ne kadar olabilir?
I2C kart üzerindeki kısa mesafeler için tasarlanmıştır; 100 kHz'te ve uygun pull-up dirençleriyle 1 metreye kadar genellikle çalışır. Daha uzun mesafelerde hızı düşürmek, bükülü çift kablo kullanmak ya da P82B715 gibi hat sürücülerine geçmek gerekir. Metrelerce uzaklık için RS-485 ya da kablosuz bağlantı daha doğru seçimdir.
I2C tarayıcı cihazımı bulamıyorsa ne yapmalıyım?
Önce SDA ve SCL'nin doğru pinlere takıldığını, ortak GND'nin bağlı olduğunu ve modülün beslendiğini kontrol et. Sonra boştaki SDA ve SCL'de besleme gerilimini ölçerek pull-up dirençlerini doğrula. Hâlâ bulunmuyorsa modülü tek başına, kısa kablolarla ve 100 kHz'te dene; ESP32'de Wire.begin'e doğru pinleri verdiğinden emin ol.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
I2C İle LCD Ekran Kullanımı
I2C modülü sayesinde sadece 2 kablo (SDA, SCL) ile LCD ekranı kontrol ederek mesaj yazdıran proje. I2C protokolü ile pin tasarrufu sağlamayı öğretir.

ESP32 I2C LCD Ekran (16x2)
Bu projede 16x2 karakter LCD ekranı I2C protokolü üzerinden ESP32'ye bağlayarak metin görüntülüyoruz. I2C sayesinde sadece 2 data pini (SDA ve SCL) ile ekranı kontrol edebiliyoruz; klasik paralel bağlantıdaki 6+ pin israfı ortadan kalkıyor. Kod ilk satıra sabit bir mesaj, ikinci satıra ise her saniye artan bir sayaç yazdırıyor. Ayrıca başlangıçta I2C tarayıcı çalıştırarak ekranın adresini Serial Monitor'a yazdırıyoruz (genelde 0x27 veya 0x3F).

ESP32 RTC DS1307 ile Dijital Saat (I2C + LCD)
Bu projede DS1307 gerçek zaman saati (RTC) modülü ile 16x2 I2C LCD ekrana saat ve tarih bilgisi yansıtıyoruz. DS1307 pil destekli bir RTC'dir; ESP32 kapansa bile zamanı korur. Her iki modül de aynı I2C hattını (SDA/SCL) paylaşır, böylece sadece iki sinyal kablosu ile çoklu cihaz kontrolü öğrenmiş oluruz. Bu proje sayesinde I2C haberleşme protokolünü, RTC modüllerinin çalışma prensibini ve LCD ekranda dinamik veri gösterimini pratik bir şekilde öğreneceksiniz.

Arduino I2C Hesap Makinesi
4x4 membran tuş takımı ve 16x2 I2C LCD ekran kullanarak toplama, çıkarma, çarpma ve bölme işlemlerini gerçekleştiren Arduino tabanlı bir hesap makinesi projesidir. I2C sayesinde sadece 2 kablo ile ekran bağlantısı sağlanır, böylece kablo karmaşası azalır ve daha fazla pin kullanıma açık kalır. Ondalıklı sayı girişi ve negatif sayı desteği de bulunmaktadır.

Pong Oyunu - SSD1306
Arduino ve SSD1306 OLED ekran kullanılarak hazırlanmış; topun hareketlerini anlık olarak takip edip yörüngesine göre tepki veren otonom yapay zeka (CPU) rakibiyle donatılmış ve ses efektleriyle zengin

ESP32 HTTPClient + Hava Durumu API (SSD1306 OLED Ekranlı)
Bu projede ESP32 ile internet üzerinden hava durumu API'sine (wttr.in) `HTTPClient.h` kullanarak REST API çağrısı yapıyoruz. Bir önceki I2C LCD versiyonundan farklı olarak burada SSD1306 OLED (128×64) ekran kullanıyoruz — büyük font, vector ikonlar ve tek ekranda zengin görsel sunum mümkün oluyor. Hava durumu için 7 farklı vector ikon (güneşli, parçalı bulutlu, bulutlu, yağmurlu, karlı, fırtınalı, sisli) runtime'da çiziliyor (bitmap dosyası gerektirmez). Sıcaklık 3x büyük fontla ortada, hava dur

Dot Matrix Saat ve Takvim (MAX7219, DS1307)
DS1307 RTC modülü ile gerçek zamanlı saat ve takvim bilgisini MAX7219 8x32 dot matrix LED ekranda gösteren bir projedir. Saat gösteriminde iki nokta her saniye yanıp sönerek zamanın aktığını yansıtır.

ESP32 Sıcaklık Loglayıcı (DHT22 + DS1307 RTC + microSD + OLED)
ESP32 ile zamanlı sıcaklık ve nem kayıt sistemi kur! Bu projede DHT22 sensörü ile her 10 saniyede sıcaklık/nem okuyup DS1307 RTC modülünden aldığın gerçek zaman etiketiyle microSD karta CSV formatında kaydediyoruz. OLED ekranda büyük font ile son sıcaklık değeri, nem yüzdesi, timestamp ve toplam kayıt sayısı canlı gösterilir. SD kart üzerindeki `/temp_log.csv` dosyası Excel/Google Sheets/Python pandas ile açılıp analiz edilebilir — sera monitörü, ev/oda sıcaklık takibi, laboratuvar veri toplama,
Diğer yazılar
İki kabloyla onlarca sensör ve ekranı aynı hatta bağlamanı sağlayan I2C protokolünü; adresleri, pull-up dirençlerini, I2C tarayıcı kodunu ve en sık hataların çözümünü örneklerle öğren.

