I2C (Inter-Integrated Circuit), 1982 yılında Philips tarafından geliştirilen, senkron, paket anahtarlamalı seri iletişim metodudur. Kısa mesafeli çevre birimleri ile mikrodenetleyici arasında iletişim için kullanılır. Barometre, OLED ekran, titreşim sensörü, gyro sensör gibi birçok çevre birimi ile iletişim için I2C protokolü kullanılır. I2C ile 7 bit adresleme kullanıldığında 112 adet, 10 bit adresleme kullanıldığında 1008 adet aygıt ile tek veriyolu üzerinde iletişim kurulabilir.
I2C iletişim için iki veriyolu kullanılır:
- SDA (Serial Data): Aygıtların veri gönderdiği ve aldığı veriyoludur.
- SCL (Serial Clock): Saat sinyalini taşıyan veriyoludur.
I2C iletişimde iki tür aygıt vardır:
- Master (Efendi): İletişimi kontrol eden aygıttır.
- Slave (Köle): Master kontrolü ile iletişim gerçekleştiren aygıttır.
I2C protokolü half duplex iletişim sağlar, yani bir aygıt iletişimdeyken diğerleri hattın boşalmasını beklemek zorundadır.
I2C veriyolundaki dirençlere pull-up direnç denir. I2C veriyolu boşta iken lojik 1 konumundadır. Pull-up dirençler veriyolunu lojik 1 konumunda tutmaya yarar. Bu dirençlerin değeri 2K ile 10K arasında seçilir. Dirençlerin değeri arttıkça iletişim hızı azalır.
I2C protkolünde iletilen veri bloğuna mesaj denir. Bir mesaj çerçevelerden oluşur. İlk çerçeve aygıt adresini, ikinci çerçeve yazmaç (register) adresini ifade eder. Üçüncü ve sonraki çerçeveler veriyi taşırlar.
Bir I2C mesajı genellikle 4 elemandan oluşur:
- Start bit: Alıcıya yeni bir frame gönderilmekte olduğunu bildiren, iletişim başlatma bitidir.
- Aygıt adresi: Master’ın hangi slave ile iletişim kurduğunu belirten adres bilgisidir. Mesaj tüm slave’lere iletildiğinde sadece bu adrese sahip slave mesajı işler.
- R/W (Read/Write): Master slave’e yazmak istiyorsa bu bit 0, slave’den okumak istiyorsa bu bit 1 olarak işaretlenir.
- ACK (Acknowledgement): Eğer frame alıcıya ulaştıysa, alıcı SDA hattını bu bit süresince lojik 0’a çeker. Master hattı lojik 0’da gördüğünde frame’in iletildiğini anlar ve sıradaki frame’e geçer. Hattın lojik 0’a çekilmesi, yani frame’in alındığının bildirilmesine ACK (Acknowledgement) denir. Eğer hattın meşgul olması gibi bir nedenle frame alıcıya ulaşmadıysa, alıcı bu bit süresince hattı lojik 1’de tutar. Bu duruma da NACK (Neagtive Acknowledgement) denir. Hattı dinleyen gönderici NACK okuyunca frame’i tekrar gönderir.
- Yazmaç adresi: Slave aygıtın bellek adres bilgilerini içerir. Master aygıt, slave’in bellek adreslerinin nasıl haritalandığını, hangi yazmaca hangi bilginin yazılacağını veya okunacağını bilir.
- Veri: Veriyi taşıyan bitlerdir.
- Stop bit(leri): İletişimin tamamlandığını belirten bittir. Saat frekansı lojik 1’deyken SDA hattı lojik 0’dan 1’e çekilerek iletişim sonlandırılır.
Örnek I2C İletişim
- I2C iletişim hattında iletişimi başlatmak için master, SCL hattı sürekli lojik 1 konumunda iken (saat kapalı iken) SDA hattını 0’a çeker. Hemen sonra SCL veriyolu üzerinde saat çalıştırılır. Bu, iletişimin başladığını gösteren start bitidir.
- SCL hattında iletişimin hızına uygun biçimde sürekli bir saat frekansı üretilir. Örneğin SCL frekansı 1Hz ise SCL hattı yarım saniye lojik 1, yarım saniye 0 konumundadır, yani her saniye bir pulse üretilmektedir. Bu pulse ile senkronize şekilde SDA hattından her saniye 1 bit veri gönderilebilir. Slave aygıt, aynı anda hem SCL hattındaki saat frekansını hem de SDA hattındaki veriyi dinleyerek gelen veriyi çözümler.
- Master, iletişim kurmak istediği slave adresini içeren çerçeveyi ve R/W bitini gönderir.
- Slave çerçeveyi sorunsuz aldıysa SDA’yı lojik 0’a çeker (ACK). SDA lojik 0 ise iletişim sorunsuz gerçekleşmiştir.
- Master sırasıyla yazmaç adresleri ve verileri içeren çerçeveleri göndererek iletime devam eder.
- İletişim tamamlandığında SCL hattı lojik 1 konumunda iken SDA hattı lojik 0’dan 1’e çekilir. Bu stop bitidir ve iletişimin tamamlandığını bildirir.
Arduino Uno’nun A4 ve A5 pinleri aynı zamanda I2C için sırasıyla SDA ve SCL pinleridir. Aşağıdaki örnekte Arduino Uno, ADXL345 titreşim sensörü ve OLED ekran ile I2C üzerinden iletişim kurmaktadır. Örnekte ADXL345’ten okunan veriler, aynı hat üzerindeki OLED ekrana yazılmaktadır. Arduino Uno master, ADXL345 ve OLED ekran slave aygıtlardır.
Malzemeler
- Arduino Uno
- ADXL345 titreşim sensörü
- OLED ekran
Bağlantı şeması
Kaynak kod
#include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_ADXL345_U.h> #include "U8glib.h" U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // Ekran nesnesini tanımla Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(); float hx, x, hy, y, hz, z; // Eksen bilgilerini tutan değişkenler void draw(void) { // Çizim fonksiyonu String Str; u8g.setFont(u8g_font_unifont); // Font seçimi u8g.setPrintPos(0, 24); // Ekran yerleşimi seçimi Str="www.hbmacit.com"; u8g.print(Str); u8g.setFont(u8g_font_profont12); // Font seçimi u8g.setPrintPos(0, 52); // Ekran yerleşimi seçimi Str = 'x:' + String(hx) + 'y:' + String(hy) + 'z:' + String(hz); u8g.print(Str); } void setup(void) { Serial.begin(9600); if(!accel.begin()) { Serial.println("Sensör bulunamadı."); while(1); } else { sensors_event_t event; accel.getEvent(&event); x = event.acceleration.x; y = event.acceleration.y; z = event.acceleration.z; } } void loop(void) { sensors_event_t event; accel.getEvent(&event); if(event.acceleration.x!= x) { hx = event.acceleration.x - x; x = event.acceleration.x; } if(event.acceleration.y!= y) { hy = event.acceleration.y - y; y = event.acceleration.y; } if(event.acceleration.z!= z) { hz = event.acceleration.z - z; z = event.acceleration.z; } u8g.firstPage(); do{ draw(); }while (u8g.nextPage()); delay(25); }
Bu kaynak kod çalıştığında ekranda aşağıdaki gibi bir görüntü elde edilir.