#include <reg52.h>
#include <intrins.h>
#define ERROR 10
sbit SDA=P3^0;
sbit SCL=P3^1;
enum eepromtype{AT2401,AT2402,AT2404,AT2408,AT2416,AT2432,AT2464,AT24128,AT24256};
enum eepromtype enumer;
unsigned char code buf1 []={1,3,5,7,9,10,11,12,13,15}; /* 發送緩沖區 */
unsigned char buf2 [10]; /* 接收緩沖區 */ /* 一個通用的24C01-24C256共9種EEPROM的字節讀寫操作程序,
此程序有五個入口條件,分別為讀寫數據緩沖區指針,
進行讀寫的字節數,EEPROM首址,EEPROM控制字節,
以及EEPROM類型。此程序結構性良好,具有極好的容錯性,程序機器碼也不多:
DataBuff為讀寫數據輸入/輸出緩沖區的首址
Length 為要讀寫數據的字節數量
Addr 為EEPROM的片內地址 AT24256為0~32767
Control 為EEPROM的控制字節,具體形式為(1)(0)(1)(0)(A2)(A1)(A0)(R/W),其中R/W=1,
表示讀操作,R/W=0為寫操作,A2,A1,A0為EEPROM的頁選或片選地址;
enumer為枚舉變量,需為AT2401至AT24256中的一種,分別對應AT24C01至AT24C256;
函數返回值為一個位變量,若返回1表示此次操作失效,0表示操作成功;
ERROR為允許最大次數,若出現ERRORCOUNT次操作失效后,則函數中止操作,并返回1
SDA和SCL由用戶自定義,這里暫定義為P3^0和P3^1; */ /* ----- AT24C01~AT24C256 的讀寫程序 ------ */
bit RW24xx(unsigned char *DataBuff,unsigned char Length,unsigned int Addr,
unsigned char Control,enum eepromtype enumer)
{ void Delay(unsigned char DelayCount); /* 延時 */
void Start(void); /* 啟動總線 */
void Stop(void); /* 停止IIC總線 */
bit RecAck(void); /* 檢查應答位 */
void NoAck(void); /* 不對IIC總線產生應答 */
void Ack(void); /* 對IIC總線產生應答 */
unsigned char Receive(void); /* 從IIC總線上讀數據子程序 */
void Send(unsigned char sendbyte); /* 向IIC總線寫數據 */
unsigned char data j,i=ERROR;
bit errorflag=1; /* 出錯標志 */
while(i--)
{ Start(); /* 啟動總線 */
Send(Control & 0xfe); /* 向IIC總線寫數據 */
if(RecAck()) continue; /* 如寫正確結束本次循環 */
if(enumer > AT2416)
{ Send((unsigned char)(Addr >> 8));
if(RecAck()) continue;
}
Send((unsigned char)Addr); /* 向IIC總線寫數據 */
if(RecAck()) continue; /* 如寫正確結束本次循環 */
if(!(Control & 0x01))
{ j=Length;
errorflag=0; /* 清錯誤特征位 */
while(j--)
{ Send(*DataBuff++); /* 向IIC總線寫數據 */
if(!RecAck()) continue; /* 如寫正確結束本次循環 */
errorflag=1;
break;
}
if(errorflag==1) continue;
break;
}
else
{ Start(); /* 啟動總線 */
Send(Control); /* 向IIC總線寫數據 */
if(RecAck()) continue;
while(--Length) /* 字節長為0結束 */
{ *DataBuff ++= Receive();
Ack(); /* 對IIC總線產生應答 */
}
*DataBuff=Receive(); /* 讀最后一個字節 */
NoAck(); /* 不對IIC總線產生應答 */
errorflag=0;
break;
}
}
Stop(); /* 停止IIC總線 */
if(!(Control & 0x01))
{ Delay(255); Delay(255); Delay(255); Delay(255);
}
return(errorflag);
} /* * * * * 以下是對IIC總線的操作子程序 * * * * */
/* * * * * * 啟動總線 * * * * */
void Start(void)
{ SCL=0; /* SCL處于高電平時,SDA從高電平轉向低電平表示 */
SDA=1; /* 一個"開始"狀態,該狀態必須在其他命令之前執行 */
SCL=1;
_nop_(); _nop_(); _nop_();
SDA=0;
_nop_(); _nop_(); _nop_(); _nop_();
SCL=0;
SDA=1;
} /* * * * * 停止IIC總線 * * * * */
void Stop(void)
{ SCL=0; /*SCL處于高電平時,SDA從低電平轉向高電平 */
SDA=0; /*表示一個"停止"狀態,該狀態終止所有通訊 */
SCL=1;
_nop_(); _nop_(); _nop_(); /* 空操作 */
SDA=1;
_nop_(); _nop_(); _nop_();
SCL=0;
} /* * * * * 檢查應答位 * * * * */
bit RecAck(void)
{ SCL=0;
SDA=1;
SCL=1;
_nop_(); _nop_(); _nop_(); _nop_();
CY=SDA; /* 因為返回值總是放在CY中的 */
SCL=0;
return(CY);
} /* * * * *對IIC總線產生應答 * * * * */
void Ack(void)
{ SDA=0; /* EEPROM通過在收到每個地址或數據之后, */
SCL=1; /* 置SDA低電平的方式確認表示收到讀SDA口狀態 */
_nop_(); _nop_(); _nop_(); _nop_();
SCL=0;
_nop_();
SDA=1;
} /* * * * * * * * * 不對IIC總線產生應答 * * * * */
void NoAck(void)
{ SDA=1;
SCL=1;
_nop_(); _nop_(); _nop_(); _nop_();
SCL=0;
} /* * * * * * * * * 向IIC總線寫數據 * * * * */
void Send(unsigned char sendbyte)
{ unsigned char data j=8;
for(;j>0;j--)
{ SCL=0;
sendbyte <<= 1; /* 使CY=sendbyte^7; */
SDA=CY; /* CY 進位標志位 */
SCL=1;
}
SCL=0;
} /* * * * * * * * * 從IIC總線上讀數據子程序 * * * * */
unsigned char Receive(void)
{ register receivebyte,i=8;
SCL=0;
while(i--)
{ SCL=1;
receivebyte = (receivebyte <<1 ) | SDA;
SCL=0;
}
return(receivebyte);
} /* * * * * * * * 一個簡單延時程序 * * * * * * * * * * * * */
void Delay(unsigned char DelayCount)
{ while(DelayCount--);
} /* ----- AT24C01~AT24C256 的讀寫程序 ------ */ void main()
{ unsigned char Control,*p1,*p2;
unsigned char Length;
unsigned int addr ; /* 24Cxx片內地址 */
p1=buf1;p2=buf2;
addr=0; /* 片內地址 AT24C256為0~32767 */
Length=8; /* 讀寫長度 */
enumer=AT24256; /* 讀寫AT24C256 */
Control=0xa0; /* 寫操作 */
RW24xx(p1,Length,addr,Control,enumer); /* 寫 */
Control=0xa1; /* 讀操作 */
RW24xx(p2,Length,addr,Control,enumer); /* 讀 */
}
/* 以上為AT24C01~AT24C256的讀寫程序,各人可根據自己的需要應用。
在buf1中填入需要寫入的內容,buf2的大小可根據需要定義。
addr可根據使用的芯片選擇,可從任何位置讀寫,只要在該芯片的范圍內。
enumer=ATxxx,根據使用的芯片賦值。各函數中的形式參數不需改變。
本程序只要在調用的程序中定義實際參數即可,上述各子程序不必改動。*/
|