//============================================================================
//prjname:STC89C51RC,STC89C52RC,STC89C54RD+EEPROM例程
//funtion:程序实现P0口,P1口分别驱动LED灯(低电平亮)把两个8位变量count.dat,temp.dat
//显示出来,这两个个八位约1s自增一次,且变量的值能够掉电保护
//author:viviFire
//说明:STC89C51RC,STC89C52RC的EEPROM的第一扇区起始地址为0x2000
//STC89C54RD+的EEPROM的第一扇区起始地址为0x8000,需修改本程序
//其他芯片请参考手册
//运用本程序请注明出自viviFire,
//本程序参考宏晶公司提供的STC5Axx系列EEPROM例子程序
//============================================================================
#include
#include
typedefunsignedcharINT8U;
typedefunsignedintINT16U;
sfrIAP_DATA=0xE2;
sfrIAP_ADDRH=0xE3;
sfrIAP_ADDRL=0xE4;
sfrIAP_CMD=0xE5;
sfrIAP_TRIG=0xE6;
sfrIAP_CONTR=0xE7;
//定义Flash操作等待时间及允许IAP/ISP/EEPROM操作的常数
//#defineENABLE_ISP0x80//系统工作时钟<5MHz时,对IAP_CONTR寄存器设置此值
//#defineENABLE_ISP0x81//系统工作时钟<10MHz时,对IAP_CONTR寄存器设置此值
#defineENABLE_ISP0x82//系统工作时钟<20MHz时,对IAP_CONTR寄存器设置此值
//#defineENABLE_ISP0x83//系统工作时钟<40MHz时,对IAP_CONTR寄存器设置此值
#defineDATA_FLASH_START_ADDRESS0x2000//STC89C51,STC89C52系列EEPROM测试起始地址
//------------------------------------------------------------------------------------------
INT8UByte_Read(INT16Uadd);//读一字节,调用前需打开IAP功能
voidByte_Program(INT16Uadd,INT8Uch);//字节编程,调用前需打开IAP功能
voidSector_Erase(INT16Uadd);//擦除扇区
voidIAP_Disable();//关闭IAP功能
voiddelayms(INT16Uz);
voidEEPROM_Init();
//------------------------------------------------------------------------------
structEEP_dat
{
INT16Uadd;
INT8Udat;
}count,temp;
//------------------------------------------------------------------------------
voidmain()
{
EEPROM_Init();
while(1)
{
P0=~count.dat;
P1=~temp.dat;
delayms(1000);
count.dat++;
temp.dat++;
Sector_Erase(DATA_FLASH_START_ADDRESS);
Byte_Program(count.add,count.dat);
Byte_Program(temp.add,temp.dat);
}
}//-----------------------------------------------------------------------------
voidEEPROM_Init()
{
count.add=0x2000;//把EEPROM变量的地址现在这里定义好
count.dat=Byte_Read(count.add);
temp.add=0x2001;//把EEPROM变量的地址现在这里定义好
temp.dat=Byte_Read(temp.add);
}//-----------------------------------------------------------------------------
//读一字节,调用前需打开IAP功能,入口:DPTR=字节地址,返回:A=读出字节
INT8UByte_Read(INT16Uadd)
{
IAP_DATA=0x00;
IAP_CONTR=ENABLE_ISP;//打开IAP功能,设置Flash操作等待时间
IAP_CMD=0x01;//IAP/ISP/EEPROM字节读命令
IAP_ADDRH=(INT8U)(add>>8);//设置目标单元地址的高8位地址
IAP_ADDRL=(INT8U)(add&0xff);//设置目标单元地址的低8位地址
EA=0;
IAP_TRIG=0x46;//先送46h,再送B9h到ISP/IAP触发寄存器,每次都需如此
IAP_TRIG=0xB9;//送完B9h后,ISP/IAP命令立即被触发起动
_nop_();
EA=1;
IAP_Disable();//关闭IAP功能,清相关的特殊功能寄存器,使CPU处于安全状态,
//一次连续的IAP操作完成之后建议关闭IAP功能,不需要每次都关
return(IAP_DATA);
}//------------------------------------------------------------------------------
//字节编程,调用前需打开IAP功能,入口:DPTR=字节地址,A=须编程字节的数据
voidByte_Program(INT16Uadd,INT8Uch)
{
IAP_CONTR=ENABLE_ISP;//打开IAP功能,设置Flash操作等待时间
IAP_CMD=0x02;//IAP/ISP/EEPROM字节编程命令
IAP_ADDRH=(INT8U)(add>>8);//设置目标单元地址的高8位地址
IAP_ADDRL=(INT8U)(add&0xff);//设置目标单元地址的低8位地址
IAP_DATA=ch;//要编程的数据先送进IAP_DATA寄存器
EA=0;
IAP_TRIG=0x46;//先送46h,再送B9h到ISP/IAP触发寄存器,每次都需如此
IAP_TRIG=0xB9;//送完B9h后,ISP/IAP命令立即被触发起动
_nop_();
EA=1;
IAP_Disable();//关闭IAP功能,清相关的特殊功能寄存器,使CPU处于安全状态,
//一次连续的IAP操作完成之后建议关闭IAP功能,不需要每次都关
}//------------------------------------------------------------------------------
//擦除扇区,入口:DPTR=扇区地址
voidSector_Erase(INT16Uadd)
{
IAP_CONTR=ENABLE_ISP;//打开IAP功能,设置Flash操作等待时间
IAP_CMD=0x03;//IAP/ISP/EEPROM扇区擦除命令
IAP_ADDRH=(INT8U)(add>>8);//设置目标单元地址的高8位地址
IAP_ADDRL=(INT8U)(add&0xff);//设置目标单元地址的低8位地址
EA=0;
IAP_TRIG=0x46;//先送46h,再送B9h到ISP/IAP触发寄存器,每次都需如此
IAP_TRIG=0xB9;//送完B9h后,ISP/IAP命令立即被触发起动
_nop_();
EA=1;
IAP_Disable();//关闭IAP功能,清相关的特殊功能寄存器,使CPU处于安全状态,
//一次连续的IAP操作完成之后建议关闭IAP功能,不需要每次都关
}//------------------------------------------------------------------------------
voidIAP_Disable()
{
//关闭IAP功能,清相关的特殊功能寄存器,使CPU处于安全状态,
//一次连续的IAP操作完成之后建议关闭IAP功能,不需要每次都关
IAP_CONTR=0;//关闭IAP功能
IAP_CMD=0;//清命令寄存器,使命令寄存器无命令,此句可不用
IAP_TRIG=0;//清命令触发寄存器,使命令触发寄存器无触发,此句可不用
IAP_ADDRH=0;
IAP_ADDRL=0;
}//------------------------------------------------------------------------------
voiddelayms(INT16Uz)
{
INT16Ux,y;
for(x=z;x>0;x--)
for(y=125;y>0;y--);
}//-------------------------------------------------------------------------------