51单片机读写内部EEPROM详解
- 格式:doc
- 大小:32.86 KB
- 文档页数:26
51单片机数据存储器结构详解1、bit是在内部数据存储空间中20h..2fh区域中一个位的地址,这在data的20h以后以字节形式出现,可互相参照。
另外加上8051可寻址的sfr,但刚刚试过,只是00h--7fh起作用,也就是说当数据有变化时颜色变红,以后的从80h到--ffh就不是位寻址区了,是位寻址的特殊寄存器,如涉及到了可位寻址的那11个当然会有反应。
复位后,程序计数器PC的内容为0000H,内部RAM的每个单元的值不确定。
每个功能寄存器的重置值如下:堆栈指针SP的重置值为07h,累加器ACC和寄存器B的重置值为00h,数据指针dptr的重置值为0000H,P0、P1、P2和P3的重置值为0ffh。
其他SFR (如PSW、TCON、tmod、tl0、Th0、TL1和Th1)的重置值也为00h。
2、wave中是低128字节和高128字节(0-7fh),低128字节是片内ram区,高128字节(80-ffh)是sfr(特殊功能寄存器)bit则是位于低128字节的20h..2fh区域,即data的20h..2fh区域3.代码位于0000H中,代码地址介于0ffh和FFH之间。
例如:org5000h标签:在db2h、3bh、43h、66h、5h、6dh、88H之后,代码从5000h变为dB4、data是在0到127之间的一个数据存储器地址,或者加128..255范围内的一个特殊功能寄存器(sfr)地址。
两者访问的方式不同。
实际上由于psw的复位设置psw.3=rs0和psw.4=rs1皆为0,所以通用工作寄存器区就是第0区,所以data的00--07h部分是与reg栏中的r0--r7对应的。
以后的则仅代表低128字节的内部ram。
5.IData是0到255范围内的IData内存地址。
IData与数据重叠128字节。
在某些地方,只有数据代表256字节的片上RAM,扩展数据是0到65535范围内的扩展数据存储器地址。
主函数:#include<reg52.h>#include"EEPROM.h"#include"smg.h"void main(){num=byte_read(DEBUG_Data_Memory_Begin_Sector_addr);//字节读(程序开始时读取EEPROM中数据)if(num>=60)num=0;//防止首次上电时读取出错??while(1){if(num<60){display(num);num++;delay(5);delay1(DELAY_CONST);sector_erase(DEBUG_Data_Memory_Begin_Sector_addr);//擦出扇区byte_program (DEBUG_Data_Memory_Begin_Sector_addr,num);//字节编程}if(num==60)num=0;}}EEPROM.h:/*STC89C51RC,STC89LE51RC 0x2000 共八个扇区STC89C52RC,STC89LE52RC 0x2000 共八个扇区STC89C54RD+,STC89LE54RD+ 0x8000 共五十八个扇区STC89C55RD+,STC89LE55RD+ 0x8000 共五十八个扇区STC89C58RD+,STC89LE58RD+ 0x8000 共五十八个扇区*/#include<reg52.h>#include<intrins.h>//sfr定义特殊功能寄存器sfr ISP_DATA =0xe2;//ISP/IAP 操作时的数据寄存器,从Flash 读出的数据放在此处,向Flash 写的数据也需放在此处sfr ISP_ADDRH =0xe3;//ISP/IAP 操作时的地址寄存器高八位sfr ISP_ADDRL =0xe4;//ISP/IAP 操作时的地址寄存器低八位sfr ISP_CMD =0xe5;//ISP/IAP 操作时的命令模式寄存器,须命令触发寄存器触发方可生效sfr ISP_TRIG =0xe6;//ISP/IAP 操作时的命令触发寄存器sfr ISP_CONTR =0xe7;//ISP/IAP 控制寄存器/* 定义命令*/#define uchar unsigned char /*8bit无符号整型*/#define uint unsigned int /*16bit无符号整型*/#define READ_AP_and_Data_Memory_Command 0x01 /*字节读数据存储区*/#define PROGRAM_AP_and_Data_Memory_Command 0x02 /*字节编程数据存储区*/#define SECTOR_ERASE_AP_and_Data_Memory_Command 0x03 /*扇区擦除数据存储*/#define DEBUG_Data_Memory_Begin_Sector_addr 0x2000//扇区地址#define DELAY_CONST 60000//延时#define WAIT_TIME 0x01uchar num;/* 打开ISP,IAP 功能*/void ISP_IAP_enable(void){EA=0;/* 关中断*/ISP_CONTR=ISP_CONTR & 0x18; /* 0001,1000 */ISP_CONTR=ISP_CONTR|WAIT_TIME;ISP_CONTR=ISP_CONTR|0x80; /* 1000,0000 */}/* 关闭ISP,IAP 功能*/void ISP_IAP_disable(void){ISP_CONTR=ISP_CONTR&0x7f;/* 0111,1111 */ISP_TRIG=0x00;EA=1;/* 开中断*/}/* 字节读*/uchar byte_read(uint byte_addr){ISP_ADDRH = (uchar)(byte_addr >> 8);ISP_ADDRL = (uchar)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD&0xf8;/* 1111,1000 */ISP_CMD = ISP_CMD|READ_AP_and_Data_Memory_Command;/* 0000,0001 */ISP_IAP_enable();ISP_TRIG = 0x46;ISP_TRIG = 0xb9;_nop_();ISP_IAP_disable();return (ISP_DATA);}/* 扇区擦除*/void sector_erase(uint sector_addr){uint get_sector_addr=0;get_sector_addr=(sector_addr & 0xfe00); /* 1111,1110,0000,0000; 取扇区地址*/ ISP_ADDRH = (uchar)(get_sector_addr >> 8);ISP_ADDRL = 0x00;ISP_CMD = ISP_CMD&0xf8;/* 1111,1000 */ISP_CMD =ISP_CMD|SECTOR_ERASE_AP_and_Data_Memory_Command;/* 0000,0011 */ ISP_IAP_enable();ISP_TRIG = 0x46;/* 触发ISP_IAP命令*/ISP_TRIG = 0xb9;/* 触发ISP_IAP命令*/_nop_();ISP_IAP_disable();}/* 字节编程*/void byte_program(uint byte_addr, uchar original_data){ISP_ADDRH = (uchar)(byte_addr >> 8);ISP_ADDRL = (uchar)(byte_addr & 0x00ff);ISP_CMD = ISP_CMD & 0xf8; /* 1111,1000 */ISP_CMD = ISP_CMD |PROGRAM_AP_and_Data_Memory_Command; /* 0000,0010 */ISP_DATA = original_data;ISP_IAP_enable();ISP_TRIG = 0x46; /* 触发ISP_IAP命令*/ISP_TRIG = 0xb9; /* 触发ISP_IAP命令*/_nop_();ISP_IAP_disable();}void delay1(uint counter){uint temp=0;for(temp=counter;temp>0;temp--){_nop_();_nop_();_nop_();}}Smg.h:/****************************************************************************** ***** 标题: 试验数码管上显示数字( 单片机直接实现位选共阴极) ** 用573锁存器控制和单片机脚直接位选控制(非译码器控制)数码管******************************************************************************** ****/#include <reg52.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intuchar code smg_duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //段码0-9.uchar code smg_wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdF,0xbF,0x7F}; //位选控制查表的方法控制void delay(uint i){uchar j;for(i;i>0;i--)for(j=200;j>0;j--);}void display(uint dat)//数码管显示函数{uint i;uint LedOut[10];LedOut[0]=smg_duan[dat%10000/1000];//(若要显示小数点,则|0x80)LedOut[1]=smg_duan[dat%1000/100];LedOut[2]=smg_duan[dat%100/10];LedOut[3]=smg_duan[dat%10];for( i=0; i<4; i++){P0=LedOut[i];P2=smg_wei[i];//使用查表法进行位选delay(10);//扫描间隔时间,数码管每位显示的时间,太长会数码管会有闪烁感}}。
51单⽚机内部EEPROM读写#include <reg52.h>#include <intrins.h>//定义类型,⽅便代码移植typedef unsigned char UINT8;typedef unsigned int UINT16;typedef unsigned long UINT32;typedef char INT8;typedef int INT16;typedef long INT32;static UINT8 i=0;/*定义寄存器 ISP*/sfr ISP_DATA= 0xe2; // Flash数据寄存器sfr ISP_ADDRH= 0xe3;// Flash⾼字节地址寄存器sfr ISP_ADDRL= 0xe4;// Flash低字节地址寄存器sfr ISP_CMD= 0xe5;// Flash命令模式寄存器sfr ISP_TRIG= 0xe6;// Flash命令触发寄存器sfr ISP_CONTR= 0xe7;// ISP/IAP 控制寄存器#define NOP() _nop_()#define EEPROM_START_ADDRESS 0X2000#define LED_PORT P2//微秒级延时void DelayNus(UINT16 t){UINT16 d=0;d=t;do{NOP();}while(--d > 0);}//毫秒级延时void DelayNms(UINT16 t){do{DelayNus(1000);}while(--t > 0);}//EEPROM使能void EEPROMEnable(void){ISP_CONTR=0x81;//使能并设置好等待时间}//EEPROM禁⽤void EEPROMDisable(void){ISP_CONTR=0x00;//禁⽌EEPROMISP_CMD = 0X00;//⽆ISP操作ISP_TRIG = 0X00;//清零ISP_ADDRH = 0X00;//清零ISP_ADDRL = 0X00;//清零}//eeprom 设置读写地址(相对地址)void EEPROMSetAddress(UINT16 addr){addr+=EEPROM_START_ADDRESS;//初始化地址ISP_ADDRH=(UINT8)(addr>>8);//设置读写地址⾼字节ISP_ADDRL=(UINT8) addr; //设置读写地址低字节}//EEPROM启动void EEPROMStart(void){ISP_TRIG=0x46;ISP_TRIG=0xB9;}//EEPROM读取单个字节UINT8 EEPROMReadByte(UINT16 addr){ISP_DATA=0X00;ISP_CMD=0X01;EEPROMEnable();EEPROMSetAddress(addr);EEPROMStart();DelayNus(10);//读取⼀个字节需要10usEEPROMDisable();return (ISP_DATA);}//EEPROM写⼊单个字节UINT8 EEPROMWriteByte(UINT16 addr,UINT8 byte) {EEPROMEnable();ISP_CMD=0X02;EEPROMSetAddress(addr);ISP_DATA=byte;EEPROMStart();DelayNus(60);EEPROMDisable();}//EEPROM扇区擦除UINT8 EEPROMSectorErase(UINT16 addr){ISP_CMD=0X03;EEPROMEnable();EEPROMSetAddress(addr);EEPROMStart();DelayNus(10);//EEPROMDisable();}void main(void){EEPROMSectorErase(0);EEPROMWriteByte(0,0x0f);i=EEPROMReadByte(0);LED_PORT = i;while(1);}现象:。
#include<reg52.h>#include<intrins.h>typedef unsigned char BYTE;typedef unsigned int WORD;//声明SFR IAP联系在一起的sfr IAP_DATA=0xE2; // flash data registersfr IAP_ADDRH=0xE3; //flash address highsfr IAP_ADDRL=0xe4; //falsh address lowsfr IAP_CMD=0Xe5; //FALSH COMMAND TRGGERsfr IAP_TRIG=0xE6; //flash command triggersfr IAP_CONTR=0xE7; //flash control register//定义ISP/IAP/EEPROM 命令#define CMD_IDIE 0 //stand-by#define CMD_READ 1 //BYTE - READ#define CMD_PROGRAM 2 // BYTE- PROGRAM#define CMD_ERASE 3 //SECTOR --ERASE//define ISP/IAP/EEPROM operation const for IAP_CONTR//#define ENABLE_IAP 0X80 //SYSCLK<40MHZ#define ENABLE_IAP 0X81 // SYSCLK<20MHZ//#define ENABLE_IAP 0x82 //SYSCLK<10MHZ//#define ENABLE_IAP 0X83 //SYSCLK<5MHZ//Start addtess for STC89C58 eeprom#define IAP_ADDRESS 0x08000void Delay(BYTE n);void IapIdle();BYTE IapReadByte(WORD addr);void IapProgramByte(WORD addr,BYTE dat);void IapEraseSector(WORD addr);void main(){WORD i;P1=0xfe; //1111,1110 system reset okDelay(5);IapEraseSector(IAP_ADDRESS); //ERASE CURRENT SECTOR for(i=0;i<512;i++) //check whether all sector data is ff {if(IapReadByte(IAP_ADDRESS+i)!=0xff)goto Error; //if error ,break}P1=0xfc; //1111,1100 erase successfulDelay(5);for(i=0;i<256;i++) //program 512 bytes data into data flash{IapProgramByte(IAP_ADDRESS+i,(BYTE)i);}P1=0XF8; //1111,1000 program successfulDelay(5);for(i=0;i<256;i++) //verify 512 bytes data{if(IapReadByte(IAP_ADDRESS+i)!=(BYTE)i)goto Error;}P1=0xf0; //1111,0000 verify successfulwhile(1);Error:P1&=0x7f; //oxxx,xxxx IAP operation failwhile(1);}// software delay functionvoid Delay(BYTE n){WORD x;while(n--){x=0;while(++x);}}//disable ISP/IAP/EEPROM function MAKE MCU in a safe state void IapIdle(){IAP_CONTR=0; //CLOSE IAP FUNCTIONIAP_CMD=0; //CLEAR COMMAND TO STANDBYIAP_TRIG=0; //CLEAR TRIGGER REGISTERIAP_ADDRH=0X80; //DATA PTR POINT TO NON-EEPROM AREA IAP_ADDRL=0; //CLEAR IAP ADDRESS TO PREVENT MISUSE }//Read one byte from ISP/IAP/EEPROM area//Input:addr (ISP/IAP/EEPROM address//Output: flash adataBYTE IapReadByte(WORD addr){BYTE dat;IAP_CONTR=ENABLE_IAP; //OPEN IAP FUNCTION ,AND SET WAIT TIMEIAP_CMD=CMD_READ; //SET ISP/IAP/EEPROM READ COMMANDIAP_ADDRL=addr; //SET ISP/IAP/EEPROM address lowIAP_ADDRH=addr>>8; //SET ISP//IAP//EEPROM address HIGHIAP_TRIG=0X46; //SEND TRIGGER COMMAND1 OX46IAP_TRIG=0XB9; //SEND TRIGGER COMMAND2 0XB9_nop_();dat=IAP_DATA; //read ISP/IAP/EEPROM dataIapIdle(); // close ISP/IAP/EEPROM FUNCITONreturn dat; //RETURN FLAH DATA}//Program one byte to ISP/IAP/EEPROM area//INPUT :addr (ISP/IAP/EEPROM address)//dat(ISP/IAP/EEPROM data)//Output:-void IapProgramByte(WORD addr, BYTE dat){IAP_CONTR=ENABLE_IAP; //OPEN IAP FUNTION AND SET WAIT TIMEIAP_CMD=CMD_PROGRAM; //SET ISP/IAP/EEPROM PROGRAM COMMAND IAP_ADDRL=addr; //set ISP/IAP/EEPROM ADDRESS LOWIAP_ADDRH=addr>>8; //set ISP/IAP/EEPROM address highIAP_DATA=dat; // WRITE ISP/IAP/EEPROM dataIAP_TRIG=0X46;IAP_TRIG=0XB9;_nop_();IapIdle();}void IapEraseSector(WORD addr){IAP_CONTR=ENABLE_IAP;IAP_CMD=CMD_ERASE;IAP_ADDRL=addr;IAP_ADDRH=addr>>8;IAP_TRIG=0X46;IAP_TRIG=0XB9;_nop_();IapIdle();}。
51单片机软件实现iic总线的工作时序所用EEPROM芯片AT24C02,实现向AT24C02中写入数据,然后将其中数据读出赋予P0口,实现流水灯的按数据亮灭,PS:附MCU图,AT24C02图于最后。
嘤其鸣矣,求其友声如若不弃,加我QQ:2447104957,高山流水,共同学习!#include <reg51.h>#define uchar unsigned char#define uint unsigned intsbit sda=P2^0;sbit scl=P2^1;//mcu原理图void delay(){;;}//微秒延时void init() //初始化,释放总线各线至高电平,SCL=0时,SDA可以改变{scl=0;delay();//微秒延时sda=1;delay();scl=1;delay();}void start() //起始信号{scl=0;delay();sda=1;delay();scl=1;delay();sda=0;delay();sda=1;//释放数据总线}void write_byte(uchar date)//字节写{uchar i,temp;temp=date;//由高位一位一位的写入for(i=0;i<8;i++)temp=temp<<1;//左移溢出到PSW寄存器CY位scl=0;//允许sda进行的变化delay();sda=CY;//进行一位一位的送入数据总线delay();scl=1;//符合读走数据总线上数据的要求delay();//稳定一段时间}scl=0;//允许sda变化,以便于接受应答信号delay();sda=1;//释放数据总线,准备接收应答信号delay();}void response()//应答,可以看书page181,由接收设备发出的第九位数据,要经由sda传输给发送设备{uchar i;scl=1;delay();while((sda==1)&&(i<250)){i++;//等待应答有一定的时间限制,sda被拉低表示有应答,由硬件控制}scl=0;delay();}void stop()//停止信号,scl=1,sda形成一个正跳变{scl=0;//允许sda变化delay();sda=0;//准备形成正跳变delay();scl=1;//信号有效前提1delay();sda=1;//形成正跳变delay();//信号有效前提1}void delay1(uint z)//毫秒级延时{for(x=z;x>0;x--)for(y=110;y>0;y--);}uchar read_byte()//带有返回值,将所读到的数据作为返回值{uchar i,d;//d=0x00;//清空存储变量的空间for(i=0;i<8;i++){scl=0;//允许变化,即允许传送数据,sda是serial dual date busdelay();scl=1;//允许读走数据delay();d=(d<<1)|sda;//将sda上数据放入存储变量d,也是8位ucharscl=0;delay();}return d;/*scl=0;delay();sda=1;//释放数据总线,准备接受应答,被拉低delay();*/}void main(){init();//初始化//例子先写入EEPROM器件AT24C16数据,然后进行读取赋予流水灯是对应数据亮灭start();//起始信号write_byte(0xa0);/*写入EEPROM器件地址,写入分为数据,地址数据,地址又分为器件地址和内部存储地址,例如某班级某学生座位*/response();//等待应答write_byte(0x03);//内部存储地址response();write_byte(0x55);//写入真正意义上的数据response();//等待应答stop();//停止读取数据信号delay1(500);//毫秒延时//第一部分结束,写入EEPROM器件AT24C16数据start();write_byte(0xa0);//申明所读器件地址response();write_byte(0x03);//申明该器件中所要求读数据的位置response();start();write_byte(0xa1);response();P0=read_byte();//进行读数据操作后,非应答,budaixingcan,而是将返回值直接赋予变量stop();//第二部分内容;读即操作理解为,主机对器件写;告诉从机我要对你进行读操作,所以先写,后读while(1);//将程序终止于此}。
单片机EEPROM读写数据流程解析EEPROM 写数据流程第一步,首先是I2C 的起始信号,接着跟上首字节,也就是我们前边讲的I2C 的器件地址,并且在读写方向上选择“写”操作。
第二步,发送数据的存储地址。
24C02 一共256 个字节的存储空间,地址从0x00~0xFF,我们想把数据存储在哪个位置,此刻写的就是哪个地址。
第三步,发送要存储的数据第一个字节、第二个字节??注意在写数据的过程中,EEPROM 每个字节都会回应一个“应答位0”,来告诉我们写EEPROM 数据成功,如果没有回应答位,说明写入不成功。
在写数据的过程中,每成功写入一个字节,EEPROM 存储空间的地址就会自动加1,当加到0xFF 后,再写一个字节,地址会溢出又变成了0x00。
EEPROM 读数据流程第一步,首先是I2C 的起始信号,接着跟上首字节,也就是我们前边讲的I2C 的器件地址,并且在读写方向上选择“写”操作。
这个地方可能有同学会诧异,我们明明是读数据为何方向也要选“写”呢?刚才说过了,24C02 一共有256 个地址,我们选择写操作,是为了把所要读的数据的存储地址先写进去,告诉EEPROM 我们要读取哪个地址的数据。
这就如同我们打电话,先拨总机号码(EEPROM 器件地址),而后还要继续拨分机号码(数据地址),而拨分机号码这个动作,主机仍然是发送方,方向依然是“写”。
第二步,发送要读取的数据的地址,注意是地址而非存在EEPROM 中的数据,通知EEPROM 我要哪个分机的信息。
第三步,重新发送I2C 起始信号和器件地址,并且在方向位选择“读”操作。
这三步当中,每一个字节实际上都是在“写”,所以每一个字节EEPROM 都会回应一个“应答位0”。
第四步,读取从器件发回的数据,读一个字节,如果还想继续读下一个字节,就发送一个“应答位ACK(0)”,如果不想读了,告诉EEPROM,我不想要数据了,别再发数据了,那就发送一个“非应答位NAK(1)”。
此文档共包含三个程序。
第一个程序最简单易懂,看懂了基本就会读写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; //按钮1sbit K2 = P3^3; //按钮2void 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_DATAEA = 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/IAPreturn 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; //按钮1sbit K2 = P3^3; //按钮2void 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 P0sbit 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 1uchar 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写入2xcx(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");}elseLCDWrite_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操作时的地址寄存器高八位。