I2C protokolü

Kurallar:

*2 pin de pull-up yapılmalıdır. Hız arttıkça direncin değeri düşmelidir. Hızınıza x diyelim.

x<100kbps ise direnç: 4k7

x=100kbps ise direnç: 2k2

x<400kbps ise direnç: 1k

değerleri tavsiye edilir.

not: kbps = Kilo Bit per second (1 saniyede gönderilen kilobit sayısı)

*I2C protokolünde veri alışverişi Start komutuyla başlar ve Stop komutuyla biter.

*Start ve Stop durum komutları ise sadece SCL hattının high olduğu durumlarda gönderilir.

*Bu protokolde data gönderimi saat darbesinin, low seviyesinde değişir. High seviyesinde sabit kalır, bir sonraki low seviyesinde ise yeni data için yeni değişim yapılarak böyle devam eder, görsel:

 

Unsurlar:

1)Start:

Simge: S

Görevi: I2C iletişimini başlatır

Nasıl: SCL high iken SDA low’a çekilir

Start Condition

 

2)Stop:

Simge:

Görevi: iletişimi durdurur

NasılSCL high iken SDA serbest bırakılır, SDA pini pull-up yapıldığından dolayısıyla hat HIGH olarak kalmış olur.

Stop Condition

 

3)Restart:

Simge: R

Görevi: Veri alışverişini yeniden başlatır

Nasıl: Start ile başlar stop ile devam etmez,

Restart Condition

biraz daha açacak olursak:

Restart Condition-2

 

4)Data Transfer:

Simge: Data

Görevi: 8 bitlik veriyi hatta gönderir.

NasılSCL yüksek olduğunda veri okunur,

SCL hattı  low iken, SDA hattının seviyesinde değişir(gönderilecek bit’in seviyesesi 1 ise high’a çekilir, 0 ise low’a çekilir).
SCL hattı High iken, alıcı tarafından veri(bit) çekilir/okunur,

bu işlem 8 kere yapıldığında 1 byte’lık veri gönderilmiş olur

Data Transfer

Açıklamalı hali:

Data Transfer-2

Daha yakından bakacak olursak:

Data Transfer-3

5) ACK(Acknowledges):

Simge: A

Görevi: Veri(byte) aktarımını onaylar yani kabul eder, ben tamamım problem yok veriyi aldım gibisinden bir mesajdır.

Nasıl: 1 bytelik veri alımı tamamlandığında, SDA hattı alıcı tarafından LOW’a çekilir.

Acknowledges

6)NACK(Negatively):

Simge: N

Görevi: Veri aktarımını onaylamama mesajıdır, yani sen veri gönderdin ama ben bu veriyi anlamadım anlamına gelir.

Nasıl: 1 bytelik veri alımı tamamlandığında, SDA hattı alıcı tarafından LOW’a çekilmez ise anlaşılır ki gönderdiğimiz veriler alıcı tarafından alınmadı, çünkü alınsaydı SDA hattı low olacaktı ,

NACK Condition

 

 

Veri Gönderme(write):

*Master cihaz start komutu gönderir,

*Master cihaz 8 bitlik data gönderir ki bu datanın ilk 7 biti alıcı cihazın i2c adresidir ve son bit ise okuma/yazma bitidir, eğer son bit 1 ise okuma, 0 ise yazma yapacağı anlamına gelir.Biz yazma işlemi yapacağımızdan bu bit low(0) olacak.

*Master’ın gönderdiği adres verisi bütün slave cihazlara gider ama sadece bu adrese sahip olan cihaz ACK gönderir, (eğer bu adrese sahip bir cihaz yoksa ACK gitmeyeceği için iletişim devam etmez.)

*ACK gören master hemen 8 bitlik data’yı gönderir -ki bu data, slave cihazın bir register adresi olmalıdır. Çünkü göndereceğimiz daha doğrusu yazmak istediğimiz bir veriyi ancak bir register adresine yazabiliriz.

*8 bitlik datayı(register adresini) alan slave cihaz aldığını belli etmek için ACK komutu gönderir

*Gönderdiği register’in alındığını gören master, register’a yazmak istediği veriyi gönderir.

*8 bitlik datayı(register’a yazılacak veriyi) alan slave cihaz aldığını belli etmek için ACK komutu gönderir

*Master,  stop komutu gönderir ve yazma işlemini bitirmiş olur.

görsel:

write example

Başka bir görsel:

