單片機(jī)讀取EEPROM(AT24C02)
在 arm cortex-m3中 有專門的斷電保護(hù)寄存器(BKP寄存器) ,在主電源切斷或系統(tǒng)產(chǎn)生復(fù)位時間時,BKP寄存器仍然可以再備用電源的支持下保持其內(nèi)容。在實際應(yīng)用中可以存入重要數(shù)據(jù),防止被惡意查看,或用于斷電回復(fù)。參見stm32 BKP寄存器操作。
單片機(jī)掉電保護(hù)通常可采用以下三種方法:
一是加接不間斷電源,讓整個系統(tǒng)在掉電時繼續(xù)工作。
二是采用備份電源,掉電后保護(hù)系統(tǒng)中全部或部分?jǐn)?shù)據(jù)存儲單元的內(nèi)容;
三是采用EEPROM來保存數(shù)據(jù)。
由于第一種方法體積大、成本高,對單片機(jī)系統(tǒng)來說,不宜采用。第二種方法是根據(jù)實際需要,掉電時保存一些必要的數(shù)據(jù),使系統(tǒng)在電源恢復(fù)后,能夠繼續(xù)執(zhí)行程序。EEPROM既具有ROM掉電不丟失數(shù)據(jù)的特點,又有RAM隨機(jī)讀寫的特點。所以使用EEPROM AT24C02實現(xiàn)掉電保護(hù)是最可行的一種方式。
AT24C02是一種I2C總線結(jié)構(gòu)的芯片。
I2C總線協(xié)議如下:
只有在在總線空閑時才可以啟動數(shù)據(jù)發(fā)送。
在數(shù)據(jù)傳送過程中,當(dāng)時鐘線為高電平時,數(shù)據(jù)線上必須保持穩(wěn)定,不允許有跳變;時鐘線為高電平時,數(shù)據(jù)線的任何電平跳變都視為是總線起始或是結(jié)束信號。
起始信號:SCL 線是高電平時,SDA 線從高電平向低電平切換;
停止信號:SCL 線是高電平時,SDA 線由低電平向高電平切換;
發(fā)送起始信號后,可以以字節(jié)為單位發(fā)送數(shù)據(jù),每個字節(jié)必須為8位,高位在前,低位在后。主設(shè)備每個字節(jié)發(fā)送后,必須接收從設(shè)備的一個應(yīng)答信號ACK,即在第9個時鐘周期,接收SDA上的低電平。
主設(shè)備發(fā)送起始信號后,第一個發(fā)送的字節(jié)必須是器件地址碼,第二個字節(jié)為期間單元碼,用于實現(xiàn)選擇所操作的器件的內(nèi)部單元。第三個字節(jié)開始傳送數(shù)據(jù)。
器件地址碼格式如下:
其中前四位是器件的類型,有固定的定義,EPROM為1010;后三位為片選,同類器件可以接8個;R/W為讀寫控制,R/W=1為從總線讀取信息,R/W=0為從總線寫入信息。
I2C 讀指定單元時序:
開始信號 + 器件地址碼(R/W = 0 寫) + ACK(接收應(yīng)答信號)+待讀取單元地址+ACK+開始信號+器件地址碼(R/W = 1 讀) + ACK+讀取8位數(shù)據(jù)+停止信號
I2C 指定單元寫時序:
開始信號 + 器件地址碼(R/W = 0 寫) + ACK(接收應(yīng)答信號)+待寫入單元地址+ACK+寫入8位數(shù)據(jù)+ ACK+停止信號
讀寫時序時間控制:
單片機(jī)讀取EEPROM(AT24C02)代碼:
at24c02.c
#include#defineucharunsignedchar//宏定義uchar為無符號字符#defineuintunsignedint#defineADDRS_R0xA1//讀操作地址#defineADDRS_W0xA0//寫操作地址sbitI2C_SCL=P2^0;sbitI2C_SDL=P2^1;sbitI2C_ACK_Led=P2^7;//接收到正確的ACK相應(yīng)(低電平),則燈不亮(低電平亮)voidI2C_Delay(ucharn);voidI2C_Start();voidI2C_End();voidI2C_ACK();voidI2C_WriteByte(ucharvar);ucharI2C_ReadByte();ucharI2C_Read(ucharaddr);voidI2C_Write(ucharaddr,ucharvar);voidI2C_Delay(ucharn){while(--n);//2us一次}voidI2C_Start(){I2C_SCL=1;I2C_Delay(1);I2C_SDL=1;I2C_Delay(1);I2C_SDL=0;I2C_Delay(1);I2C_SCL=0;//每次執(zhí)行完讀寫操作后都,拉低SCL,防止時序混亂I2C_Delay(1);}voidI2C_End(){I2C_SCL=0;I2C_Delay(1);I2C_SDL=0;I2C_Delay(1);I2C_SCL=1;I2C_Delay(1);I2C_SDL=1;I2C_Delay(1);}voidI2C_ACK()//EEPROM字節(jié)寫入相應(yīng),低電平正確{I2C_SCL=0;I2C_Delay(1);I2C_SCL=1;I2C_Delay(1);while(I2C_SDL==1){I2C_ACK_Led=0;}I2C_ACK_Led=1;I2C_SCL=0;I2C_Delay(1);}voidI2C_WriteByte(ucharvar)//單字節(jié)寫入函數(shù){uchari;for(i=0;i<8;i++){I2C_SCL=0;I2C_Delay(1);if(var&0x80)I2C_SDL=1;elseI2C_SDL=0;I2C_Delay(1);I2C_SCL=1;I2C_Delay(1);var<<=1;}I2C_SCL=0;I2C_Delay(1);}ucharI2C_ReadByte()//單字節(jié)讀取函數(shù){ucharvar,i;for(i=0;i<8;i++){var<<=1;I2C_SCL=0;I2C_Delay(1);I2C_SCL=1;I2C_Delay(1);if(I2C_SDL==1)var|=0x01;I2C_Delay(1);}I2C_SCL=0;I2C_Delay(1);returnvar;}voidI2C_Write(ucharaddr,ucharvar)//EEPROM單元寫入函數(shù){I2C_Start();I2C_WriteByte(ADDRS_W);I2C_ACK();I2C_WriteByte(addr);I2C_ACK();I2C_WriteByte(var);I2C_ACK();I2C_End();}ucharI2C_Read(ucharaddr)//EEPROM單元讀取函數(shù){ucharvar;I2C_Start();I2C_WriteByte(ADDRS_W);I2C_ACK();I2C_WriteByte(addr);I2C_ACK();I2C_Start();I2C_WriteByte(ADDRS_R);I2C_ACK();var=I2C_ReadByte();I2C_End();returnvar;}
在程序中調(diào)用讀寫函數(shù)即可,程序調(diào)試使用的是11.0592Mhz的晶振。