Arduino - I2C Haberleşme - Elektrik Elektronik Projeleri

Post Top Ad

4 Mayıs 2015 Pazartesi

Arduino - I2C Haberleşme

Bu yazımızda aygıtlar arası I2C protokolü ile haberleşmeyi inceleyeceğiz. Ben örnek olarak iki arduinonun haberleşmesini gerçekleştirdim.
Devre:
Arduino Uno için SDA pini A4 nolu pindir, SCL pini ise A5 nolu pindir. Arduino Mega’da ise SDA ve SCL pinleri, 20 ve 21 nolu pinlerdir.

Arduino Uno ve Arduino Mega arasında yapılacak haberleşme için bağlantı şeması:
I2C Haberleşmesi:
I2C haberleşme protokolü Philips tarafından geliştirilmiştir. Inter Integrated Circuit kelimelerinin baş harflerinden oluşmaktadır. Düşük bant genişliğine sahip, kısa mesafeli bir senkron haberleşme protokolüdür.

I2C protokolünde haberleşme için iki hat kullanılır. Bunlar SCL ve SDA hatlarıdır. SCL (Serial Clock) veri senkronizasyonunu sağlayan, clock sinyallerinin iletildiği hattır. SDA (Serial Data) ise verilerin iletildiği hattır. SCL ve SDA hatlarına birer pull-up direnci bağlanmalıdır.
I2C protokolünde, aygıtlar master – slave ilişkisi içerisinde haberleşirler. Yani aygıtlar ya master ya da slave olarak ayarlanmalıdırlar. Genellikle aygıtlardan biri master diğerleri slave olarak ayarlanır. Ayrıca I2C protokolünün multimaster özelliği de mevcuttur. Bu durumda hatta birden fazla master olabilir.

Haberleşme master olarak seçilen aygıtın kontrolündedir. Haberleşmeyi başlatan ve bitiren master’dır. Master SCL hattına clock sinyalleri göndererek haberleşmeyi kontrol eder. Slave olarak seçilen ayıtlar clock sinyali üretmezler, yalnızca veri alışverişinde bulunurlar. Her slave 7 veya 10 bitlik bir adrese sahiptir. Master, slave’lere bu adresleri ile ulaşır. Master’ın bir adresi yoktur.

Master – slave arasındaki veri alışverişi SDA hattı üzerinden gerçekleşir. Bu hatta veri iletimi çift yönlüdür. Yani aygıtlara gelen ve giden veri tek hat üzerindedir. I2C iletişimin veri yolu 8 bittir. Yani veriler 1 byte’lık bölümler halinde iletilir.
Clock sinyali lojik-1 iken, data sinyali lojik-1’den lojik-0’a geçmesi ile start komutu verilir. Aynı şekilde clock sinyali lojik-1 iken, data sinyalinin lojik-0’dan lojik-1’e geçmesi ile de stop komutu oluşturulur. Veri iletimi start komutuyla başlar stop komutuyla biter. Start – stop komutlarını master aygıt oluşturur. Master aygıttan slave aygıta veri gönderme işleminde; ilk önce start biti, ardından adres bitleri, ardından yazma/okama biti, daha sonra veri bitleri, en son olarak da stop biti gönderilir. Her veri gönderiminde, 8 bit gönderildikten sonra, slave aygıttan verileri aldığına dair onay biti olan ACK (acknowledge) master’a gönderilir. Bazı durumlarda (veri iletiminde hata oluşması durumunda) slave master’a ACK bitinin değili olan NACK bitini gönderir. Bu durumda master aygıt stop biti göndererek haberleşmeyi durdurur, veya tekrar start biti göndererek yeniden haberleşmeye başlar.

I2C haberleşmede her 9. bit ACK veya NACK bitidir. Veri gönderiminde 8 bitlik bölümden sonra bu onay veya onay değil biti gönderilir. I2C haberleşmede gönderilen R/W biti ise okuma/yazma bitidir. Bu bit 0 ise yazma işleminin yapılacağını, 1 ise okuma ise okuma işleminin yapılacağını bildirir.
Slave aygıt 7 bitlik veya 10 bitlik adrese sahip olabilir. Slave 7 bit adrese sahip ise start bitinden sonra bu 7 bit adres eklenir, ardından 8. bit olarak R/W (yazma/okuma) biti eklenir. 9. bit ise ACK bitidir. Eğer slave 10 bit adrese sahip ise, adres iki bölüm halinde gönderilir. İlk bölümde adres bilgisinin ilk iki biti yer alır. Bu bölüm 11110XX(R/W) bitlerinden oluşur. Buradaki 11110 kısım sabittir. XX kısmi ise adres bilgisinin ilk iki bitidir. 8. bit olarak ise R/W (okuma/yazma) biti yer alır. Bu bölümün ardından 9. bit olarak ACK bilgisi gönderilir. İkinci bölüm ise adres bilgisinin kalan 8 bitidir. Bu bölümün ardından yine ACK bilgisi gönderilir. Ardından data bitlerinin iletilmesine geçilir. Data bitlerinin gönderilmesinde de gönderilen her 8 bitlik bölümden sonra ACK bilgisi iletilir.
Wire.h Kütüphanesi
Arduino ile I2c haberleşmesinde Wire.h kütüphanesini kullanmaktayız.bu kütüphanenin bazı fonksiyonlarına kısaca değinecek olursak:

Wire.begin()

