I²C (Inter-Integrated Circuit) Haberleşmesi


I²C seri iletişimi, mikrodenetleyicinin diğer entegre elemanlarıyla kolay iletişim kurmasını sağlayan entegreler arası bir haberleşme protololüdür. Kullanacağımız PIC18F4585  içerisinde hem I²C hem de SPI (Serial Peripheral Interface) birimini içinde barındıran MSSP (Master Synchronous Serial Port) modülü bulunmaktadır.
I²C protokolünde haberleşmek için iki uç kullanılır. Bunlar SDA (Seri veri giriş-çıkış) ve SCL (Seri saat sinyali – clock)’dir. SDA uçlarından bilgi aktarımı işlemleri SCL ucundaki  saat sinyali sayesinde senkronize olarak gerçekleştirilmektedir. Datasheet’e bakacak olursak PIC18F4585′de SDA ve SCL  için kullanılan uçların 18. ve 23. pinler olduğunu görebiliriz.
Bu protokolde entegreler master(ana-usta) ya da slave(uydu-köleolabilir. Entegre master iken; saat sinyalini kendisi yönetir, iletişimin kontrolü master olan entegrededir. Slave konumunda olan entegre saat sinyali üretmez, sadece veri alışveriş işlemi yapar.
Bu bölümdeki amacımız elimizdeki 2 adet PIC18F4585 entegresinden birini master, birini slave olacak şekilde programlayarak master’dan slave‘e veri gönderip, yine master   aracılığıyla slave‘den veri okumak olacak. İki entegreyi de bu senaryo için programlamamız gerekiyor.
I²C iletişiminde her bir slave cihazının kendine özgü bir adresi vardır. Böylece master olan cihaz hangi slave cihazıyla işlem yapacağını belirtebilir (Bir master birden çok slave cihazıyla veya birden çok master kendi arasında I²C kullanarak haberleşebilir). Bu adres  7 bitlik veya 10 bitlik olabilir. Biz bu bölümde 7 bitlik adresleme kullanacağız. Veri iletişim hattı I²C protokolünde 8 bittir. Yani tek seferde 8 bitlik (1 byte) veri gönderip okuyabiliriz.
Genel olarak iletişim aşağıdaki şekilde sağlanır;
  • Başlama şartı (Start Condition)
  • Adres + Okuma/yazma bilgisi
  • Veri bitleri
  • Durma şartı (Stop Condition)
Not:  Start ve Stop şartları master cihaz tarafından oluşturulur. Master cihazın adres bilgisi olmaz. Veri bitlerinden önce mutlaka adres bilgisi gönderilmelidir ki o adrese sahip slave    cihaz seçilsin. Yoksa veri aktarımı -tek birslave cihazla haberleşme yapılsa bile- gerçekleşmez. Okuma/yazma bilgisi denen şey iste master cihazın slavecihaza veri gönderme veya cihazdan veri alma durumunun belirlenmesinde kullanılır.
Master veri gönderirken akış genel hatlarıyla şu şekilde işler.
Master tarafında:
  • Master cihazı tarafından I²C modülü açılır. İletişim hız (baud) ayarları  yapıldıktan sonra start şartı oluşturulur (Bu karşı tarafa gönderilen ilk start bitidir, bütün slave cihazlarına gider).
  • Hemen ardından master cihaz 7 bitlik slave adresi bilgisini okuma/yazma bitiyle beraber gönderir (Okuma/yazma biti adres olarak gönderdiğimiz değişkenin son bitidir. Normalde tanımladığımız char, int gibi tiplerdeki değişkenler 8 bitlik değişkenlerdir. Biz bu değişkenlere adres bilgisini yazdığımız da son-en yüksek anlamlı- bit önemsiz kalır. Biz bu biti okuma/yazma bilgisini taşıyacak şekilde 1 veya 0 ile doldurur karşı tarafa öyle göndeririz).
  • Master cihaz adres + R/W(okuma/yazma) bilgisini gönderdikten sonra slave cihazdan bir acknowledge sinyali bekler. (Ack)
  • Slave cihazdan Ack geldiğinde master cihaz 8 bitlik veriyi  I²C üzerinden gönderir. Slave cihaz, alınan her 8 bitlik veri için bir Ack gönderir.
  • Master göndereceği tüm verileri gönderdikten sonra bir Not-Acknowledge (N-Acksinyali gönderir ve artık veri aktarımı yapmayacağını belirtmiş olur. Bunun üzerinde slave’den herhangi bir bilgi gelmez.
  • Master tarafından stop şartı oluşturulur ve  I²C iletişimi sonlanır.
  • Master cihaz iletişimi tamamladığında  I²C modülünü kullanıma kapatır.
Slave tarafında:
  • I²C modülü kullanıma açılır ve slave adres bilgisi ilgili register’a yazılır.  I²C iletişim protokolüne göre verilen adres değiştirilmediği sürece slave adresi o olacaktır.
  • Slave cihazın kodları master tarafından gelecek veriyi yakalayacak şekilde kodlanmış olmalıdır. İster “while(1)içerisinde devamlı olarak bilgi beklersiniz -gereksiz- ister veri geldiğinde oluşturulan interrupt’ı yakalar ona göre davranırsınız. Her iki biçimde de master tarafından start bitiadres bilgisi(eğer adresler uyuşuyorsa) ve R/W bitialınır. R/W bitinin alınmasındna sonra bir Ack otomatik olarak gönderilir (Bizim ek bir Ack gönderme kodu eklememize gerek kalmayacak, veri alındığında donanım bu kodu otomatik olarak yolluyor zaten. Ama eğer donanım bunu desteklemiyor olsaydı bizim R/W biti alındıktan sonra Ack sinyali oluşturmamız gerekecekti).
  • Adres ve R/W bilgisi alındıktan sonra gelen bilgi veriyi içerir. Buna göre slave tarafında ikinci gelen veri ilgili değişkenlere alınmalıdır (veya gelen verinin adres mi yoksa veri mi içerdiğini belirten flag‘lere bakılabilir). Yine alınan her veri için Ack sinyali otomatik olarak üretilir.
  • Master tarafından N-Ack sinyali geldiğinde slave artık Ack göndermez.  I²C modülü kullanıma kapatılır.
Master cihazının kodları aşağıdaki şekilde olacak;
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>
#include <i2c.h>
#include <spi.h>
#pragma config OSC = HS, WDT = OFF, LVP = OFF
void show_data_on_leds(char);
void main(void) {
    char data_tx = 1,data_rx = 0,addr = 10;
    ADCON1 = 0x0F;
    CloseSPI();
    CloseI2C();
    TRISB = 0x07;
    PORTB = 0;
    TRISC = 0;
    PORTC = 0;
    OpenI2C(MASTER, SLEW_OFF);
    SSPADD=0x0A;
    //SSPADD = 49;
    while(1) {
        PORTBbits.RB3 = 1;
//******************************DATA OKU********************************//
        if(!PORTBbits.RB2) {
            while(!PORTBbits.RB2);
            Delay10KTCYx(20);
            PORTBbits.RB5 = 1;
            StartI2C();
            while ( SSPCON2bits.SEN );      // wait until start condition is over
            WriteI2C(addr | 0x01);          // write 1 byte - R/W bit should be 1
            IdleI2C();
            //while (SSPCON2bits.ACKEN);
            data_rx = ReadI2C();            // read data byte
            NotAckI2C();
            while (SSPCON2bits.ACKEN);
            StopI2C();                      // send STOP condition
            while ( SSPCON2bits.PEN );      // wait until stop condition is over
            show_data_on_leds(data_rx);
        }
//*****************************DATA GONDER******************************//

        if(!PORTBbits.RB0) {
            while(!PORTBbits.RB0);
            Delay10KTCYx(20);
            data_tx = 1;
            IdleI2C();                          // ensure module is idle
            StartI2C();                         // initiate START condition
            while(SSPCON2bits.SEN);
            // wait until start condition is over
            WriteI2C(addr & 0xFE);              // write 1 byte - R/W bit should be 0
            IdleI2C();                          // ensure module is idle
            WriteI2C(data_tx);                  // Write data byte to EEPROM
            IdleI2C();                          // ensure module is idle
            StopI2C();                          // send STOP condition
            while(SSPCON2bits.PEN);             // wait until stop condition is over
        }
        if(!PORTBbits.RB1) {
            while(!PORTBbits.RB1);
            Delay10KTCYx(20);
            data_tx++;
            IdleI2C();                          // ensure module is idle
            StartI2C();                         // initiate START condition
            while(SSPCON2bits.SEN);
            // wait until start condition is over
            WriteI2C(addr & 0xFE);              // write 1 byte - R/W bit should be 0
            IdleI2C();                          // ensure module is idle
            WriteI2C(data_tx);                  // Write data byte
            IdleI2C();                          // ensure module is idle
            StopI2C();                          // send STOP condition
            while(SSPCON2bits.PEN);             // wait until stop condition is over
        }
    }
}

//****************************DATA GOSTER********************************//

void show_data_on_leds(char data) {
    if(data == 1) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 0;
        PORTBbits.RB5 = 0;
    }
    if(data == 2) {
        PORTBbits.RB3 = 0;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 0;
    }
    if(data == 3) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 0;
    }
    if(data == 4) {
        PORTBbits.RB3 = 0;
        PORTBbits.RB4 = 0;
        PORTBbits.RB5 = 1;
    }
    if(data == 5) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 0;
        PORTBbits.RB5 = 1;
    }
    if(data == 6) {
        PORTBbits.RB3 = 0;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 1;
    }
    if(data == 7) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 1;
    }
    Delay10KTCYx(500);
    PORTBbits.RB5 = 0;
    PORTBbits.RB4 = 0;
    PORTBbits.RB3 = 0;
}

