此文档共包含三个程序。
第一个程序最简单易懂,看懂了基本就会读写51单片机内部EEPROM了。
第二个程序和第一个读写EEPROM原理差不多,包含有LCD1602操作方法,有写字符串的方法。
第三个程序在原有基础上增加了外部中断功能,细心的人会发现,操作内部EEPROM过程会将总中断关闭,实际上程序要用到中断时只需在原有的EEPROM操作后加上开总中断即可。
验证第二、第三个程序时需按程序内主程序中的操作说明进行烧录单片机,以验证是否成功操作单片机内部EEPROM。
程序1: - /***************************************************************
- 作品:EEPROM实验,开机还原关电前LED的亮灭状况
- 单片机:STC89C52RC
- 晶振:12M
- 编译环境:Keil uVision4 V9.00
- ***************************************************************/
- //#include <STC89C52RC.H>
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /****************特殊功能寄存器声明****************/
- 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 = P2^0;
- sbit LED2 = P2^1;
- sbit K1 = P3^2; //按钮1
- sbit K2 = P3^3; //按钮2
- void cc(uint addr);
- void xcx(uint addr,uchar dat);
- uchar dcx(uint addr);
- void Q0();
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:主程序
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- /*
- void main(void)
- {
- uchar V;
- V = dcx(0x2002); // 开机读取EEPROM区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
- }
- }
- }
- */
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:擦除某一扇区(每个扇区512字节)
- 入口:addr = 某一扇区首地址
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void cc(uint addr)
- {
- // 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
- // 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
- ISP_CONTR = 0x81;
- ISP_CMD = 0x03; // 用户可以对"Data Flash/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 = 待写入数据
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void xcx(uint addr,uchar dat)
- {
- ISP_CONTR = 0x81;
- ISP_CMD = 0x02; // 用户可以对"Data Flash/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 = 读出的数据
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- uchar dcx(uint addr)
- {
- uchar dat;
-
- ISP_CONTR = 0x81;
- ISP_CMD = 0x01; // 用户可以对"Data Flash/EEPROM区"进行字节读
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- dat = ISP_DATA; // 取出数据
- Q0(); // 关闭ISP/IAP
- return dat;
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:关闭ISP/IAP操作
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void Q0()
- {
- ISP_CONTR = 0; // 关闭IAP功能
- ISP_CMD = 0; // 待机模式,无ISP操作
- ISP_TRIG = 0; // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
- }
- /*
- STC89C52RC内部EEPROM详细地址表:
- 第一扇区 第二扇区 第三扇区 第四扇区
- 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址
- 2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH
- 第五扇区 第六扇区 第七扇区 第八扇区
- 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址
- 2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh
- */
复制代码
程序2: - /***************************************************************
- 作品:EEPROM实验,开机还原关电前LED的亮灭状况
- 单片机:STC89C52RC
- 晶振:12M
- 编译环境:Keil uVision4 V9.00
- ***************************************************************/
- //#include <STC89C52RC.H>
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /****************特殊功能寄存器声明****************/
- 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 = P2^0;
- sbit LED2 = P2^1;
- sbit K1 = P3^2; //按钮1
- sbit K2 = P3^3; //按钮2
- void cc(uint addr);
- void xcx(uint addr,uchar dat);
- uchar dcx(uint addr);
- void Q0();
- #ifndef uchar
- #define uchar unsigned char
- #endif
- #ifndef uint
- #define uint unsigned int
- #endif
- /**********************************
- PIN口定义
- **********************************/
- #define LCD1602_DATAPINS P0
- sbit LCD1602_E=P2^7;
- sbit LCD1602_RW=P2^5;
- sbit LCD1602_RS=P2^6;
- /**********************************
- 函数声明
- **********************************/
- /*在51单片机12MHZ时钟下的延时函数*/
- void Lcd1602_Delay1ms(uint c); //误差 0us
- /*LCD1602写入8位命令子函数*/
- void LcdWriteCom(uchar com);
- /*LCD1602写入8位数据子函数*/
- void LcdWriteData(uchar dat) ;
- /*LCD1602初始化子程序*/
- void LcdInit();
- /*LCD1602写入字符串*/
- void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);
- /*设置LCD1602写入字符串的位置*/
- void LCD_set_xy(uchar x, uchar y, uchar z);
- uchar ON_Hour=0x07; //初始开灯时间 07:00 1
- uchar Warning_TempH=32; //高温报警温度 5
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:主程序
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- /*
- void main(void)
- {
- uchar V;
- V = dcx(0x2002); // 开机读取EEPROM区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
- }
- }
- }
- */
- void main(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 = 某一扇区首地址
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void cc(uint addr)
- {
- // 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
- // 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
- ISP_CONTR = 0x81;
- ISP_CMD = 0x03; // 用户可以对"Data Flash/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 = 待写入数据
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void xcx(uint addr,uchar dat)
- {
- ISP_CONTR = 0x81;
- ISP_CMD = 0x02; // 用户可以对"Data Flash/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 = 读出的数据
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- uchar dcx(uint addr)
- {
- uchar dat;
-
- ISP_CONTR = 0x81;
- ISP_CMD = 0x01; // 用户可以对"Data Flash/EEPROM区"进行字节读
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- dat = ISP_DATA; // 取出数据
- Q0(); // 关闭ISP/IAP
- return dat;
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:关闭ISP/IAP操作
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void Q0()
- {
- ISP_CONTR = 0; // 关闭IAP功能
- ISP_CMD = 0; // 待机模式,无ISP操作
- ISP_TRIG = 0; // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
- }
- /*
- STC89C52RC内部EEPROM详细地址表:
- 第一扇区 第二扇区 第三扇区 第四扇区
- 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址
- 2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH
- 第五扇区 第六扇区 第七扇区 第八扇区
- 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址
- 2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh
- */
- /*******************************************************************************
- * 函 数 名 : Lcd1602_Delay1ms
- * 函数功能 : 延时函数,延时1ms
- * 输 入 : c
- * 输 出 : 无
- * 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。
- *******************************************************************************/
- void Lcd1602_Delay1ms(uint c) //误差 0us
- {
- uchar a,b;
- for (; c>0; c--)
- {
- for (b=199;b>0;b--)
- {
- for(a=1;a>0;a--);
- }
- }
- }
- /*******************************************************************************
- * 函 数 名 : void LCDWrite_String(uchar x, uchar y, uchar *s)
- * 函数功能 : 向LCD写入一个字符串
- * 输 入 : x,y,*s
- * 输 出 : 无
- *******************************************************************************/
- 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:纵坐标 z:字符串长度
- * 输 出 : 无
- *******************************************************************************/
- void LCD_set_xy(uchar x,uchar y,uchar z)
- {
- uchar i;
- if(y==0)
- {
- LcdWriteCom(0x80+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x80+x);
- }
- if(y==1)
- {
- LcdWriteCom(0xc0+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xc0+x);
- }
- if(y==2)
- {
- LcdWriteCom(0x94+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x94+x);
- }
- if(y==3)
- {
- LcdWriteCom(0xd4+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xd4+x);
- }
- }
- /*******************************************************************************
- * 函 数 名 : LcdWriteCom
- * 函数功能 : 向LCD写入一个字节的命令
- * 输 入 : com
- * 输 出 : 无
- *******************************************************************************/
- #ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
- void LcdWriteCom(uchar com) //写入命令
- {
- 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
- 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);
- LCD1602_DATAPINS = com << 4; //发送低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 数 名 : LcdWriteData
- * 函数功能 : 向LCD写入一个字节的数据
- * 输 入 : dat
- * 输 出 : 无
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdWriteData(uchar dat) //写入数据
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //选择输入数据
- LCD1602_RW = 0; //选择写入
- LCD1602_DATAPINS = dat; //写入数据
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5); //保持时间
- LCD1602_E = 0;
- }
- #else
- void LcdWriteData(uchar dat) //写入数据
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //选择写入数据
- LCD1602_RW = 0; //选择写入
- LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- LCD1602_DATAPINS = dat << 4; //写入低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 数 名 : LcdInit()
- * 函数功能 : 初始化LCD屏
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x38); //开显示
- LcdWriteCom(0x0c); //开显示不显示光标
- LcdWriteCom(0x06); //写一个指针加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //设置数据指针起点
- }
- #else
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x32); //将8位总线转为4位总线
- LcdWriteCom(0x28); //在四位线下的初始化
- LcdWriteCom(0x0c); //开显示不显示光标
- LcdWriteCom(0x06); //写一个指针加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //设置数据指针起点
- }
- #endif
复制代码
程序3: - /***************************************************************
- 作品:EEPROM实验,开机还原关电前LED的亮灭状况
- 单片机:STC89C52RC
- 晶振:12M
- 编译环境:Keil uVision4 V9.00
- ***************************************************************/
- //#include <STC89C52RC.H>
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /****************特殊功能寄存器声明****************/
- 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 = P2^0;
- sbit LED2 = P2^1;
- sbit K1 = P3^2; //按钮1
- sbit K2 = P3^3; //按钮2
- void cc(uint addr);
- void xcx(uint addr,uchar dat);
- uchar dcx(uint addr);
- void Q0();
- #ifndef uchar
- #define uchar unsigned char
- #endif
- #ifndef uint
- #define uint unsigned int
- #endif
- /**********************************
- PIN口定义
- **********************************/
- #define LCD1602_DATAPINS P0
- sbit LCD1602_E=P2^7;
- sbit LCD1602_RW=P2^5;
- sbit LCD1602_RS=P2^6;
- /**********************************
- 函数声明
- **********************************/
- /*在51单片机12MHZ时钟下的延时函数*/
- void Lcd1602_Delay1ms(uint c); //误差 0us
- /*LCD1602写入8位命令子函数*/
- void LcdWriteCom(uchar com);
- /*LCD1602写入8位数据子函数*/
- void LcdWriteData(uchar dat) ;
- /*LCD1602初始化子程序*/
- void LcdInit();
- /*LCD1602写入字符串*/
- void LCDWrite_String(uchar x, uchar y,uchar z, uchar *s);
- /*设置LCD1602写入字符串的位置*/
- void LCD_set_xy(uchar x, uchar y, uchar z);
- void IntConfiguration();
- /*
- uchar ON_Hour=0x07; //初始开灯时间 07:00 1
- uchar Warning_TempH=32; //高温报警温度 5
- */
- uchar ON_Hour; //初始开灯时间 07:00 1
- uchar Warning_TempH; //高温报警温度
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:主程序
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void main(void)
- {
- LcdInit();
- IntConfiguration();
- /////////////////////////////////////////////////////////////////
- /*
- cc(0x2000); // 擦除第1个扇区(2000h~21FFh)
- xcx(0x2000,ON_Hour); // 对EEPROM区2002h写入2
- xcx(0x2001,Warning_TempH); // 对EEPROM区2002h写入2
- */
- /////////////////////////////////////////////////////////////////
- while(1)
- {
- ON_Hour = dcx(0x2000);
- Warning_TempH = dcx(0x2001);
- if((ON_Hour==0x07)||(Warning_TempH==32))
- {
- LcdWriteCom(0x80);
- LCDWrite_String(0, 1, 7, "SUCCESS");
- }
- else
- LcdWriteCom(0x80);
- LCDWrite_String(0, 1, 5, "ERROR");
- }
- /*
- uchar V;
- V = dcx(0x2002); // 开机读取EEPROM区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
- }
- }
- */
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:擦除某一扇区(每个扇区512字节)
- 入口:addr = 某一扇区首地址
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void cc(uint addr)
- {
- // 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
- // 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
- ISP_CONTR = 0x81;
- ISP_CMD = 0x03; // 用户可以对"Data Flash/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 = 待写入数据
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void xcx(uint addr,uchar dat)
- {
- ISP_CONTR = 0x81;
- ISP_CMD = 0x02; // 用户可以对"Data Flash/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 = 读出的数据
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- uchar dcx(uint addr)
- {
- uchar dat;
-
- ISP_CONTR = 0x81;
- ISP_CMD = 0x01; // 用户可以对"Data Flash/EEPROM区"进行字节读
- ISP_ADDRL = addr;
- ISP_ADDRH = addr>>8;
- EA = 0;
- ISP_TRIG = 0x46;
- ISP_TRIG = 0xB9;
- _nop_();
- dat = ISP_DATA; // 取出数据
- Q0(); // 关闭ISP/IAP
- return dat;
- }
- /*┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
- 函数:关闭ISP/IAP操作
- ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈*/
- void Q0()
- {
- ISP_CONTR = 0; // 关闭IAP功能
- ISP_CMD = 0; // 待机模式,无ISP操作
- ISP_TRIG = 0; // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
- EA=1;
- }
- /*
- STC89C52RC内部EEPROM详细地址表:
- 第一扇区 第二扇区 第三扇区 第四扇区
- 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址
- 2000h 21FFh 2200h 23FFh 2400h 25FFh 2600h 27FFH
- 第五扇区 第六扇区 第七扇区 第八扇区
- 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址 起始地址 结束地址
- 2800h 29FFh 2A00h 2BFFh 2C00h 2DFFh 2E00h 2FFFh
- */
- /*******************************************************************************
- * 函 数 名 : Lcd1602_Delay1ms
- * 函数功能 : 延时函数,延时1ms
- * 输 入 : c
- * 输 出 : 无
- * 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。
- *******************************************************************************/
- void Lcd1602_Delay1ms(uint c) //误差 0us
- {
- uchar a,b;
- for (; c>0; c--)
- {
- for (b=199;b>0;b--)
- {
- for(a=1;a>0;a--);
- }
- }
- }
- /*******************************************************************************
- * 函 数 名 : void LCDWrite_String(uchar x, uchar y, uchar *s)
- * 函数功能 : 向LCD写入一个字符串
- * 输 入 : x,y,*s
- * 输 出 : 无
- *******************************************************************************/
- 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:纵坐标 z:字符串长度
- * 输 出 : 无
- *******************************************************************************/
- void LCD_set_xy(uchar x,uchar y,uchar z)
- {
- uchar i;
- if(y==0)
- {
- LcdWriteCom(0x80+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x80+x);
- }
- if(y==1)
- {
- LcdWriteCom(0xc0+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xc0+x);
- }
- if(y==2)
- {
- LcdWriteCom(0x94+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0x94+x);
- }
- if(y==3)
- {
- LcdWriteCom(0xd4+x);
- for(i=0;i<z;i++)
- {
- LcdWriteData(' ');
- }
- LcdWriteCom(0xd4+x);
- }
- }
- /*******************************************************************************
- * 函 数 名 : LcdWriteCom
- * 函数功能 : 向LCD写入一个字节的命令
- * 输 入 : com
- * 输 出 : 无
- *******************************************************************************/
- #ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
- void LcdWriteCom(uchar com) //写入命令
- {
- 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
- 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);
- LCD1602_DATAPINS = com << 4; //发送低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 数 名 : LcdWriteData
- * 函数功能 : 向LCD写入一个字节的数据
- * 输 入 : dat
- * 输 出 : 无
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdWriteData(uchar dat) //写入数据
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //选择输入数据
- LCD1602_RW = 0; //选择写入
- LCD1602_DATAPINS = dat; //写入数据
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5); //保持时间
- LCD1602_E = 0;
- }
- #else
- void LcdWriteData(uchar dat) //写入数据
- {
- LCD1602_E = 0; //使能清零
- LCD1602_RS = 1; //选择写入数据
- LCD1602_RW = 0; //选择写入
- LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- LCD1602_DATAPINS = dat << 4; //写入低四位
- Lcd1602_Delay1ms(1);
- LCD1602_E = 1; //写入时序
- Lcd1602_Delay1ms(5);
- LCD1602_E = 0;
- }
- #endif
- /*******************************************************************************
- * 函 数 名 : LcdInit()
- * 函数功能 : 初始化LCD屏
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- #ifndef LCD1602_4PINS
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x38); //开显示
- LcdWriteCom(0x0c); //开显示不显示光标
- LcdWriteCom(0x06); //写一个指针加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //设置数据指针起点
- }
- #else
- void LcdInit() //LCD初始化子程序
- {
- LcdWriteCom(0x32); //将8位总线转为4位总线
- LcdWriteCom(0x28); //在四位线下的初始化
- LcdWriteCom(0x0c); //开显示不显示光标
- LcdWriteCom(0x06); //写一个指针加1
- LcdWriteCom(0x01); //清屏
- LcdWriteCom(0x80); //设置数据指针起点
- }
- #endif
- void IntConfiguration()
- {
- //设置INT0
- IT0=1;//跳变沿出发方式(下降沿)
- EX0=1;//打开INT0的中断允许。
- //设置INT1
- IT1=1;//跳变沿出发方式(下降沿)
- EX1=1;//打开INT0的中断允许。
- EA=1;//打开总中断
- }
- void Int0() interrupt 1
- {
- cc(0x2000); // 擦除第1个扇区(2000h~21FFh)
- xcx(0x2000,0x07); // 对EEPROM区2002h写入2
- xcx(0x2001,32);
- LcdInit();
- }
- void Int1() interrupt 2
- {
- cc(0x2000); // 擦除第1个扇区(2000h~21FFh)
- xcx(0x2000,0x08); // 对EEPROM区2002h写入2
- xcx(0x2001,33);
- LcdInit();
- }
复制代码
全部资料下载地址:
51单片机读写内部EEPROM详解.rar
(101.88 KB, 下载次数: 364)
|