24C02:256 個字節(jié)的 EEPROM。一般情況下,EEPROM 擁有 30 萬到 100 萬次的壽命?;?I2C 通信協(xié)議的器件。I2C 是一個通信協(xié)議,它擁有嚴密的通信時序邏輯要求,而EEPROM 是一個器件,只是這個器件采樣了 I2C 協(xié)議的接口與單片機相連而已,二者并沒有必然的聯(lián)系,EEPROM 可以用其它接口, I2C 也可以用在其它很多器件上。
1、EEPROM寫數(shù)據(jù)流程
第一步,首先是 I2C 的起始信號,接著跟上首字節(jié),也就是我們前邊講的 I2C 的器件地
址,并且在讀寫方向上選擇“寫”操作。
第二步,發(fā)送數(shù)據(jù)的存儲地址。24C02一共 256 個字節(jié)的存儲空間,地址從 0x00~0xFF,我們想把數(shù)據(jù)存儲在哪個位置,此刻寫的就是哪個地址。
第三步,發(fā)送要存儲的數(shù)據(jù)第一個字節(jié)、第二個字節(jié)„„注意在寫數(shù)據(jù)的過程中,
EEPROM 每個字節(jié)都會回應一個“應答位 0”,來告訴我們寫 EEPROM 數(shù)據(jù)成功,如果沒有回應答位,說明寫入不成功。
在寫數(shù)據(jù)的過程中,每成功寫入一個字節(jié),EEPROM 存儲空間的地址就會自動加 1,當加到 0xFF 后,再寫一個字節(jié),地址會溢出又變成了 0x00。
2、EEPROM讀數(shù)據(jù)流程
第一步,首先是 I2C 的起始信號,接著跟上首字節(jié),也就是我們前邊講的 I2C 的器件地址,并且在讀寫方向上選擇“寫”操作。這個地方可能有同學會詫異,我們明明是讀數(shù)據(jù)為何方向也要選“寫”呢?剛才說過了,24C02 一共有 256 個地址,我們選擇寫操作,是為了把所要讀的數(shù)據(jù)的存儲地址先寫進去,告訴 EEPROM 我們要讀取哪個地址的數(shù)據(jù)。這就如同我們打電話,先撥總機號碼(EEPROM 器件地址),而后還要繼續(xù)撥分機號碼(數(shù)據(jù)地址),而撥分機號碼這個動作,主機仍然是發(fā)送方,方向依然是“寫”。
第二步,發(fā)送要讀取的數(shù)據(jù)的地址,注意是地址而非存在EEPROM 中的數(shù)據(jù),通知EEPROM 我要哪個分機的信息。
第三步,重新發(fā)送 I2C 起始信號和器件地址,并且在方向位選擇“讀”操作。
這三步當中,每一個字節(jié)實際上都是在“寫”,所以每一個字節(jié)EEPROM 都會回應一個“應答位 0”。
第四步,讀取從器件發(fā)回的數(shù)據(jù),讀一個字節(jié),如果還想繼續(xù)讀下一個字節(jié),就發(fā)送一個“應答位ACK(0)”,如果不想讀了,告訴 EEPROM,我不想要數(shù)據(jù)了,別再發(fā)數(shù)據(jù)了,那就發(fā)送一個“非應答位NAK(1)”。
和寫操作規(guī)則一樣,我們每讀一個字節(jié),地址會自動加 1,那如果我們想繼續(xù)往下讀,給EEPROM 一個 ACK(0)低電平,那再繼續(xù)給 SCL 完整的時序,EEPROM 會繼續(xù)往外送數(shù)據(jù)。如果我們不想讀了,要告訴 EEPROM 不要數(shù)據(jù)了,那我們直接給一個NAK(1)高電平即可。這個地方大家要從邏輯上理解透徹,不能簡單的靠死記硬背了,一定要理解明白。梳理一下幾個要點: A、在本例中單片機是主機,24C02 是從機; B、無論是讀是寫, SCL 始終都是由主機控制的; C、寫的時候應答信號由從機給出,表示從機是否正確接收了數(shù)據(jù); D、讀的時候應答信號則由主機給出,表示是否繼續(xù)讀下去。
#include
extern void I2CStart();
extern void I2CStop();
extern unsigned char I2CReadACK();
extern unsigned char I2CReadNAK();
extern bit I2CWrite(unsigned char dat);
/* E2讀取函數(shù),buf-數(shù)據(jù)接收指針,addr-E2中的起始地址,len-讀取長度 */
void E2Read(unsigned char *buf, unsigned char addr, unsigned char len)
{
do //用尋址操作查詢當前是否可進行讀寫操作
{
I2CStart();
if(I2CWrite(0x50 << 1)) //應答則跳出循環(huán),非應答則進行下一次查詢
{
break;
}
I2CStop();
}
while(1);
I2CWrite(addr); //寫入起始地址
I2CStart(); //發(fā)送重復啟動信號
I2CWrite((0x50 << 1) | 0x01); //尋址器件,后續(xù)為讀操作
while (len > 1) //連續(xù)讀取len-1個字節(jié)
{
*buf++ = I2CReadACK(); //最后字節(jié)之前為讀取操作+應答
len--;
}
*buf = I2CReadNAK(); //最后一個字節(jié)為讀取操作+非應答
I2CStop();
}
/* E2寫入函數(shù),buf-源數(shù)據(jù)指針,addr-E2中的起始地址,len-寫入長度 */
void E2Write(unsigned char *buf, unsigned char addr, unsigned char len)
{
while (len > 0)
{
//等待上次寫入操作完成
do //用尋址操作查詢當前是否可進行讀寫操作
{
I2CStart();
if(I2CWrite(0x50 << 1)) //應答則跳出循環(huán),非應答則進行下一次查詢
{
break;
}
I2CStop();
}
while(1);
//按頁寫模式連續(xù)寫入字節(jié)
I2CWrite(addr); //寫入起始地址
while(len > 0)
{
I2CWrite(*buf++); //寫入一個字節(jié)數(shù)據(jù)
len--; //待寫入長度計數(shù)遞減
addr++; //E2地址遞增
if ((addr & 0x07) == 0) //檢查地址是否到達頁邊界,24C02每頁8字節(jié),
{
//所以檢測低3位是否為零即可
break; //到達頁邊界時,跳出循環(huán),結(jié)束本次寫操作
}
}
I2CStop();
}
}