Haberleşmeyi başlattığımız fonksiyondur. Haberleşmeyi master olarak başlatmak istiyorsak, parametre girmeyiz. Eğer haberleşmeyi slave olarak başlatmak istiyorsak parametre olarak adres bilgisi gireriz.

Wire.beginTransmission(adres)

Master aygıttan adresini parametre olarak girdiğimiz slave aygıta veri gönderimini başlatmak için bu ifadeyi kullanırız.

Wire.endTransmission()

Master aygıtın veri gönderimini bitirmek için kullanılan fonksiyondur.

Wire.onReceive(işlem)

Master’dan slave’e veri geldiğinde yapılacak olan işlemleri belirttiğimiz ifadedir. Parametre olarak bir fonksiyon alır. Biz  salave’e veri geldiğinde ne yapmak istiyorsak bu fonksiyonda tanımlarız. Bu oluşturduğumuz fonksiyon da parametre olarak integer bir parametre ile tanımlanmalıdır.

Wire.available()

Biz verilerin gelmeye başladığını bu fonksiyon ile anlarız. Bu fonksiyon okunmamış (okunmayı bekleyen) veri sayısını dönderir.

Wire.read()

Gelen veriyi okumak için kullanılan fonksiyondur.

Wire.write()

Parametre olarak girilen ifadeyi ileten ifadedir.

Wire.requestFrom()

Slave’lerden veri istediğimiz ifadedir. Parametre olarak üç değer alır. İlk parametre veri isteyeceğimiz slave’in adresidir. İkinci parametrede kaç byte’lık veri istediğimizi bildiririz. Son parametresi ise boolean bir değişkendir.

Wire.onRequest()

Veri istendiğinde slave’in ne yapacağını belirttiğimiz ifadedir. Parametre olarak bir fonksiyon alır. Bu fonksiyonda neler yapılması gerektiğini tanımlarız.

Master’dan Slave’e Veri Gönderme:

Wire.beginTransmission(4);
Wire.write(x);
Wire.endTransmission();

Slave’e gelen veriyi okuma:

Wire.onReceive(receiveEvent);
void receiveEvent(int howMany)

  int x = Wire.read();
}

Master’ın slave’den veri istemesi:

Wire.requestFrom(2, 6);

Slave’den master’a veri gönderme:

Wire.onRequest(requestEvent);
void requestEvent()
{
  Wire.write(x);  
}

Master’ın gelen veriyi okuması:

while(Wire.available())
{
  int x = Wire.read();
}  

Kodlar:
  • Master olarak seçilen arduino’nun kodları:
#include <Wire.h>

char c;

void setup()
{
  Wire.begin();  // haberleşme master olarak başlatıldı
  Serial.begin(9600);
}

void loop()
{
  Wire.requestFrom(1, 16);  //Slave 1'den 16 byte'lık veri isteniyor
  while(Wire.available()){
    c = Wire.read();
    Serial.print(c);
  }
  Serial.println();
 
  Wire.beginTransmission(1);      // Slave 1' veri gönderiliyor
  Wire.write("Master: Merhaba");  // string veri gönderiliyor
  Wire.endTransmission();
 
  delay(500);
}

  • Slave olarak seçilen arduinonun kodları:
#include <Wire.h>

char c;

void setup()
{
  Wire.begin(1);  // haberleşme slave 1 olarak başlatıldı
  Wire.onRequest(requestEvent);  // veri istendiğinde
  Wire.onReceive(receiveEvent);  // veri geldiğinde
  Serial.begin(9600);
}

void loop()
{
  delay(100);
}

void receiveEvent(int howMany)
{
  while(Wire.available()){
    c = Wire.read();
    Serial.print(c);
  }
  Serial.println();
}

void requestEvent()
{
  Wire.write("Slave 1: Merhaba");
}

8 yorum:

  1. void receiveEvent()
    void requestEvent()

    why you have not mentioned these two functions in loop?

    YanıtlaSil
  2. sanırım sız 1 adet master ve 1 adet slawe olarak kodları verdınız. 1 master 2 slawe oldugu zaman master 1 ıncı yada 2 ncı slawe nası yoneticek? slawelere farklı bı ısımlendırme/tanımlama yapmamız gerekirmi?

    YanıtlaSil
    Yanıtlar
    1. uygulamada 1 adet slave olduğundan yalnızca ona isim verilmiştir. slave 1 olarak isimlendirilmiştir. birden fazla slave cihaz olduğunda her birine farklı isim vermek gerekecektir.

      Sil
  3. aynı adrese sahip birden fazla slave okuma hakkında bilginiz varmı?

    YanıtlaSil
    Yanıtlar
    1. aynı isme sahip birden fazla slave oluşturulabiliyor mu bilmiyorum. aynı isme sahip her iki slave de hatta aynı anda veri gönderdiğinde verilerde bozulma meydana gelebilir. o yüzden bu protokolde her bir slave ile tek tek iletişim kurulmaktadır.

      Sil
  4. büyük data transferi yapılmak istendiğinde napılmı?

    YanıtlaSil
    Yanıtlar
    1. datalar bir buffer'da tutulup sonra iletilmelidir. yada ring buffer metodu kullanılabilir.

      Sil
  5. slave yalnızca char olarak mı okuyabilir? double gönderip double alamıyor muyuz? ya da char değil string diye okuyamıyor muyuz?

    YanıtlaSil

Post Top Ad