i2c-tutorial-master-slave

 

 

Veri okuma(read):

*Master cihaz start komutu gönderir,

*Master cihaz 7 bitlik adres bilgisi ile 1 bitlik okuma okuma bitini yani HIGH seviyeyi gönderir.

*Bu adrese sahip olan slave cihaz ACK ve 8 bitlik veriyi gönderir.

*Master bu veriyi başarıyla aldığını belirtmek için ACK gönderir. Alamadıysa NACK gönderir.

*Master stop komutu göndererek iletişimi bitirir.

Görsel:

read example

Başka bir görsel:

i2c-tutorial-slave-master

 

 

Daha gerçekçi olalım:

i2c

Bu görsel daha güzel anlatmış:

 

pic18I2C_06

Başka bir varyasyon:

pic18I2C_07

Not:

Slave cihazın adresini nerden biliyoruz? Tabiki datasheet bilgilerinden öğreniyoruz. Mesela 24lc02b adlı i2c ile haberleşen bir eepromun datasheet’inde şöyle yazıyor:

address

 

 

Terimler:

*SCL (Serial CLock),

*SDA (Serial DAta),

*yazma koruma(WP-Write Protect) ,

*çıkış izin(OE-Output Enable),

*ACK(alındı[acknowledge=kabul etmek]),

*Most significant bit (en önemli bit),

*Least (en az önemli bit/en önemsiz bit)

 

Yazılımsal örnekler:

void i2c_start(void)
{
SDA = 1;             // i2c start bit sequence
i2c_dly();
SCL = 1;
i2c_dly();
SDA = 0;
i2c_dly();
SCL = 0;
i2c_dly();
}

void i2c_stop(void)
{
SDA = 0;             // i2c stop bit sequence
i2c_dly();
SCL = 1;
i2c_dly();
SDA = 1;
i2c_dly();
}

unsigned char i2c_rx(char ack)
{
char x, d=0;
SDA = 1;
for(x=0; x<8; x++) {
d <<= 1;
do {
SCL = 1;
}
while(SCL_IN==0);    // wait for any SCL clock stretching
i2c_dly();
if(SDA_IN) d |= 1;
SCL = 0;
}
if(ack) SDA = 0;
else SDA = 1;
SCL = 1;
i2c_dly();             // send (N)ACK bit
SCL = 0;
SDA = 1;
return d;
}

bit i2c_tx(unsigned char d)
{
char x;
static bit b;
for(x=8; x; x–) {
if(d&0x80) SDA = 1;
else SDA = 0;
SCL = 1;
d <<= 1;
SCL = 0;
}
SDA = 1;
SCL = 1;
i2c_dly();
b = SDA_IN;          // possible ACK bit
SCL = 0;
return b;
}

 

The 4 primitive functions above can easily be put together to form complete I2C transactions. Here’s and example to start an SRF08 ranging in cm:

i2c_start();              // send start sequence
i2c_tx(0xE0);             // SRF08 I2C address with R/W bit clear

i2c_tx(0x00);             // SRF08 command register address
i2c_tx(0x51);             // command to start ranging in cm
i2c_stop();               // send stop sequence

Now after waiting 65mS for the ranging to complete (I’ve left that to you) the following example shows how to read the light sensor value from register 1 and the range result from registers 2 & 3.

i2c_start();              // send start sequence
i2c_tx(0xE0);             // SRF08 I2C address with R/W bit clear

i2c_tx(0x01);             // SRF08 light sensor register address
i2c_start();              // send a restart sequence
i2c_tx(0xE1);             // SRF08 I2C address with R/W bit set

lightsensor = i2c_rx(1);  // get light sensor and send acknowledge. Internal register address will increment automatically.
rangehigh = i2c_rx(1);    // get the high byte of the range and send acknowledge.
rangelow = i2c_rx(0);     // get low byte of the range – note we don’t acknowledge the last byte.
i2c_stop();               // send stop sequence

 

3 thoughts on “I2C protokolü

  1. Hocam “Most significant bit” ve “Least significant bit” çevirilerinde hata olmuş. Most significant bit(MSB) = en yüksek değerlikli bit, least significant bit(LSB) = en düşük değerlikli bit olacak sanırım.

  2. Read modunda okumak istedigimiz registerin adresini gönderemiyormuyuz?Burada slave direk kendi kafasına göre registerin içindeki değeri döndürmüş?

Bir Cevap Yazın