STC89C5x系列單片機(jī)內(nèi)部EEPROM
/********************************************************************************
*個(gè)人申明:*
*本人在運(yùn)用STC89C5x系列單片機(jī)內(nèi)部EEPROM時(shí),了解其對(duì)非0xff值的存儲(chǔ)空間*
*不能通過字節(jié)編程直接寫入。這一約定可能給一些人帶來應(yīng)用的麻煩,所以本*
*人決定編寫一能夠讓程序員不考慮這一約定的API。經(jīng)過幾個(gè)小時(shí)的編寫和調(diào)*
*試,基本能達(dá)到本人原本設(shè)想的目標(biāo)。由于時(shí)間倉促及個(gè)人水平有限,不免會(huì)*
*有些算法低效,還望高手指教。Email:chenguozhou1982@yahoo.com.cn。*
**
*本程序通過改幾個(gè)宏定義可以運(yùn)用到STC的很多型號(hào)MCU上,本人只測(cè)試了*
*STC89C5x系列*
*本程序可以任意修改和傳播,修改者請(qǐng)注明修改人、修改時(shí)間,傳播過程請(qǐng)注*
*明原著。不得用于任何商業(yè)目的。*
**
********************************************************************************
*FileName:EEPROM.C,V0.2.0*
*Author:GuozhouChen*
*Date:2007.09.15*
**
********************************************************************************
*使用數(shù)據(jù)類型說明:*
*UINT:16位無符號(hào)整形*
*BYTE:8位無符號(hào)字符型*
*BOOL:1位布爾類型*
**
********************************************************************************
*直接調(diào)用的API說明:*
**
*讀函數(shù)原形:UINTEEPROM_ReadBytes(UINTaddr,BYTE*buf,UINTsize)*
*函數(shù)返回為UINT類型的實(shí)際讀出數(shù)據(jù)字節(jié)數(shù)。*
*參數(shù)說明:addr為需要讀取EEPROM區(qū)域的第一字節(jié)地址,取值范圍為內(nèi)部*
*EEPROM除最后一扇區(qū)外的地址,因最后一扇區(qū)被犧牲做為緩存。*
*buf為目的數(shù)據(jù)區(qū)指針,即指向保存讀出數(shù)據(jù)區(qū)域的首地址。*
*size為要求讀出數(shù)據(jù)的字節(jié)數(shù)*
**
*寫函數(shù)原形:UINTEEPROM_WritBytes(UINTaddr,BYTE*buf,UINTsize)*
*函數(shù)返回為UINT類型的實(shí)際寫入數(shù)據(jù)字節(jié)數(shù)。*
*參數(shù)說明:addr為需要寫入EEPROM區(qū)域的第一字節(jié)地址,取值范圍為內(nèi)部*
*EEPROM除最后一扇區(qū)外的地址,因最后一扇區(qū)被犧牲做為緩存。*
*buf為源數(shù)據(jù)區(qū)指針,即指向需要寫入數(shù)據(jù)區(qū)域的首地址。*
*size為要求寫入數(shù)據(jù)的字節(jié)數(shù)*
**
********************************************************************************
*使用說明:*
*1、根據(jù)MCU和編譯器的實(shí)際情況修改幾個(gè)宏定義和數(shù)據(jù)類型定義。宏定義和數(shù)據(jù)類*
*型定義部分可以單獨(dú)寫成頭文件。*
*2、在需要使用EEPROM_ReadBytes()和EEPROM_WritBytes()函數(shù)的文件中做個(gè)*
*原形申明。*
*3、在需要的地方直接添入實(shí)參調(diào)用即可。*
**
********************************************************************************/
/********************************************************************************
**
*頭文件*
**
********************************************************************************/
#include"STC89C5x.h"
/********************************************************************************
**
*數(shù)據(jù)類型定義*
**
********************************************************************************/
typedefunsignedintUINT;
typedefunsignedcharBYTE;
typedefbitBOOL;
/********************************************************************************
**
*宏定義*
**
********************************************************************************/
#defineBYTES_EACH_SECTOR512//MCUEEPROM每扇區(qū)的字節(jié)數(shù)
//CPU等待時(shí)間,晶振0-5M設(shè)置為3,5-10M為2,10-20M為1,大于20M為0
#defineWAIT_TIME0
#defineUSEING_EACH_SECTOR512//計(jì)劃每扇區(qū)要用的字節(jié)數(shù),用量越小寫速度越快
#defineEEPROM_ADDR_START0x2000//EEPROM起始地址
#defineEEPROM_ADDR_END0x2fff//EEPROM結(jié)束地址
/********************************************************************************
**
*從指定首地址為addr的EEPROM區(qū)域讀出size字節(jié)數(shù)據(jù)到buf指向的區(qū)域內(nèi),并返回實(shí)際讀*
*出數(shù)據(jù)的字節(jié)數(shù)*
**
********************************************************************************/
UINTEEPROM_ReadBytes(UINTaddr,BYTE*buf,constUINTsize)
{
BOOLold_EA;
BYTE*p_buf;
UINTi,current_size;
p_buf=buf;
current_size=0;
ISP_CMD=0x01;
ISP_CONTR=0x80|WAIT_TIME;
for(i=0;i
//地址越界檢測(cè)
if((addr
{
break;
}
ISP_ADDRH=addr>>8;
ISP_ADDRL=addr&0x00ff;
old_EA=EA;
EA=0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
EA=old_EA;
*p_buf=ISP_DATA;
addr++;
p_buf++;
current_size++;
}
ISP_CMD=0x00;
ISP_CONTR=0x00;
returncurrent_size;
}
/********************************************************************************
**
*把buf指向單元內(nèi)的數(shù)據(jù)寫入地址為addr的EEPROM單元內(nèi),成功返回1,或則返回0*
**
********************************************************************************/
BOOLEEPROM_WritByte(UINTaddr,BYTE*buf)
{
BOOLold_EA;
if((addr
{
return0;
}
ISP_CMD=0x02;
ISP_CONTR=0x80|WAIT_TIME;
ISP_DATA=(*buf);
ISP_ADDRH=addr>>8;
ISP_ADDRL=addr&0x00ff;
old_EA=EA;
EA=0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
EA=old_EA;
ISP_CMD=0x00;
ISP_CONTR=0x00;
return1;
}
/********************************************************************************
**
*擦除AddrInSector地址所在的整個(gè)扇區(qū)*
**
********************************************************************************/
voidErasureAllSector(UINTAddrInSector)
{
BOOLold_EA;
ISP_CMD=0x03;
ISP_CONTR=0x80|WAIT_TIME;
ISP_ADDRH=AddrInSector>>8;
ISP_ADDRL=AddrInSector&0x00ff;
old_EA=EA;
EA=0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
EA=old_EA;
ISP_CMD=0x00;
ISP_CONTR=0x00;
}
/********************************************************************************
**
*從首地址為src扇區(qū)單元拷貝連續(xù)size字節(jié)數(shù)據(jù)到首地址為des的連續(xù)扇區(qū)單元內(nèi),并返*
*回實(shí)際拷貝的字節(jié)數(shù)*
**
********************************************************************************/
UINTCopySector(UINTsrc,UINTdes,constUINTsize)
{
BYTEtemp;
UINTcurrent_size,i;
current_size=0;
for(i=0;i
if(!EEPROM_ReadBytes(src,&temp,1))
{
break;
}
if(!EEPROM_WritByte(des,&temp))
{
break;
}
des++;
src++;
current_size++;
}
returncurrent_size;
}
/********************************************************************************
**
*把buf指向區(qū)域內(nèi)的size字節(jié)數(shù)據(jù)寫入首地址為addr的EEPROM連續(xù)區(qū)域,并返回實(shí)際寫入*
*數(shù)據(jù)的字節(jié)數(shù)*
**
********************************************************************************/
UINTEEPROM_WritBytes(UINTaddr,BYTE*buf,constUINTsize)
{
BYTE*p_buf,temp,move;
UINTi,bufaddr,current_size,cur_sector_start_addr;
p_buf=buf;
move=0;
current_size=0;
for(i=0;i
if(!EEPROM_ReadBytes(addr,&temp,1))
{
break;
}
if(temp==0xff)
{
EEPROM_WritByte(addr,p_buf);
}
//發(fā)現(xiàn)第一個(gè)單元不是0xff,要從新寫入數(shù)據(jù)需要做擦除整個(gè)扇區(qū)
else
{
//擦除用作緩沖的這個(gè)扇區(qū)
ErasureAllSector(EEPROM_ADDR_END);
cur_sector_start_addr=addr&0xfe00;
//把第一個(gè)非0xff單元前的數(shù)據(jù)拷貝到緩沖扇區(qū)
CopySector(cur_sector_start_addr
,(EEPROM_ADDR_END+1-BYTES_EACH_SECTOR)
,(addr-cur_sector_start_addr));
//計(jì)算剩余需要存儲(chǔ)的數(shù)據(jù)需寫入緩沖扇區(qū)的首個(gè)單元地址
bufaddr=(addr-cur_sector_start_addr)
+(EEPROM_ADDR_END+1-BYTES_EACH_SECTOR);
//把剩余要存儲(chǔ)的數(shù)據(jù)寫入緩沖扇區(qū)
for(;i
EEPROM_WritByte(bufaddr,p_buf);
addr++;
bufaddr++;
p_buf++;
current_size++;
}
//把需要改變區(qū)域后的數(shù)據(jù)寫入緩沖扇區(qū)
if(addr
CopySector(addr,bufaddr,USEING_EACH_SECTOR
-(addr-cur_sector_start_addr));
}
//擦除當(dāng)前扇區(qū)
ErasureAllSector(cur_sector_start_addr);
move=1;
break;
}
addr++;
p_buf++;
current_size++;
}
if(move)
{
//把緩沖扇區(qū)數(shù)據(jù)拷貝到當(dāng)前扇區(qū)
CopySector((EEPROM_ADDR_END-BYTES_EACH_SECTOR+1)
,cur_sector_start_addr,USEING_EACH_SECTOR);
}
returncurrent_size;
}
/*****************************Nothingbelowthisline***************************/
評(píng)論