I2C Bağlantısı

Bu projede Atmega8'de bulunan TWI (Two Wire serial Interface) modülünü kullanarak Dallas DS1307 saat entegresiyle mikroişlemcimizi konuşturacağız. DS1307 saat entegresi Philips'in I2C protokolünü desteklemektedir. Biz de Atmega8'in TWI modülünü I2C protokolü için kullanmak ve bir önceki LCD projemize küçük ekler yapmak suretiyle dijital bir saat yapacağız. Ancak burada amaç saat yapmak değil TWI modülünü ve I2C protokolünü anlamaktır. Bu proje öğrenildikten sonra I2C protokolünü destekleyen her türlü çevre birimini (çeşitli entegre ve mikroişlemciler, sensörler, vb) işlemcinize bağlamak çok kolay olacaktır.

Projemizde Peter Fleury'nin yazdığı I2C kütüphanesini kullanacağız. Proje dosyaları arasında bu kütüphaneden gelen 3 yeni dosya var: i2cmaster.h başlık dosyası, twimaster.c C dosyası ve i2cmaster.S assembler dosyası. Bu dosyaların ayrıntılarına girmeden önce TWI modülünü biraz açmaya çalışalım. İşlemcideki TWI modülünü ek bir donanım olarak düşünebilirsiniz. Atmega8 işlemcisi PWM, A/D çevirici, USART gibi pek çok donanıma sahiptir. TWI modülünü yani donanımı kullanarak I2C bağlantısı kurduğunuzda işlemcinin üzerindeki iş yükü azalır ve protokol ile ilgili tüm detaylar bu ek donanım tarafından yürütülür. Eğer mikroişlemcinizin TWI modülü yoksa ya da TWI için ayrılan pinleri (Atmega8 için PC4 ve PC5) başka bir iş için kullanmak zorundaysanız aynı işi yazılım olarak da yapabilirsiniz. Ama amacınız her zaman öncelikle var olan donanımsal özellikleri kullanmak olmalıdır. Sonuç olarak TWI donanımını kullanacaksanız twimaster.c dosyasını, I2C protokolünü yazılımla yürütecekseniz i2cmaster.S dosyasını kullanmalısınız. Bu bir assembler dosyasıdır ve bir WinAVR projesi içine rahatlıkla eklenebilir. Bunun için make dosyasında assembler dosyaları ile ilgili bölümde dosya uzantısının büyük harfle yazıldığına dikkat ederek gerekli değişiklikleri yapmalısınız ( ASRC=i2cmaster.S ).

Bu projede TWI modülünü kullandığımız için projemizi twimaster.c dosyası ile derleyeceğiz, i2cmaster.S dosyası deney yapmanız için proje dosyaları arasında yer alıyor. DS1307'nin çalışması için 32.768Hz'lik bir kristale ihtiyaç var, bozuk bir quartz kol saatinin içindeki kristali kullanabilirsiniz. DS1307'i işlemciye bağlarken dikkat etmeniz gereken önemli noktalardan biri de pull-up dirençleridir ( 4,7K değerindeki iki adet direnci SDA ve SCL bacaklarına pull-up direnci olarak bağlamanız gerekir (bakınız Resim3). DS1307'nin 3 numaralı bacağına (VBat) 3 voltluk bir saat pili bağladığınız zaman devre tarih ve saat bilgisini yıllarca saklar, böylece devre her kapanıp açıldığında saati yeniden kurmak gerekmez. Yaptığınız devrede pil kullanmayacaksanız, VBat bacağını toprağa ( - ) bağlamanız gerekir (bakınız Resim 4).

#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "lcd.h"
#include "i2cmaster.h"
void ds1307_write(uint8_t address, uint8_t data);
uint8_t ds1307_read(uint8_t address);
void delay_ms(uint16_t ms);

//Bu satir ile bir stream objesi yaratilip lcd_put_char fonksiyonuna
//yonlendiriliyor. Printf ve turevleri icin gerekli
FILE lcd_str = FDEV_SETUP_STREAM(lcd_putchar, NULL, _FDEV_SETUP_WRITE);

//Ana Program Fonksiyonu
int main(void){
uint8_t sec=0,min=0,hr=0,date=0,month=0,year=0,wday=0,h1,h2,m1,m2;
lcd_init(); //lcd'yi hazirla
//standart giris ve cikis lcd_str olsun
stdout = stdin = &lcd_str;
lcd_goto(1,4); //satir 1, sutun 4e git
fprintf_P(stdout,PSTR("I2C Test"));
lcd_goto(2,1); //satir 2, sutun 1e git
fprintf_P(stdout,PSTR("www.berik.net"));
delay_ms(2500);
lcd_clr();

//saati kuralim
ds1307_write ( 0x00 , 0 ); // -- saniye
ds1307_write ( 0x01 , 0 ); // -- dakika
ds1307_write ( 0x02 , 13 ); // -- saat
ds1307_write ( 0x03 , 0 ); // -- haftanin kacinci gunu
ds1307_write ( 0x04 , 27 ); // -- gun
ds1307_write ( 0x05 , 7 ); // -- ay
ds1307_write ( 0x06 , 7 ); // -- yil
ds1307_write ( 0x07 , 0); // -- option register
while(1){ //sonsuz dongu
sec= ds1307_read (0x00);
min= ds1307_read (0x01);
hr= ds1307_read (0x02);
wday= ds1307_read (0x03);
date= ds1307_read (0x04);
month= ds1307_read (0x05);
year= ds1307_read (0x06);
//basit BCD cevrimi
h1=hr/10;
h2=hr-(h1*10);
m1=min/10;
m2=min-(m1*10);
lcd_goto(1,0);
printf("Saat: %02d:%02d:%02d",hr,min,sec);
lcd_goto(2,0);
printf("Tarih: %02d/%02d/%02d",date,month,year);
delay_ms(100); }
}

void ds1307_write(uint8_t address, uint8_t data){
uint8_t loc;
loc=data; loc=loc / 10;
loc=loc * 16;
data=data % 10;
loc=loc + data;
data=loc; i2c_start(0xd0);
i2c_write(address);
i2c_write(data);
i2c_stop(); }

uint8_t ds1307_read(uint8_t address){
uint8_t temp,loc;
i2c_start(0xd0);
i2c_write(address);
i2c_stop();
i2c_start(0xd1);
temp=i2c_readNak();
i2c_stop();
loc=temp;
loc=loc &0xf0;
loc=loc/16;
temp=temp & 0x0f;
loc=(loc * 10)+temp;
temp=loc; return(temp);
}

void delay_ms(uint16_t ms){
for(uint16_t c=0;c<ms;c++)_delay_ms(1);
}

Adlarından da anlaşılacağı üzere ds1307_read ve ds1307_write fonksiyonları, I2C alt rutinlerini kullanarak DS1307'nin yazmaçlarına belli bir değeri yazmak ve bu yazmaçlardaki değerleri okumak için kullanılır. ( DS1307'nin çalışması ile ilgili daha detaylı bilgi için entegrenin el kitabına bakınız. )

Proje Dosyaları

Proje Dosyaları