ATMELのAT-Tiny26,ATmega,R8Cなどのワンチップマイコン,C言語,JAVAなどのプログラミング言語の入門のためのページです.サンプルプログラムを中心に紹介します.他にもLinixや数学ソフトなどの紹介も行います.

このブログを検索

あなたは 番目のお客様です.

2008年7月15日火曜日

マイコンでI2C-EEPROMの読み書きを行う


I2Cはプルアップされた2本の信号線による双方向通信方式です.
24CXXタイプのEEPROMは,SDAとSCLの2ピンでデータの読み書きができます.
ATMEL24C256は2.7-5.5Vの電圧で動き,8ビット×32768のデータが記録できます.
ATMEL24C256は書き込みに10-20msの時間が必要でこの間は,信号を受け付けません.

SDAピンがデータの書き込みと読み込みを兼ねます(2-wire Serial)
SDAピンはプルアップ(1kΩでVCCにつなげる)してPB2と接続します
SCLピンはプルアップ(1kΩでVCCにつなげる)してPB1と接続します
EEPROMを1個だけ使うのであればA0=0,A1=0としてGNDにつなげておくのが望ましいが,
無接続でも動きます.
WPピンはhighにすると書き込み不可です.GNDにつなげておくか,無接続でも動きます
SCLの立ち上がりでデータ書き込み,SCLの立ち下がりでデータ読み込みが行われます.

ATMEL24C256のピンの説明
VCC:電源のプラス
A0:Address Inputs(GNDまたは無接続)
A1:Address Inputs(GNDまたは無接続)
SDA:Serial Data:PB1
SCL:Serial Clock Input:PB0
WP:Write Protect(GNDまたは無接続)
NC:No Connect無接続

接続の回路











以下がAT-Tiny26Lを使ったATMEL24C256のテストプログラム
AT-Tiny26Lは内部発振または外部発振の8MHzで64msの遅延Start-up timeに設定しました
指定したアドレスに値をByteWriteモードで書き込み,
今度はこのアドレスの値をRandomReadモードで読み込み,
値をPAに出力する(LEDが点灯する)
#include <avr/io.h>
#include <avr/interrupt.h>

uint16_t a;//aは16ビット整数でマイクロ秒単位のカウントを行うa<65535

ISR (TIMER0_OVF0_vect){ //タイマカウンタ0のオーバーフローで呼ばれる
a+=256;
}
//マイクロ秒単位の待ち
void delay(int16_t t){
TCNT0=0;
a=0;
while(a+TCNT0<t){}
}

void start(void){
PORTB|= 1<<1;// set PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB&=~(1<<1); // clear PB1
PORTB&=~(1<<0); // clear CLK
delay(5);
}
void stop(void){
PORTB&=~(1<<1); // clear PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB|= 1<<1;// set PB1
PORTB&=~(1<<0); // clear CLK
delay(5);
}
void Hclk(void){//SDAがhighで1クロック
PORTB|= 1<<1;// set PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB&=~(1<<0); // clear CLK
delay(5);
}
void Lclk(void){//SDAがlowで1クロック
PORTB&=~(1<<1); // clear PB1
PORTB|= 1<<0; // set CLK
delay(5);
PORTB&=~(1<<0); // clear CLK
delay(5);
}

void write(uint16_t add,uint8_t dat){//EEPにデータ書き込み
uint16_t k;
uint8_t i;
start();
for(k=0B100000000;k>0;k=k>>1)if(k & 0B101000000)Hclk();
else Lclk();
i=add/256; //上位アドレス
for(k=0B10000000;k>0;k=k>>1)if(k & i)Hclk();
else Lclk();
Lclk();//ACK
i=add%256; //下位アドレス
for(k=0B10000000;k>0;k=k>>1)if(k & i)Hclk();
else Lclk();
Lclk();//ACK
i=dat;
for(k=0B10000000;k>0;k=k>>1)if(k & i)Hclk();
else Lclk();
Lclk();//ACK
stop();//Stop
}

//データ読み込み
uint8_t read(uint16_t add){
uint8_t i;
uint16_t k;
start();
for(k=0B100000000;k>0;k=k>>1)if(k & 0B101000000)Hclk();
else Lclk();
i=add/256; //上位アドレス
for(k=0B10000000;k>0;k=k>>1)if(k & i)Hclk();
else Lclk();
Lclk();//ACK

i=add%256; //下位アドレス
for(k=0B10000000;k>0;k=k>>1)if(k & i)Hclk();
else Lclk();
Lclk();//ACK
start();
for(k=0B100000000;k>0;k=k>>1)if(k & 0B101000010)Hclk();
else Lclk();
DDRB&=~(1<<1); //PB1を入力に変更
i=0;
for(k=0B10000000;k>0;k=k>>1){
PORTB|= 1<<0; // set CLK
delay(5);
if(PINB & (1<<1))i+=k;
PORTB&=~(1<<0); // clear CLK
delay(5);
}
DDRB|= 1<<1; //PB1を出力に変更
Hclk();//NO ACK
stop();//Stop
return i;
}

int main(void)
{
uint8_t i,j,x;
DDRA=0B11111111; //PAは全てOUT,LEDを接続しデータを確認する
DDRB=0B00000011; //PB0,PB1:OUT
TCCR0=0B00000010; //タイマカウンタ0の分周をセットCK/8
TIMSK|= 1<<TOIE0; //タイマカウンタ0のオーバーフロー割り込みを許可する
sei(); //All Int Enable 割り込みを可能にする
for(i=0;i<65;i++){
write(i,i); //書き込み最初の引数は16ビット(uint16_t)
delay(30000); //書き込みに10-20msほど必要
x=read(i); //読み込み
PORTA=x; //データをPAに出力
for(j=0;j<50;j++)delay(10000); //Wait 0.5s
}
while(1){}//while(1)終了の無限ループ
}