51单片机读写内部EEPROM详解.docx
《51单片机读写内部EEPROM详解.docx》由会员分享,可在线阅读,更多相关《51单片机读写内部EEPROM详解.docx(31页珍藏版)》请在冰豆网上搜索。
51单片机读写内部EEPROM详解
此文档共包含三个程序。
第一个程序最简单易懂,看懂了基本就会读写51单片机内部EEPROM了。
第二个程序和第一个读写EEPROM原理差不多,包含有LCD1602操作方法,有写字符串的方法。
第三个程序在原有基础上增加了外部中断功能,细心的人会发现,操作内部EEPROM过程会将总中断关闭,实际上程序要用到中断时只需在原有的EEPROM操作后加上开总中断即可。
验证第二、第三个程序时需按程序内主程序中的操作说明进行烧录单片机,以验证是否成功操作单片机内部EEPROM。
程序1:
/***************************************************************
作品:
EEPROM实验,开机还原关电前LED的亮灭状况
单片机:
STC89C52RC
晶振:
12M
编译环境:
KeiluVision4V9.00
***************************************************************/
//#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
/****************特殊功能寄存器声明****************/
sfrISP_DATA=0xe2;
sfrISP_ADDRH=0xe3;
sfrISP_ADDRL=0xe4;
sfrISP_CMD=0xe5;
sfrISP_TRIG=0xe6;
sfrISP_CONTR=0xe7;
sbitLED1=P2^0;
sbitLED2=P2^1;
sbitK1=P3^2;//按钮1
sbitK2=P3^3;//按钮2
voidcc(uintaddr);
voidxcx(uintaddr,uchardat);
uchardcx(uintaddr);
voidQ0();
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
主程序
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
/*
voidmain(void)
{
ucharV;
V=dcx(0x2002);//开机读取EEPROM区2002h数据,还原关电前LED的亮灭状况
if(V==2){LED1=0;LED2=1;}
elseif(V==6){LED1=0;LED2=0;}
while
(1)
{
if(!
K1)
{
while(!
K1);
LED1=0;LED2=1;
cc(0x2000);//擦除第1个扇区(2000h~21FFh)
xcx(0x2002,2);//对EEPROM区2002h写入2
}
if(!
K2)
{
while(!
K2);
LED1=0;LED2=0;
cc(0x2000);//擦除第1个扇区(2000h~21FFh)
xcx(0x2002,6);//对EEPROM区2002h写入6
}
}
}
*/
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
擦除某一扇区(每个扇区512字节)
入口:
addr=某一扇区首地址
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
voidcc(uintaddr)
{
//打开IAP功能(ISP_CONTR.7)=1:
允许编程改变Flash,设置Flash操作等待时间
//0x83(晶振<5M)0x82(晶振<10M)0x81(晶振<20M)0x80(晶振<40M)
ISP_CONTR=0x81;
ISP_CMD=0x03;//用户可以对"DataFlash/EEPROM区"进行扇区擦除
ISP_ADDRL=addr;//ISP/IAP操作时的地址寄存器低八位,
ISP_ADDRH=addr>>8;//ISP/IAP操作时的地址寄存器高八位。
EA=0;
ISP_TRIG=0x46;//在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,
ISP_TRIG=0xB9;//再写入B9h,ISP/IAP命令才会生效。
_nop_();
Q0();//关闭ISP/IAP
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
写一字节
入口:
addr=扇区单元地址,dat=待写入数据
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
voidxcx(uintaddr,uchardat)
{
ISP_CONTR=0x81;
ISP_CMD=0x02;//用户可以对"DataFlash/EEPROM区"进行字节编程
ISP_ADDRL=addr;
ISP_ADDRH=addr>>8;
ISP_DATA=dat;//数据进ISP_DATA
EA=0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
Q0();//关闭ISP/IAP
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
读一字节
入口:
addr=扇区单元地址
出口:
dat=读出的数据
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
uchardcx(uintaddr)
{
uchardat;
ISP_CONTR=0x81;
ISP_CMD=0x01;//用户可以对"DataFlash/EEPROM区"进行字节读
ISP_ADDRL=addr;
ISP_ADDRH=addr>>8;
EA=0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
dat=ISP_DATA;//取出数据
Q0();//关闭ISP/IAP
returndat;
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
关闭ISP/IAP操作
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
voidQ0()
{
ISP_CONTR=0;//关闭IAP功能
ISP_CMD=0;//待机模式,无ISP操作
ISP_TRIG=0;//关闭IAP功能,清与ISP有关的特殊功能寄存器
}
/*
STC89C52RC内部EEPROM详细地址表:
第一扇区第二扇区第三扇区第四扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2000h21FFh2200h23FFh2400h25FFh2600h27FFH
第五扇区第六扇区第七扇区第八扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2800h29FFh2A00h2BFFh2C00h2DFFh2E00h2FFFh
*/
程序2:
/***************************************************************
作品:
EEPROM实验,开机还原关电前LED的亮灭状况
单片机:
STC89C52RC
晶振:
12M
编译环境:
KeiluVision4V9.00
***************************************************************/
//#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
/****************特殊功能寄存器声明****************/
sfrISP_DATA=0xe2;
sfrISP_ADDRH=0xe3;
sfrISP_ADDRL=0xe4;
sfrISP_CMD=0xe5;
sfrISP_TRIG=0xe6;
sfrISP_CONTR=0xe7;
sbitLED1=P2^0;
sbitLED2=P2^1;
sbitK1=P3^2;//按钮1
sbitK2=P3^3;//按钮2
voidcc(uintaddr);
voidxcx(uintaddr,uchardat);
uchardcx(uintaddr);
voidQ0();
#ifndefuchar
#defineucharunsignedchar
#endif
#ifndefuint
#defineuintunsignedint
#endif
/**********************************
PIN口定义
**********************************/
#defineLCD1602_DATAPINSP0
sbitLCD1602_E=P2^7;
sbitLCD1602_RW=P2^5;
sbitLCD1602_RS=P2^6;
/**********************************
函数声明
**********************************/
/*在51单片机12MHZ时钟下的延时函数*/
voidLcd1602_Delay1ms(uintc);//误差0us
/*LCD1602写入8位命令子函数*/
voidLcdWriteCom(ucharcom);
/*LCD1602写入8位数据子函数*/
voidLcdWriteData(uchardat);
/*LCD1602初始化子程序*/
voidLcdInit();
/*LCD1602写入字符串*/
voidLCDWrite_String(ucharx,uchary,ucharz,uchar*s);
/*设置LCD1602写入字符串的位置*/
voidLCD_set_xy(ucharx,uchary,ucharz);
ucharON_Hour=0x07;//初始开灯时间07:
001
ucharWarning_TempH=32;//高温报警温度5
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
主程序
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
/*
voidmain(void)
{
ucharV;
V=dcx(0x2002);//开机读取EEPROM区2002h数据,还原关电前LED的亮灭状况
if(V==2){LED1=0;LED2=1;}
elseif(V==6){LED1=0;LED2=0;}
while
(1)
{
if(!
K1)
{
while(!
K1);
LED1=0;LED2=1;
cc(0x2000);//擦除第1个扇区(2000h~21FFh)
xcx(0x2002,2);//对EEPROM区2002h写入2
}
if(!
K2)
{
while(!
K2);
LED1=0;LED2=0;
cc(0x2000);//擦除第1个扇区(2000h~21FFh)
xcx(0x2002,6);//对EEPROM区2002h写入6
}
}
}
*/
voidmain(void)
{
LcdInit();
//不注销下面三句,烧录一次
//注销小面三句,再烧录一次
//若两次烧录后现象一致,则操作内部EEPROM成功
/////////////////////////////////////////////////////////////////
cc(0x2000);//擦除第1个扇区(2000h~21FFh)
xcx(0x2000,ON_Hour);//对EEPROM区2002h写入2
xcx(0x2001,Warning_TempH);//对EEPROM区2002h写入2
/////////////////////////////////////////////////////////////////
ON_Hour=dcx(0x2000);
Warning_TempH=dcx(0x2001);
if((ON_Hour==0x07)||(Warning_TempH==32))
{
LcdWriteCom(0x80);
LCDWrite_String(0,1,7,"SUCCESS");
}
else
LCDWrite_String(0,1,5,"ERROR");
while
(1);
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
擦除某一扇区(每个扇区512字节)
入口:
addr=某一扇区首地址
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
voidcc(uintaddr)
{
//打开IAP功能(ISP_CONTR.7)=1:
允许编程改变Flash,设置Flash操作等待时间
//0x83(晶振<5M)0x82(晶振<10M)0x81(晶振<20M)0x80(晶振<40M)
ISP_CONTR=0x81;
ISP_CMD=0x03;//用户可以对"DataFlash/EEPROM区"进行扇区擦除
ISP_ADDRL=addr;//ISP/IAP操作时的地址寄存器低八位,
ISP_ADDRH=addr>>8;//ISP/IAP操作时的地址寄存器高八位。
EA=0;
ISP_TRIG=0x46;//在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,
ISP_TRIG=0xB9;//再写入B9h,ISP/IAP命令才会生效。
_nop_();
Q0();//关闭ISP/IAP
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
写一字节
入口:
addr=扇区单元地址,dat=待写入数据
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
voidxcx(uintaddr,uchardat)
{
ISP_CONTR=0x81;
ISP_CMD=0x02;//用户可以对"DataFlash/EEPROM区"进行字节编程
ISP_ADDRL=addr;
ISP_ADDRH=addr>>8;
ISP_DATA=dat;//数据进ISP_DATA
EA=0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
Q0();//关闭ISP/IAP
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
读一字节
入口:
addr=扇区单元地址
出口:
dat=读出的数据
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
uchardcx(uintaddr)
{
uchardat;
ISP_CONTR=0x81;
ISP_CMD=0x01;//用户可以对"DataFlash/EEPROM区"进行字节读
ISP_ADDRL=addr;
ISP_ADDRH=addr>>8;
EA=0;
ISP_TRIG=0x46;
ISP_TRIG=0xB9;
_nop_();
dat=ISP_DATA;//取出数据
Q0();//关闭ISP/IAP
returndat;
}
/*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
函数:
关闭ISP/IAP操作
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
voidQ0()
{
ISP_CONTR=0;//关闭IAP功能
ISP_CMD=0;//待机模式,无ISP操作
ISP_TRIG=0;//关闭IAP功能,清与ISP有关的特殊功能寄存器
}
/*
STC89C52RC内部EEPROM详细地址表:
第一扇区第二扇区第三扇区第四扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2000h21FFh2200h23FFh2400h25FFh2600h27FFH
第五扇区第六扇区第七扇区第八扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2800h29FFh2A00h2BFFh2C00h2DFFh2E00h2FFFh
*/
/*******************************************************************************
*函数名:
Lcd1602_Delay1ms
*函数功能:
延时函数,延时1ms
*输入:
c
*输出:
无
*说名:
该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/
voidLcd1602_Delay1ms(uintc)//误差0us
{
uchara,b;
for(;c>0;c--)
{
for(b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/*******************************************************************************
*函数名:
voidLCDWrite_String(ucharx,uchary,uchar*s)
*函数功能:
向LCD写入一个字符串
*输入:
x,y,*s
*输出:
无
*******************************************************************************/
voidLCDWrite_String(ucharx,uchary,ucharz,uchar*s)//x0~15,y0,1,2,3
{
LCD_set_xy(x,y,z);
while(*s)
{
LcdWriteData(*s);
s++;
}
}
/*******************************************************************************
*函数名:
voidLCD_set_xy(ucharx,uchary,ucharz)
*函数功能:
指定向LCD写入字符串的位置
*输入:
x,y,z//x:
横坐标y:
纵坐标z:
字符串长度
*输出:
无
*******************************************************************************/
voidLCD_set_xy(ucharx,uchary,ucharz)
{
uchari;
if(y==0)
{
LcdWriteCom(0x80+x);
for(i=0;i{
LcdWriteData('');
}
LcdWriteCom(0x80+x);
}
if(y==1)
{
LcdWriteCom(0xc0+x);
for(i=0;i{
LcdWriteData('');
}
LcdWriteCom(0xc0+x);
}
if(y==2)
{
LcdWriteCom(0x94+x);
for(i=0;i{
LcdWriteData('');
}
LcdWriteCom(0x94+x);
}
if(y==3)
{
LcdWriteCom(0xd4+x);
for(i=0;i{
LcdWriteData('');
}
LcdWriteCom(0xd4+x);
}
}
/*******************************************************************************
*函数名:
LcdWriteCom
*函数功能:
向LCD写入一个字节的命令
*输入:
com
*输出:
无
*******************************************************************************/
#ifndefLCD1602_4PINS//当没有定义这个LCD1602_4PINS时
voidLcdWriteCom(ucharcom)//写入命令
{
LCD1602_E=0;//使能
LCD1602_RS=0;//选择发送命令
LCD1602_RW=0;//选择写入
LCD1602_DATAPINS=com;//放入命令
Lcd1602_Delay1ms
(1);//等待数据稳定
LCD1602_E=1;//写入时序
Lcd1602_Delay1ms(5);//保持时间
LCD1602_E=0;
}
#else
voidLcdWriteCom(ucharcom)//写入命令
{