I²C (Inter-Integrated Circuit)
Bu konuda I²C'den bahsedeceğim. Tam olarak Inter-Integrated Circuit olarak tanımlanır. Bütünleşmiş devre anlamına gelir. Bir haberleşme protokolüdür burada bahsedilen haberleşme senkronize olarak haberleşmedir. Arduino'dan daha önce böyle bir şeyi duymuşsunuzdur.
Düşük hızlı çevre birimlerii mainboardlarda, embedded systemsda, cep telefonlarında kullanılır bu protokol. Üreticisi Philips'tir. Motora gibi ve birçok daha büyük kurumlar, firmalar tarafından kullanılır. I²C standartlarıyla uyumlu ürünler piyasaya sürerler. Mantığına bakalım;
Ground'ı saymazsak bunun dışında iki adet hatta ihtiyacımız oluyor, SDA-SCL ve bizim burada gördüğünüz gibi 2 master, 3 slaveimiz var. Haberleşmesi de bu şekilde oluyor. Bunun çıkış sinyalini lojik olarak inceleyecek olursak;
Kendinize t0 ve t1 belirleyerek arasındaki integrali incelerseniz çok daha iyi yorumlayabilirsiniz, aynı şekilde t0 ve t1 belirlerseniz bunların genel türevini alırsanız mantığını anlayabilirsiniz.
Şimdi ise kendimiz bunun konfigürasyonunu yapalım.
Configuration Parameters
Kod:
[COLOR="Cyan"](voıd) [/COLOR]I2C_config ([COLOR="cyan"]voıd[/COLOR])
{
__HAL_RCC_I2C1_CLK_ENABLE();
myI2Chandle.Instance = I2C1;
myI2Chandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
myI2Chandle.Init.ClockSpeed = [COLOR="cyan"]100000[/COLOR];
myI2Chandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
myI2Chandle.Init.DutyCycle = I2C_DUTYCYCLE_2;
myI2Chandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
myI2Chandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;
myI2Chandle.Init.OwnAddress1 = [COLOR="cyan"]0[/COLOR];
myI2Chandle.Init.OwnAddress2 = [COLOR="cyan"]0[/COLOR];
HAL_I2C_Init(&myI2Chandle);
//voıd yazmak zorunda kaldım çünkü sansürlüyor.
}
__HAL_RCC_I2C1_CLK_ENABLE();
I²C'imizde üç adet channelımız bulunmaktadır ve biz bunun birincisini aktif ederek ona clock vereceğiz, bu satırımızda bu işlemi gerçekleştiriyoruz.
myI2Chandle.Init.AddressingMode
I²C'de 0-255 arasında kullanacağımız adresin sınırlarını belirliyoruz.8 bit seçme sebebimiz budur.
myI2Chandle.Init.ClockSpeed
Clockumuzu burada 100kHz olarak veriyoruz.
myI2Chandle.Init.DualAddressMode
Dual adrese ihtiyaç duyacak olursak burayı belirleyeceğiz fakat biz dual adrese ihtiyaç duymuyoruz. Bu sebepten disable ediyoruz.
myI2Chandle.Init.DutyCycle
Duty cycle'ı PWM (Pulse Width Modulation)den biliyorsanız burayı rahat kavrarsınız, Açıklayacak olursak; gönderdiğimiz işarette 1 olan kısmını ne kadar süreyle belirlediğimiz kısımdır. Burada ise 2'dir. 100000'in 2clock cycleında ne kadar duty olacağını belirliyoruz.
myI2Chandle.Init.GeneralCallMode
Genel arama modumuzu belirliyoruz burada aslında. (çağırma*) Bunu belirleyip belirmeyeceğimizi söylüyoruz. Biz disable ediyoruz.
myI2Chandle.Init.NoStretchMode
Burada bir esneme, genişleme olup olmayacağını belirliyoruz diyebiliriz. Biz bunu aktif etmiyoruz.
myI2Chandle.Init.OwnAddress1
Slave olsaydık bunu 1 girmemiz gerekirdi fakat masterız.
myI2Chandle.Init.OwnAddress2
Slave olsaydık bunu 1 girmemiz gerekirdi fakat masterız.
GPIO'nun konfigürasyonu için buraya giriniz.
Main programımızı da açıklayalım;
Kod:
int main ()
{
HAL_Init();
f3_GPIO();
I2C_config();
for (int i=0; i<255; i++)
{
if (HAL_I2C_IsDeviceReady(&myI2Chandle, i,i,10) == HAL_OK)
break ;
}
I²C'imizde 6'ya clocku 7'ye datayı veriyoruz. For döngümüzde 255'e kadar değer döndüreceğiz kullandığımız I²C kadar break yapacak. If koşulumuzda sürekli data gönderiyoruz burada bize eleman olduğu hakkında bildiri yapıyor ve deviceda işaret oluyor. Programımızda break satırına breakpoint koyarsak programı çalıştırırken veya debug yaparken koyduğumuz yerde i'nin adresine bakarız ve ona göre elemanlarımızı oraya koyarız. Bu da bize kolaylık sağlar.
Kod:
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitTypeDef mypin;
mypin.Pin = GPIO_PIN_6 |GPIO_PIN_7;
mypin.Mode = GPIO_MODE_AF_OD;
mypin.Pull = GPIO_PULLUP;
mypin.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
mypin.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB,&mypin);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig (SYSTICK_CLKSOURCE_HCLK);.
HAL_NVIC_SetPriority (SysTick_IRQn,0,0);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
Burada bilmemiz gereken şey prescaler kavramı. Frekansımızı belirli bir orana bölerek clock veriyoruz. Prescaler kavramına ayrıca bir bakmanızı tavsiye ederim. Burada ise 1000'e bölüyoruz.
HAL_SYSTICK_CLKSourceConfig (SYSTICK_CLKSOURCE_HCLK);
Burada bilmemiz gereken şey CubeMX'de external ve internal olarak belirlediğimiz osilatörün kristal ile çalışacağıdır. Virtual olarak yaptığımız kısmı burada kod ile yapıyoruz.
HAL_NVIC_SetPriority (SysTick_IRQn,0,0);
Bu kodumuz interruptların(kesmelerin) vektörel yönlendirilmesi ile ilgilidir. Şayet öncelikleri eşitse adresi küçük olanı işleme alır.
[ame="https://www.youtube.com/watch?v=1uHJ9q02Y1s&t=625s"]Videolu Anlatım;[/ame]