-
此文档共包含三个程序。
第一个程序最简单易懂,看懂了基本就会读写
51
单片机内部
EEPROMT
。
第二个程序和第一个读写
EEP ROM
原理差不多,包含有
L
CD1602
操作方
法,有写字符串的方法。
第三个程序
在原有基础上增加了外部中断功能,细心的人会发现,操作内
部
EEPROM
过程会将总中断关闭,实际上程序要用到中断时
只需在原有的
EEP
ROM
操作后加上开总中断即可。
<
/p>
验证第二、第三个程序时需按程序内主程序中的操作说明进行烧录单片
机,以验证是否成功操作单片机内部
EEPROM
。
程序
1
:
/**
**************************************************
***********
作品:
EEP ROM
实验,开机还原关电前
LED
的亮灭状况
单片机:
STC89C52RC
晶振:
12M
编译环境:
Keil uVision4 V9.00
********
**************************************************
*****
//#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
****************
特殊功能寄存器声明
****************
1 /
43
sfr ISP_DATA
= 0xe2;
sfr ISP_ADDRH = 0xe3;
sfr ISP_ADDRL = 0xe4;
sfr
ISP_CMD = 0xe5;
sfr ISP_TRIG = 0xe6;
sfr ISP_CONTR = 0xe7;
sbit
LED1 = P 2
八
0;
sbit LED2 = P
2
八
1;
sbit K1= P 3
八
2;//
按钮
1
sbit K2= P3
八<
/p>
3;//
按钮
2
voidcc(uint addr);
voidxcx(uint addr,uchar dat);
uchar dcx(uint addr);
voidQ0();
/*
/*
void main(void)
uchar V;
*/
2 /
43
V
= dcx(0x2002);//
开机读取
EEPROM
p>
区
2002h
数
据
,
还原关电前
LED
的亮
灭
状况
if(V ==
2){LED1=0;LED2=1;}
else if(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
*/
/*
3 / 43
函数:擦除某一扇区
(
每个扇区
512
字节
)
入口:
addr
=
某一扇区首地址
*/
void cc(uint addr)
//
打开
IAP
功能
(
ISP_CONTR.7)=
允许编程改变
Fla
sh
设置
Flash
操作等待时
间
//
0x83(
晶振
v5M)0x82(
晶振
v10M)0x81(
晶振
v20M)0x80(
晶振
<40M)
ISP_CONTR = 0x81;
ISP_CMD= 0x03;/
用户可以对
< br>
区
进行扇区擦除
ISP_ADDRL = addr;// IS
P/IA
操作时的地址寄存器低八位,
ISP _ADDRH = addr>>8;// IS
P/IA
操作时的地址寄存器高八位。
EA =0;
ISP_TRIG =
0x46;
在
ISPEN(ISP_
CONTR.7)
时
,
对
ISP_TRlGfe
写入
46h
,
ISP_TRIG = 0
xB9;
再写入
B9h,ISP/IAP
命令才会生效。
_nop_();
Q0();
}//
关闭
ISP/IAP
/*
函数:写一字节
4 /
43
入口:
addr =
扇区单元地址
, dat =
待写入数
据
void xcx(uint addr,uchar dat)
ISP_CONTR = 0x81;
ISP_CMD= 0x02;/
用户可以对
< br>
区
进行字节编程
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=
读出的数
据
uchar dcx(uint addr)
5 /
43
*/
*/
uchar dat;
ISP_CONTR = 0x81;
ISP_CMD= 0x01;/
用户可以对
< br>
区
进行字节读
< br>
ISP_ADDRL
= addr;
ISP_ADDRH = addr>>8;
EA = 0;
ISP_TRIG = 0x46;
ISP_TRIG =
0xB9;
_nop_();
dat =
ISP_DATA;
Q0();
return dat;
}//
取出数据
//
关闭
ISP/IAP
/*
函数:关闭<
/p>
ISP/lAP
操作
void Q0()
ISP_CONTR =
0;
关闭
IAP
功能
ISP_CMD=
0;/
待
机模式,无
ISP
操作
ISP_TRIG= 0;
关闭
IAP
功能
,
清与
I
SP
有关的特殊功能寄存器
}
6 /
43
*/
/*
STC89C52R
内部
EEPROM
羊细地址表
< br>:
第一扇区第二扇区第三扇区第四扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2000h21FFh2200h23FFh2400h25FFh2600h27FFH
第五扇区第六扇区第七扇区第八扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2800h29FFh2A00h2BFFh2C00h2DFFh2E00h2FFFh
*/
程序
2
:
**************
*************************************************
作品:
EEP
ROM
实验,开机还原关电前
LED
的亮灭状况
单片机:
STC89C52RC
晶振
:
12M
编译环境:
Keil
uVision4 V9.00
************************
***************************************/
//#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
7
/ 43
/****************
特殊功能寄存器声明
****************/
sfr
ISP_DATA = 0xe2;
sfr ISP_ADDRH = 0xe3;
sfr ISP_ADDRL = 0xe4;
sfr
ISP_CMD = 0xe5;
sfr ISP_TRIG = 0xe6;
sfr ISP_CONTR = 0xe7;
sbit
LED1 = P 2
八
0;
sbit LED2 = P
2
八
1;
sbit K1= P 3
八
2;//
按钮
1
sbit K2= P3
八<
/p>
3;//
按钮
2
voidcc(uint addr);
voidxcx(uint addr,uchar dat);
uchar dcx(uint addr);
voidQ0();
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
/**********************************
8 / 43
PIN
口定义
**********************************
#define LCD1602_DATAPINS P0
sbit LCD1602_E
二
P
2
八
7;
sbit LCD1602
_RW=
卩
2
八
5;
sbit LCD1602_RS
二
P
2
八
6;
**********************************
函数声明
**********************************
/*
在
51
单片机
12MHZ
时钟下的延时函数
*/
void
Lcd1602_Delay1ms(uint
c);//
误差
Ous
/*LCD1602
写入
8
位命令子函数
*/
void
LcdWriteCom(uchar com);
/*LCD16O2
写入
8
位数据子函数
*/
void LcdWriteData(uchar dat);
/*LCD16O2
初始化子程序
*/
void LcdInit();
/*LCD16O2
写入字符串
*/
void
LCDWrite_String(uchar x, uchar y,uchar z, uchar
*s);
/*
设置
LCD1602<
/p>
写入字符串的位置
*/
void
LCD_set_xy(uchar x, uchar y, uchar z);
9 / 43
uchar
ON_Hour=0x07;//
初始开灯时间
07
:
OOluchar
Warning_TempH=32;//
高
温报警温度
/*
/*
void main(void)
uchar V;
V = dcx(0x2002);//<
/p>
开机读取
EEPROM
区
2002h
数据
,
状况
if(V == 2){LED1=0;LED2=1;}
else if(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
10 /
43
*/
LED
的亮灭
还原关电前
if(!K2)
while(!K2);
LED1=0;LED2=0;
cc(0x2000);//
擦除第
1
个扇区
(
2000h~21FFh
xcx(0x2002,6);//
对
EEPROM
区
2002h
写入
6
*/
void
main(void)
LcdInit();
//
不注销下面三句,烧录一次
//
注销小面三句,再烧录一次
//
p>
若两次烧录后现象一致,则操作内部
EEPROM
成功
< br>/////////////////////////////////////////////// //////////////////
cc(0x2000);//
擦除第
1
个扇区
(
2000h~21FFh <
/p>
xcx(0x2000,ON_Hour);//
对
EEPROM
区
2002h
写入
2
xcx(0x2001,Warning_TempH);
//
对
EEPROM
区
2002h
写入
/////////
//////////////////////////////////////////////////
//////
11 /
43
2
ON_Hour = dcx(0x2000);
Warning_TempH = dcx(0x2001);
if((ON_Hour==0x07)||(Warning_TempH==32))
LcdWriteCom(0x80);
LCDWrite_String(0, 1, 7,
else
LCDWrite_String(0, 1,
5,
while(1);
/*
函
数:擦除某一扇区
(
每个扇区
512
字节
)
入口:
addr
=
某一扇区首地址
*/
void cc(uint addr)
//
打开
lAP
功能
(
ISP_CONTR.7)=
允许编程改变
Fla
sh
设置
Flash
操作等待时
// 0x83(
晶振
<5M)0x82(
晶振
v10M)0x81(
晶振
<20M)0x80(
晶振
<40M)
ISP_CONTR = 0x81;
ISP_CMD= 0x03;/
用户可以对
< br>
区
进行扇区擦除
操作时的地址寄存器低八位,
12 /
43
间
ISP_ADDRL = addr;// IS P/IA
ISP _ADDRH = addr>>8;// IS
P/IA
操作时的地址寄存器高八位。
EA =0;
ISP_TRIG =
0x46;
在
ISPEN(ISP_
CONTR.7)
时
,
对
ISP_TRlGfe
写入
46h
,
ISP_TRIG =
0xB9;
再写入
B9h,ISP/
IAP
命令才会生效。
_nop_();
Q0();//
关闭
ISP/IAP
/*
函数:写一字节
入口:
addr
=
扇区单元地址
, dat
=
待写入数据
void
xcx(uint addr,uchar dat)
ISP_CONTR =
0x81;
ISP_CMD= 0x02;/
用户可以对
p>
区
进行字节编程<
/p>
ISP_ADDRL = addr;
ISP_ADDRH = addr>>8;
ISP_DATA=
dat;/
数据进
ISP_DATA
EA = 0;
ISP_TRIG = 0x46;
ISP_TRIG = 0xB9;
_nop_();
13 /
43
*/
Q0();//
关闭
ISP/IAP
/*
函数:读一字节
入口:
addr
=
扇区单元地址
出口:
dat
二
读出的数据
uchar
dcx(uint addr)
uchar dat;
ISP_CONTR = 0x81;
ISP_CMD= 0
x01;/
用户可以对
区
进行字节读
ISP_ADDRH =
addr>>8;
EA = 0;
ISP_TRIG =
0x46;
ISP_TRIG = 0xB9;
_nop_();
dat =
ISP_DATA;/
取出数据
Q0();//
关闭
ISP/IAP
return dat;
14 /
43
*/
ISP_ADDRL
= addr;
/*
函数:关闭
ISP/lAP
p>
操作
*/
void Q0()
ISP_CONTR =
0;
关闭
lAP
功能
ISP_CMD= 0;/
待机模式,无
ISP
操作
ISP_TRIG=
0;
关闭
IAP
功能
< br>,
清与
ISP
有关的特殊功能寄
存器
}
/*
STC89C52R
内部
EEPROM
羊细地址表
:
第一扇区第二扇区第三扇区第四扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2000h21FFh2200h23FFh2400h25FFh2600h27FFH
第五扇区第六扇区第七扇区第八扇区
起始地址结束地址起始地址结束地址起始地址结束地址起始地址结束地址
2800h29FFh2A00h2BFFh2C00h2DFFh2E00h2FFFh
*/
/************************
*****************************************
**************
函数名
:
Lcd1602_Delay1ms
函数功能
:
延时函数,延时
1ms
15 /
43
输入
: c
输出
:
无
<
/p>
说名
:
该函数是在
12MHZ
晶振下,
12
分频单片机
的延时。
***********************
******************************************
**************
void
Lcd1602_Delay1ms(uint c)//
误差
Ous
uchar a,b;
for (; c>O; c--)
for
(b=199;b>O;b--)
for(a=1;a>O;a--);
/******************************************* **********************
**************
*
函数名
: void LCDWrite_String(uchar x, uchar
y, uchar *s)
*
函数功能
:
向
LCD
写入一个字符串
*
输入
: x,y,*s
*
输出
:
无
********
**************************************************
*******
**************
16 /
43
void LCDWrite_String(uchar x, uchar y,
uchar z, uchar *s)//x 0~15 , y 0,1,2,3
LCD_set_xy(x,y,z);
while(*s)
LcdWriteData(*s);
s++;
******************************************** *********************
**************
*
函数名
:
void LCD_set_xy(uchar x,
uchar y,uchar z)
*
函数功能
:
指定向
LCD
写入字符串
的位置
*
输入
:
x,y,z//x:
横坐标
y:<
/p>
纵坐标
Z
:
字符
串长度
*
输出
:
无
*************
**************************************************
**
**************
void
LCD_set_xy(uchar x,uchar y,uchar z)
uchar i;
if(y==0)
17 /
43
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(' ');
18 /
43
LcdWriteCom(0x94+x);
if(y==3)
LcdWriteCom(0xd4+x);
for(i=0;i
LcdWriteData(' ');
LcdWriteCom(0xd4+x);
/******
**************************************************
*********
**************
*
函数名
: LcdWriteCom
*
函数功能
:
向
LCD
写入一个字节的命令
*
输入
:
com
*
输出
:
************************
*****************************************
**************
#ifndefLCD1602
4PINS/
当没有定义这个
LCD1602 4PIN
时
void LcdWriteCom(uchar
com)//
写入命令
19 /
43
LCD1602_E = 0;/
使
/
能
LCD1602_RS =
0;
选择发送命令
LCD1602_RW =
0;/
选
/
择写入
LCD1602_DATA
PINS = com
放
入命令
Lcd1602_Delay
1ms(1);//
等待数据稳定
LCD1602_E = 1;/
写
/
入时序
Lcd1602_Delay
1ms(5);//
保持时间
LCD1602_E = 0;
#else
void LcdWriteCom(uchar com)//
写入命令
LCD1602_E =
0;/
使
/
能清零
LCD1602_RS =
0;/
选
/
择写入命令
LCD1602_RW
= 0;/
选
/
择写入
LCD1602_DATAPINS = com
由于
4
位的接线是接到
P0
口的高四位,所以传
送高四位不用改
//Lcd1602_Delay1ms(1);
LCD1602_E = 1;/
写
/
入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
Lcd1602_Delay1ms(1);
20 /
43