STC單片機內部EEPROM的應用
STC各型號單片機內置的EEPROM的容量各有不同,見(jiàn)下表:
本文引用地址:http://dyxdggzs.com/article/201611/316202.htm單片機芯片型號 | 起始地址 | 內置EEPROM容量(每扇區512字節) |
STC89C51RC,STC89LE51RC | 0x2000 | 共八個(gè)扇區 |
STC89C52RC,STC89LE52RC | 0x2000 | 共八個(gè)扇區 |
STC89C54RD+,STC89LE54RD+ | 0x8000 | 共五十八個(gè)扇區 |
STC89C55RD+,STC89LE55RD+ | 0x8000 | 共五十八個(gè)扇區 |
STC89C58RD+,STC89LE58RD+ | 0x8000 | 共五十八個(gè)扇區 |
(內部EEPROM可以擦寫(xiě)100000次以上)
上面提到了IAP,它的意思是“在應用編程”,即在程序運行時(shí)程序存儲器可由程序自身進(jìn)行擦寫(xiě)。正是是因為有了IAP,從而可以使單片機可以將數據寫(xiě)入到程序存儲器中,使得數據如同燒入的程序一樣,掉電不丟失。當然寫(xiě)入數據的區域與程序存儲區要分開(kāi)來(lái),以使程序不會(huì )遭到破壞。
要使用IAP功能,與以下幾個(gè)特殊功能寄存器相關(guān):
寄存器標識 | 地址 | 名稱(chēng) | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 初始值 |
ISP_DATA | 0xE2 | ISP/IAP閃存數據寄存器 | 11111111 | ||||||||
ISP_ADDRH | 0xE3 | ISP/IAP閃存地址高位 | 00000000 | ||||||||
ISP_ADDRL | 0xE4 | ISP/IAP閃存地址低位 | 00000000 | ||||||||
ISP_CMD | 0xE5 | ISP/IAP閃存命令寄存器 | - | - | - | - | - | MS2 | MS1 | MS0 | xxxxx000 |
ISP_TRIG | 0xE6 | ISP/IAP閃存命令觸發(fā) | xxxxxxxx | ||||||||
ISP_CONTR | 0xE7 | ISP/IAP控制寄存器 | ISPEN | SWBS | SWRST | - | - | WT2 | WT1 | WT0 | 00xx000 |
ISP_DATA: ISP/IAP操作時(shí)的數據寄存器。
ISP/IAP從Flash讀出的數據放在此處,向Flash寫(xiě)的數據也需放在此處
ISP_ADDRH:ISP/IAP操作時(shí)的地址寄存器高八位。
ISP_ADDRL:ISP/IAP操作時(shí)的地址寄存器低八位。
ISP_CMD: ISP/IAP操作時(shí)的命令模式寄存器,須命令觸發(fā)寄存器觸發(fā)方可生效。
B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | 命令/操作模式選擇 |
保留 | 命令選擇 | |||||||
- | - | - | - | - | 0 | 0 | 0 | 待機模式,無(wú)ISP/IAP操作 |
- | - | - | - | - | 0 | 0 | 1 | 對用戶(hù)的應用程序Flash區及數據Flash區字節讀 |
- | - | - | - | - | 0 | 1 | 0 | 對用戶(hù)的應用程序Flash區及數據Flash區字節編程 |
- | - | - | - | - | 0 | 1 | 1 | 對用戶(hù)的應用程序Flash區及數據Flash區扇區擦除 |
ISP_TRIG:ISP/IAP操作時(shí)的命令觸發(fā)寄存器。
當ISPEN(ISP_CONTR.7)=1時(shí),對ISP_TRIG先寫(xiě)入0x46,再寫(xiě)入0xb9,ISP/IAP命令才會(huì )生效。
ISP_CONTR:ISP/IAP控制寄存器。
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
ISPEN | SWBS | SWRST | - | - | WT2 | WT1 | WT0 |
ISPEN:ISP/IAP功能允許位。0:禁止ISP/IAP編程改變Flash,1:允許編程改變Flash
SWBS:軟件選擇從用戶(hù)主程序區啟動(dòng)(0),還是從ISP程序區啟動(dòng)(1)。
SWRST:0:不操作,1:產(chǎn)生軟件系統復位,硬件自動(dòng)清零。
ISP_CONTR中的SWBS與SWRST這兩個(gè)功能位,可以實(shí)現單片機的軟件啟動(dòng),并啟動(dòng)到ISP區或用戶(hù)程序區,這在“STC單片機自動(dòng)下載”一節,亦有所應用。
如:
ISP_CONTR=0x60; 則可以實(shí)現從用戶(hù)應用程序區軟件復位到ISP程序區開(kāi)始運行程序。
ISP_CONTR=0x20; 則可以實(shí)現從ISP程序區軟件復位到用戶(hù)應用程序區開(kāi)始運行程序。
用IAP向Flash中讀寫(xiě)數據,是需要一定的讀寫(xiě)時(shí)間的,讀寫(xiě)數據命令發(fā)出后,要等待一段時(shí)間才可以讀寫(xiě)成功。這個(gè)等待時(shí)間就是由WT2、WT1、WT0與晶體振蕩器頻率決定的。
設置等待時(shí)間 | CPU等待時(shí)間(機器周期) | |||||
WT2 | WT1 | WT0 | 讀取 | 編程 | 扇區擦除 | 建議的系統時(shí)鐘 |
0 | 1 | 1 | 6 | 30 | 5471 | 5MHz |
0 | 1 | 0 | 11 | 60 | 10942 | 10MHz |
0 | 0 | 1 | 22 | 120 | 21885 | 20MHz |
0 | 0 | 0 | 43 | 240 | 43769 | 40MHz |
(以上的建議時(shí)鐘是(WT2、WT1、WT0)取不同的值時(shí)的標稱(chēng)時(shí)鐘,用戶(hù)系統中的時(shí)鐘不要過(guò)高,否則可能使操作不穩定。)
以下是具體的實(shí)現代碼:
EEPROM操作函數:
#define RdCommand 0x01
#define PrgCommand 0x02
#define EraseCommand 0x03
#define Error 1
#define Ok 0
#define WaitTime 0x01
#define PerSector 512
unsignedchar xdata Ttotal[512];
/*
---------------------------------------------------------------------
打開(kāi) ISP,IAP功能
---------------------------------------------------------------------
*/
voidISP_IAP_enable(void)
{
EA=0;/*關(guān)中斷*/
ISP_CONTR|=0x18;/*0001,1000*/
ISP_CONTR|=WaitTime;/*寫(xiě)入硬件延時(shí)*/
ISP_CONTR|=0x80;/*ISPEN=1*/
}
/*
---------------------------------------------------------------------
關(guān)閉 ISP,IAP功能
---------------------------------------------------------------------
*/
voidISP_IAP_disable(void)
{
ISP_CONTR&=0x7f;/* ISPEN = 0 */
ISP_TRIG=0x00;
EA=1;/*開(kāi)中斷 */
}
/*
----------------------------------------------------------------------
公用的觸發(fā)代碼
----------------------------------------------------------------------
*/
voidISPgoon(void)
{
ISP_IAP_enable();/*打開(kāi) ISP,IAP功能 */
ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節1 */
ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節2 */
_nop_();
}
/*
-----------------------------------------------------------------------
字節讀
-----------------------------------------------------------------------
*/
unsignedchar byte_read(unsigned int byte_addr)
{
ISP_ADDRH=(unsigned char)(byte_addr>>8); /*地址賦值*/
ISP_ADDRL=(unsigned char)(byte_addr&0x00ff);
ISP_CMD&=0xf8; /*清除低3位 */
ISP_CMD|=RdCommand;/*寫(xiě)入讀命令*/
ISPgoon();/*觸發(fā)執行*/
ISP_IAP_disable();/*關(guān)閉ISP,IAP功能*/
return ISP_DATA;/*返回讀到的數據*/
}
/*
------------------------------------------------------------------------
扇區擦除
------------------------------------------------------------------------
*/
voidsectorerase(unsigned int sector_addr)
{
unsigned int iSectorAddr;
iSectorAddr=(sector_addr&0xfe00);/*取扇區地址*/
ISP_ADDRH=(unsigned char)(iSectorAddr>>8);
ISP_ADDRL=0x00;
ISP_CMD&=0xf8;/*清空低3位*/
ISP_CMD|=EraseCommand;/*擦除命令3*/
ISPgoon();/*觸發(fā)執行 */
ISP_IAP_disable();/*關(guān)閉ISP,IAP功能*/
}
/*
-------------------------------------------------------------------------------------
字節寫(xiě)
-------------------------------------------------------------------------------------
*/
voidbyte_write(unsigned int byte_addr, unsigned char original_data)
{
ISP_ADDRH=(unsigned char)(byte_addr>>8); /*取地址*/
ISP_ADDRL=(unsigned char)(byte_addr & 0x00ff);
ISP_CMD&=0xf8;/*清低3位*/
ISP_CMD|=PrgCommand;/*寫(xiě)命令2*/
ISP_DATA=original_data;/*寫(xiě)入數據準備*/
ISPgoon();/*觸發(fā)執行*/
ISP_IAP_disable();/*關(guān)閉IAP功能*/
}
/*
-----------------------------------------------------------------
字節寫(xiě)并校驗
-----------------------------------------------------------------
*/
unsignedchar byte_write_verify(unsigned int byte_addr, unsigned char original_data)
{
ISP_ADDRH=(unsigned char)(byte_addr>>8); /*取地址*/
ISP_ADDRL=(unsigned char)(byte_addr&0xff);
ISP_CMD&=0xf8;/*清低3位*/
ISP_CMD|=PrgCommand;/*寫(xiě)命令2*/
ISP_DATA=original_data;
ISPgoon();/*觸發(fā)執行*/
/*開(kāi)始讀,沒(méi)有在此重復給地址,地址不會(huì )被自動(dòng)改變*/
ISP_DATA=0x00;/*清數據傳遞寄存器*/
ISP_CMD&=0xf8;/*清低3位*/
ISP_CMD|=RdCommand;/*讀命令1*/
ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節1 */
ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節2 */
_nop_();/*延時(shí)*/
ISP_IAP_disable();/*關(guān)閉IAP功能*/
if(ISP_DATA==original_data)/*讀寫(xiě)數據校驗*/
return Ok;/*返回校驗結果*/
else
return Error;
}
/*
--------------------------------------------------------------------------
數組寫(xiě)入
--------------------------------------------------------------------------
*/
unsignedchar arraywrite(unsigned int begin_addr, unsigned int len, unsigned char *array)
{
unsigned int i;
unsigned int in_addr;
/*判是否是有效范圍,此函數不允許跨扇區操作 */
if(len > PerSector)
return Error;
in_addr = begin_addr & 0x01ff;/*扇區內偏移量 */
if((in_addr+len)>PerSector)
return Error;
in_addr = begin_addr;
/*逐個(gè)寫(xiě)入并校對 */
ISP_IAP_enable();/*打開(kāi)IAP功能 */
for(i=0;i { /*寫(xiě)一個(gè)字節 */ ISP_ADDRH=(unsigned char)(in_addr >> 8); ISP_ADDRL=(unsigned char)(in_addr & 0x00ff); ISP_DATA=array[i]; /*取數據 */ ISP_CMD&=0xf8;/*清低3位 */ ISP_CMD|=PrgCommand;/*寫(xiě)命令2 */ ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節1 */ ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節2 */ _nop_(); /*讀回來(lái) */ ISP_DATA=0x00; ISP_CMD&=0xf8;/*清低3位*/ ISP_CMD|=RdCommand;/*讀命令1*/ ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節1 */ ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節2 */ _nop_(); /*比較對錯 */ if(ISP_DATA!=array[i]) { ISP_IAP_disable(); return Error; } in_addr++;/*指向下一個(gè)字節*/ } ISP_IAP_disable(); return Ok; } /* ----------------------------------------------------------------------------- 扇區讀出 ----------------------------------------------------------------------------- */ /*程序對地址沒(méi)有作有效性判斷,請調用前事先保證他在規定范圍內 */ voidarrayread(unsigned int begin_addr, unsigned char len) { unsigned int iSectorAddr; unsigned int i; iSectorAddr = begin_addr; // & 0xfe00; /*取扇區地址*/ ISP_IAP_enable(); for(i=0;i { ISP_ADDRH=(unsigned char)(iSectorAddr>>8); ISP_ADDRL=(unsigned char)(iSectorAddr & 0x00ff); ISP_CMD&=0xf8;/*清低3位*/ ISP_CMD|=RdCommand;/*讀命令1*/ ISP_DATA=0; ISP_TRIG=0x46;/*觸發(fā)ISP_IAP命令字節1 */ ISP_TRIG=0xb9;/*觸發(fā)ISP_IAP命令字節2 */ _nop_(); Ttotal[i]=ISP_DATA; iSectorAddr++; } ISP_IAP_disable();/*關(guān)閉IAP功能*/ } 主函數對EEPROM操作函數進(jìn)行調用: #include #include #include #include inti; voiddelay(unsigned int time) { while(time--); } voidmain() { _ADOS(22.1184); //ADOS自動(dòng)下載 //for(i=0;i<100;i++) //{ //Ttotal[i]=i; //} //arraywrite(0x8000,100,Ttotal); /* 第一次運行時(shí)向EEPROM中寫(xiě)入數據 然后再將寫(xiě)入函數注釋掉,將先前寫(xiě) 入的數據讀出,輸出在P2口上。 */ arrayread(0x8000,100); for(i=0;i<100;i++) { P2=~Ttotal[i]; delay(10000); } while(1); }
評論