51接EEPROM用24C08

51關掉資料就不見了啊,用一顆24C08的EEPROM來記錄要儲存的變數,下次開機再讀出來就行了

執行影片

接法

電路圖

點圖可以放大

-------------------------------------------------------------------------------------

動作描述(用程式碼讓SDA程SCL輸出動作,讓EEPROM知道我們要作什麼事

void Start()

{

SDA=1;

SCL=1;

SDA=0;

SCL=0;

}

void Stop()

{

SCL=0;

SDA=0;

SCL=1;

SDA=1;

}

------------------------------------------------------------------------------------------------------------------------

void NoAck()

{

SDA=1;

SCL=1;

SCL=0;

}

bit TestAck()

{

bit ErrorBit;

SDA=1;

SCL=1;

ErrorBit=SDA;

SCL=0;

return(ErrorBit);

}

------------------------------------------------------------------------------------------------------------------------------------

1.寫入資料到EEPROM上(應用上面的動作描述)

void Write8Bit(uchar input)

{

uchar temp;

for(temp=8;temp!=0;temp--)

{

SDA=(bit)(input&0x80);

SCL=1;

SCL=0;

input=input<<1;

}

}

---------------------------------------------------------------------------------------------------------------------------------

2.從EEPROM讀出資料(應用上面的動作描述)

uchar Read8Bit()

{

uchar temp,rbyte=0;

for(temp=8;temp!=0;temp--)

{

SCL=1;

rbyte=rbyte<<1;

rbyte=rbyte|((uchar)(SDA));

SCL=0;

}

return(rbyte);

}

----------------------------------------------------------------------------------------------------------------------------

3.此程式寫法與硬體特性說明

如DATASHEET所示

24C08一次只能讀寫8BIT

若要存取16BIT資料,則要分成2次寫,2次讀

讀寫16BIT資料的示意圖

點圖可以放大

先將要寫入的資料777寫入高八位(Data Address 0~7)

777/256 =3(取商數)

再將777的低八位寫入(Data Address 8~15)

777/256 = 9(取餘數)

讀取的時候一樣,先讀出高八位(Data Address 0~7)

3 X 256 = 768

再讀出低八位(Data Address 8~15)

9

2者相加 768+9 =777

===================完整程式碼==========================================

/******************************************

使用8051的P1_0接24C08的SCL腳.P1_1接SDA腳

做資料儲存的動作

MCU:AT89S51

石英:12MHZ

EEPROM:I2C 24C08

SCL跟SDA的上拉電阻:10K

函數指令及用法:

Write24c08(8BIT長度資料,寫入地址)

Write24c08_uint(16BIT長度資料,寫入地址)

uchar Read24c08(讀出地址)=>會回傳8BIT長度資料

uint Read24c08_uint(讀出地址)=>會回傳16BIT長度資料

*******************************************/

#include<regx51.h>

#define uchar unsigned char //unsigend簡化成u

#define uint unsigned int //unsigend簡化成u

#define ulong unsigned long //unsigend簡化成u

#define WriteDeviceAddress 0xa0 //定格式操作指令不可改

#define ReadDviceAddress 0xa1 //定格式操作指令不可改

sbit SCL=P1^0; //定義腳位,隨電路圖改變

sbit SDA=P1^1; //定義腳位,隨電路圖改變

/*延遲副程式*/

void DelayMs(uint number)

{

uchar temp;

for(;number!=0;number--)

{

for(temp=112;temp!=0;temp--) ;

}

}

/*********************************

以下動作是照DATASHEET做的勿亂改

**********************************/

void Start()

{

SDA=1;

SCL=1;

SDA=0;

SCL=0;

}

void Stop()

{

SCL=0;

SDA=0;

SCL=1;

SDA=1;

}

void NoAck()

{

SDA=1;

SCL=1;

SCL=0;

}

bit TestAck()

{

bit ErrorBit;

SDA=1;

SCL=1;

ErrorBit=SDA;

SCL=0;

return(ErrorBit);

}

/*********************************

以上動作是照DATASHEET做的勿亂改

**********************************/

/*寫DATA的動作*/

void Write8Bit(uchar input)

{

uchar temp;

for(temp=8;temp!=0;temp--)

{

SDA=(bit)(input&0x80);

SCL=1;

SCL=0;

input=input<<1;

}

}

/*寫8位元函數*/

void Write24c08(uchar ch,uchar address)

{

EA=0;

Start();

Write8Bit(WriteDeviceAddress);

TestAck();

Write8Bit(address);

TestAck();

Write8Bit(ch);

TestAck();

Stop();

DelayMs(10);

EA=1;

}

/*寫16位元函數*/

void Write24c08_uint(uint dat,uchar address)

{

uchar hi8,lo8;

hi8=dat/256;

lo8=dat%256;

Write24c08(hi8,address);

DelayMs(10); //很重要!2次寫入動作不延時則會寫入失敗!*(接不同石英可能須要微調)*

Write24c08(lo8,address+8);

}

/*讀DATA的動作*/

uchar Read8Bit()

{

uchar temp,rbyte=0;

for(temp=8;temp!=0;temp--)

{

SCL=1;

rbyte=rbyte<<1;

rbyte=rbyte|((uchar)(SDA));

SCL=0;

}

return(rbyte);

}

/*讀8位元函數*/

uchar Read24c08(uchar address)

{

uchar ch;

Start();

Write8Bit(WriteDeviceAddress);

TestAck();

Write8Bit(address);

TestAck();

Start();

Write8Bit(ReadDviceAddress);

TestAck();

ch=Read8Bit();

NoAck();

Stop();

return(ch);

}

/*讀16位元函數*/

uint Read24c08_uint(uchar address)

{

uint dat;

uchar hi8,lo8;

hi8=Read24c08(address);

lo8=Read24c08(address+8);

dat=(256*hi8)+lo8;

return(dat);

}

code seven_seg[10]={0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48}; //74LS47編碼IC對應0~9

code scan[3]={0x06,0x05,0x03}; //掃描碼FOR 74LS47 S1 ,S2 ,S3

unsigned char counter[3]={0,0,0}; //存放十位數,個位數,小數點第一位

unsigned char i;

int steps; //記錄encoder的步數

unsigned int temp; //給計時器工作用

void timer0_initialize(void) //初始化計時器0

{

EA=0; //關閉中斷功能(所有中斷副程式失效)

ET0=1; //開啟計時器0中斷功能

EX0=1; /* 設定接受INT0的中斷 */

EX1=1; /* 設定接受INT1的中斷 */

IT0=1; //設INT0為負緣觸發*(避免一次訊號累加,造成錯步)*

IT1=1; //設INT1為負緣觸發*(避免一次訊號累加,造成錯步)*

PX0=1; //INT0中斷優先處理

PX1=1; //INT0中斷優先處理

PT0=0; //timer0中斷延後處理*(避免遺漏encoder的訊號)*

TMOD|=0x01; //設定計時器模式

temp=65536-8333; //設定中斷一次的時間

TH0=temp/256; //填入高八位

TL0=temp%256; //填入低八位

TR0=1; //啟動計時器

EA=1; //開啟中斷功能(中斷副程式可以執行)

}

void timer0_isr(void) interrupt TF0_VECTOR using 1 //計時器中斷副程式,計時器中斷一次即執行*(此程式中每秒中斷120次)*

{

TR0=0; //停止計時器

TH0=temp/256; //重新埴入高八位

TL0=temp%256; //重新埴入低八位

TR0=1; //啟動計時器

counter[0]=steps%10; //取steps的小數點第一位

counter[1]=steps%100/10; //取steps的個位數

counter[2]=steps/100; //取steps的十位數

P2=scan[i]; //先上掃描碼導通小數點第一位的七段

P2|=seven_seg[counter[i]]; //將小數點第一位的七段碼OR進P2,以免破壞掃描碼

if(i==1)P2_7=0; //掃描到個位數七段加上小數點

else P2_7=1; //若不是個位數不用加小數點

i++; //導通下一顆七段

if(i>2)i=0; //掃描到十位數後重新從小數第一位開始掃描

}

static void xint0_isr(void) interrupt IE0_VECTOR //INT0中斷副程式

{

if(steps<1000)steps++; //ENCODER步數+1

}

static void xint1_isr(void) interrupt IE1_VECTOR //INT1中斷副程式

{

if(steps>0)steps--; //ENCODER步數-1

}

void main(void) //主程式

{

timer0_initialize(); //呼叫一次計時器初始化

while(1)

{

/*測試程序*/

if(P1_2==0)

{

Write24c08_uint(steps,0);

}

if(P1_3==0)

{

steps=Read24c08_uint(0) ;

}

/*測試OK*/

}

}