Satır 16’da alınan sayıları ledlerde göstermek için yazılan fonksiyonun prototipi bulunuyor.
Satır 19’da gönderilen veriler için data_tx alınan veriler içinse data_rx değişkeni tanımlanıyor. Ayrıca slave tarafında belirlediğimiz adres bilgisinide burda addr değişkeninde tutuyoruz. (Bu adres bilgisi iki taraf içinde haberleşme boyunca değişmeyecek. Yoksa bağlantı kurulamaz.)
Satır 21’de tüm ADC giriş/çıkışlarını dijital olacak şekilde ayarlıyoruz. Satır 22 ve 23’te SPI ve I2C modüllerini kapatıyoruz Daha sonra I2C modülünü tekrar kullanıma açacağız.
Satır 25,26,27,28’de portların giriş/çıkış ayarları yapılıyor. C portundan veri göndereceğimiz için çıkış olarak ayarlıyoruz (C portu daha sonra biz I2C modülünü açtığımızda I2C protokolünün gerektirdiği şekilde ayarlanacak SDA SCL pinlerinin giriş çıkış durumuna göre. Biz default olarak TRISC = 0 dedik)
Satır 30’da I2C  modülü master olarak işlem yapacak şekilde ayarlanıyor. Satır 31’de SSPADD register’ına adres bilgisi yazılıyor (Normalde bunu yazmamız gerkemiyor, çünkü şu anda master tarafındayız. Adres bilgisi slave tarafında yazılır ki master cihaz, slave cihazı bulabilsin. Bu satırı yazmak şart değil.)
Satır 36 ve 38’de RB2 pinine bağlı butona basılıp basılmadığı kontrol ediliyor. Eğer butona basılıp çekilirse ona göre işlem yapılacak.
Satır 40’da RB2 pinine bağlı butona basıldığını anlamak amacıyla RB5 pinine bağlı ledi yakıyoruz. Bu tamamen görsel olarak programın çalışabilirliğini denetlemek için. I2C haberleşmesiyle bir alakası yok.
Satır 42’de I2C haberleşmesi başlatılıyor.  Satır 43’de start koşulunun sağlanıp sağlanmadığı denetleniyor. (Bu satır olmasa da I2C haberleşmesi sağlanabilir fakat start koşulu sağlanmazsa programa devam etmenin bir mantığı yoktur. Bu şartın sağlanıp sağlanmadığını kontrol edip öyle devam etmek gerekiyor.)
Satır 45’de slave cihazın adres bilgisiyle birlikte bu cihaza okuma mı yoksa yazma mı yapılacağı bilgisi gönderiliyor. İlk 7 bit adres biti, son bit ise okuma/yazma biti olacağından . Elimizdeki değeri 0×01 (0b00000001)  ile OR işlemine sokuyoruz. Bu işlem son biti(LSB) her zaman 1 yapacağı için (LSB biti 0 olarak verildiğinden elimizdeki değerin LSB biti ne olursa olsun o bitin değeri 1 olacaktır.) slave adrese okuma yapmak istediğimizi belirtmiş oluyoruz.
Satır 46’da hattın tekrar veri aktarım işlemine uygun olana kadar programın beklemesini sağlıyoruz. Idle()fonksiyonu hat uygun olana kadar kendi içinde boş bir döngüye girer.
Satır 49’da data_rx değişkenine slave cihazından 1 byte’lık veri okuyoruz.
Satır 51’de artık başka veri istemediğimizi belirtmek için NotAck() fonksiyonu ile NOT ACKNOWLEDGE sinyali gönderiyoruz. Bu sinyal karşı taraf açısından bağlantının biteceği anlamına gelir. Karşı taraf artık bir şey göndermez ( ACKNOWLEDGE sinyali de göndermez).
Satır 52’de NotAck()  ile istediğimiz koşulun sağlanıp sağlanmadığını kontrol ediyoruz. Bu durum geçene kadar bekliyoruz.
Satır 54’de I2C haberleşmesini bitiriyoruz. Satır 58’de Bitirme koşulunun sağlanıp sağlanmadığını kontrol ediyoruz.
Satır 57’da slave cihazından gelen veriyi show_on_leds() fonksiyonuyla ledlerde gösteriyoruz. (Gelen verinin 0-7 arasında olduğunu kabul etmemiz gerekiyor çünkü sadece 3 tane ledimiz var)
Satır 62 ve 63’da RB0 pinine bağlı butona basılıp basılmadığı kontrol ediliyor. Eğer butona basılıp çekilirse ona göre işlem yapılacak.  Yapılacak olan işlem; slave cihazına “1” sayısı göndermek (slave cihazı aldığı bu sayıyı kendi ledlerinde gösterecek).
Satır 68’de I2C hattı veri aktarımına uygun olana kadar bekleniyor. Satır 69’de I2C haberleşmesi başlatılıyor. Satır 70’te başlama şartının sağlanıp sağlanmadığı kontrol ediliyor (Başlama şartı sağlana kadar bekleniyor).
Satır 72’de slave cihazın adres bilgisiyle beraber bu sefer okuma işlemi yapacağımızı belirtmek için son biti (LSB) 1 yapmamız gerekiyor. Bunun için addr değişkenini 0xFE (0b11111110) sayısıyla AND işlemine sokuyoruz. Bu işlem giden 8 bitlik datanın son bitini her zaman 0 yapacağı için slave cihazına yazma işlemi yapacağımızı belirtmiş oluruz.
Satır 73′te hat veri aktarımı için uygun olana kadar bekliyoruz. Satır 75’te data_tx değişkenini slave cihazına I2C üzerinden gönderiyoruz (1 sayısı gidecek). Satır 76’da hattın idle durumuna gelmesi için yeniden bekliyoruz.
Satır 80’de I2C haberleşmesini bitiriyoruz. Satır 81’de Bitirme koşulunun sağlanıp sağlanmadığını kontrol ediyoruz.
Satır 82 ve 83′de RB1 pinine bağlı butona basılıp basılmadığını kontrol ediyoruz. Bu butonun yaptığı şeyde RB0’dakiyle aynı. Tek fark burada “1” sayısı yerine data_tx’in mevcut değerini 1 artırarak göndermesi.
Satır 106’da data_rx’deki değeri ledlerde gösterebilmek için yazılmış fonksiyon bulunuyor.
Not: I2C bağlantısı kurulurken donanımsal olarak da yapılması gerekenler vardır. Master cihazın SDA pinini slave cihazın SDA pinine, slave cihazın SCL pinini master cihazın SCL pinine bağlamak gerekir fakat “pull-up”yapılması gerekebilir. Pull-up denen şey, hat boştayken hattın hangi durumda olacağını belirlemektir. Eğer hattın boştayken hangi durumda olacağını belirlemezsek, hatta iletişim yokken hattın lojik-1’demi yoksa lojik-0’damı olduğu belirsiz olur. Biz bunu istemiyoruz. Hat boştayken sürekli olarak lojik-1’de (yani ~5 volt) olmasını istiyoruz. Bunun için kurmamız gereken devre şeması aşağıdaki şekilde verilmiştir

Rp dirençleri 1k’lık yada 10k’lık seçebiliriz. Çok düşük veya çok yüksek olmadığı sürece problem olmayacaktır. Amaç hattı 5 volt’a bağlamaktır esasında.
Aşağıda iki adet PIc18F4585 mikrodenetleyicisinin birbirine I2C haberleşmesi yapacak şekilde bağlantısı görünüyor (Pull-up kullanılarak
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>
#include <i2c.h>
#include <spi.h>
#pragma config OSC = HS, WDT = OFF, LVP = OFF
char data_rx=0, addr=0, read_write=0, flag=0, i=0, dummy;
char save[15] = {2,4,6,3,5,7,1,2,3,4,5,6,7};
void show_data_on_leds(char);
void int_handler(void);
#pragma code high_vector=0x08
void high_interrupts (void) {
    _asm GOTO int_handler _endasm
}
#pragma code low_vector=0x18
void low_interrupts (void) {
    _asm GOTO int_handler _endasm
}
#pragma code
#pragma interrupt int_handler
void int_handler(void) {
    if(PIR1bits.SSPIF == 1) {
        if(SSPSTATbits.D_A == 0) { //gelen bilgi adres ise
            while(!DataRdyI2C());
            addr = ReadI2C();
            if(addr & 0x01) { //master reading
                PORTB = 0b00000000;
                Delay10KTCYx(50);
                PORTB = 0b00111000;
                Delay10KTCYx(50);
                PORTB = 0b00000000;
                if(SSPSTATbits.READ_WRITE == 1) {
                    WriteI2C(save[i]);
                    while(SSPCON2bits.ACKEN);
                    i++;
                }
            }
        }

        else if(SSPSTATbits.D_A == 1) { //gelen bilgi data ise
            if(addr & 0x01)
                dummy = SSPBUF; //mode:master reading, buffer temizleniyor
            else {
                while(!DataRdyI2C());
                data_rx = ReadI2C(); //mode:master writing, data okunuyor
                show_data_on_leds(data_rx);
            }
        }
        PIR1bits.SSPIF = 0;
    }
}
void main(void) {
    ADCON1 = 0x0F;
    CloseSPI();
    CloseI2C();
    TRISB = 0x07;
    PORTB = 0;
    TRISC = 0;
    TRISCbits.RC3 = 1;
    TRISCbits.RC4 = 1;
    PORTC = 0;
    PORTB = 1;
    OpenI2C( SLAVE_7, SLEW_OFF);
    SSPADD = 10; //SSPADD contains I2C device address in SLAVE mode
    INTCONbits.GIE = 1;
    INTCONbits.PEIE = 1;
    PIE1bits.SSPIE = 1;
    while(1); //haberlesme istegi gelene kadar bekle
}

//****************************DATA GOSTER********************************//

void show_data_on_leds(char data) {
    if(data == 1) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 0;
        PORTBbits.RB5 = 0;
    }
    if(data == 2) {
        PORTBbits.RB3 = 0;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 0;
    }

    if(data == 3) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 0;
    }
    if(data == 4) {
        PORTBbits.RB3 = 0;
        PORTBbits.RB4 = 0;
        PORTBbits.RB5 = 1;
    }
    if(data == 5) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 0;
        PORTBbits.RB5 = 1;
    }
    if(data == 6) {
        PORTBbits.RB3 = 0;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 1;
    }
    if(data == 7) {
        PORTBbits.RB3 = 1;
        PORTBbits.RB4 = 1;
        PORTBbits.RB5 = 1;
    }
}
Slave cihazına yüklenen program kesme mekanizmasıyla çalışacak. Karta I2C üzerinden veri geldiği zaman bir kesme oluşacak ve biz o kesmeye gidip gelen veriyi analiz edeceğiz (Veriyle beraber read/write bitinin geldiğini de unutmamak gerekiyor).
Satır 16’da değişkenler tanımlanıyor. data_rx gelen veriyi tutacak, addr slave cihazın adres bilgisini tutacak, dummydğişkenini şimdilik kullanmayacağız.
Satır 17’de save adında bir dizi tanımladık. Bu dizi karşı tarafa gönderilecek elemanları içeriyor. Master bizden her bir eleman okumak istediğinde bu dizideki elemanları sırasıyla göndereceğiz.
Satır 19’da gelen verileri ledlerde göstermek için yazılan fonksiyonun prototipi bulunuyor.
Satır 36’de kesme mekanizmasına giriliyor. Satır 36’dan itibaren I2C kesmesi oluştuğunda çalışacak kodlar bulunuyor.
Satır 37’deki SSPTATbits.D_A == 0 ifadesi master taraftan gelen verinin adres bilgisi olup olmadığını kontrol ediyor. Bu bit “0” ise karşı taraftan adres geliyor, “1” ise karşı taraftan alınması gereken veri geliyor anlamına gelir (SSPSTATbits.D_A yerine SSPSTATbits.DATA_ADRESS de yazılabilir).
Satır 38’de alınacak data uygun olana kadar bekleniyor. Satır 39’da adres bilgisi I2C üzerinden okunuyor.  Şimdi bu adres bilgisinin son bitinin 1’mi yoksa 0’mı olduğunu kontrol etmemiz gerek. Ben iki kere kontrol ettim ama siz bir sonraki 2 adımdan birini de uygulayabilirsiniz. Aynı sonucu verecektir.
Satır 41’de gelen addr değişkeninin son biti kontrol ediliyor. Eğer son bit “1” ise bu bloktaki işlemler yapılacak.
Satır 48’deki SSPSTATbits.READ_WRITE == 1 ifadesi Satır 41’deki işlemin aynısını yapıyor. Eğer bu bit “1” ise master tarafı okuma yapmak istiyor, “0” ise master tarafı yazmak istiyor anlamına gelir.
(SSPSTATbits.READ_WRITE yerine SSPSTATbits.R_W de yazılabilir).
Satır 49’da save dizimizdeki değerimiz gönderiliyor. Satır 50′de gönerme işleminin tamamlanması bekleniyor. Satır 52’de dizi değişkeni bir sonraki elemanı gösterecek şekilde ayarlanıyor.
Satır 57’deki SSPSTATbits.D_A == 1 ifadesi master tarafınfan gelen verinin okunabilir veri olup olmadığını kontrol ediyor. Eğer gelen veri adres bilgisi değil de alınması gereken bilgiyse bu bloktaki kodlar çalışacak (SSPSTATbits.D_A yerine SSPSTATbits.DATA_ADRESS de yazılabilir). Gelen bilgi data ise bu karşı tarafın adres bilgisinin sonunda sıfır gönderdiği anlamına gelir. Bu kontrol bir önceki if bloğunda yapılmıştır. Eğer alınan son bitsıfır ise veri gönderilmemiş, son bit bir ise veri gönderilmiştir. Eğer son bit sıfır ise veri gönderilmez ve donanım kendiliğinden bir Ack sinyali gönderir. Master bunun üzerine bu cihaza okunması gereken veriyi gönderir. Bu sefer oluşan kesmede program Satır 57′deki koşulu sağlar ve bu bloktaki kodlar çalışır.
Satır 63’te veri okunmaya uygun olana kadar bekleniyor. Satır 64’de veri data_rx değişkenine aktarılıyor.
Satır 65’de okunan veri ledlerde gösterilmek üzere show_on_leds()  fonksiyonuna parametre olarak gönderiliyor.
Satır 69’da I2C kesmesinin oluştuğunu belirten flag sıfırlanıyor.
Satır 74’de tüm ADC giriş/çıkışları dijital olacak şekilde ayarlanıyor. Satır I2C modülü kapatılıyor Daha sonra I2C modülünü tekrar kullanıma açacağız.
Satır 78-84 arasında giriş çıkış portlarını ayarlayıp onlara ilk değerlerini veriyoruz. C portunun giriş çıkışlarıOpenI2C() fonksiyonu tarafından da ayarlabilir ama bu satırlarda görüldüğü şekilde kendimiz de ayarlayabiliriz.
Satır 86’da I2C modülü kullanıma açılıyor. Slave modu aktif.
Satır 87’de cihazımız slave olduğu için cidaha bir adres veriyoruz. Bu adresi istediğimiz gibi verebiliriz, yeter ki master cihazdaki adres bilgisi burada SSPADD registerına yazdığımız değerle eşit olsun. (Burada değeri “10” olarak yazdım, istersem bu değeri hexadecimal olarak “0x0A” olarak da yazabilirdim. Bir fark yaratmaz.)
Satır 89,90,91’de global kesmeler, dış kesmeler ve I2C kesmeleri aktifleştiriliyor.
Satır 93’de program sonsuz döngüde veri almak için bekletiliyor



Yorumlar