利用89C52RC的DATAFLASH实现掉电存储数据

来源:互联网 发布:淘宝店铺代理 编辑:程序博客网 时间:2024/05/18 09:34

以下蓝色字转自

http://xouou.iteye.com/blog/1815427

STC单片机的内部EEPROM是用DATAFLASH模拟出来的,不是真正的EEPROM存储器,不能用普通的方法来操作
下面是一些注意点:
1.字节写之前要先将这个字节所在扇区的其它有效数据读取到RAM暂存(这步不是必须的)
2.暂存完之后再对整个扇区(512字节)进行擦除操作,擦拭完后,整个扇区每个地址中数据都变成0xFF
3.将欲写入的N个字节数据,用字节写函数写入EEPROM
4.将暂存到RAM的其它有用的EEPROM值再用字节写函数写回EEPROM
5.STC用FLASH模拟出来的EEPROM的字节写功能只能将1变成0,而不能将0变成1,
  只有扇区擦除后数据才是全1,
  例如:在地址0x21f0处第1次写11010110,第2次写111010,读出结果是这2个值的相与10010
         所以如果一个地址处的值不是0xff时写入新的数据是不对的,要先执行扇区擦除,变为0xff,
         对于单个字节的写入,我们可以先检查该地址处的数据是否为0xff,是的话就不用擦除扇区了

----------------------------------------------------------------------
STC89C52单片机内部EEPROM 的读写过程
1  配置ISP_CONTR寄存器,使能第7位ISPEN,让ISP_IAP功能生效,并配置低3位的等待时间
2  写指令: 读/写/擦除扇区 这3个命令
3  赋值: ISP_ADDRH和ISP_ADDRL的地址值
4  关闭总中断EA,因为下面要写的2个触发指令必须是连续操作的,不能被中断
5  执行公用的  ISP_IAP 触发指令,触发后读写操作才能进行
6  打开中断 EA, 关闭ISP_IAP功能:清相关寄存器


测试时请不要长时间用while读写flash,因为该区域读写次数有限(虽然次数很大,但是也经受不了长时间的while),可以做一个掉电检测单元,掉电检测单元是检测到电压小与处理器工作电压时还能短时间供电的电路,还得用二极管、电感将单片机的数字部分隔离出来,在主电源掉电之后切断模拟电路。用很大的电容(2200uF)来进行短暂的供电,然后把数据保存到EEPROM。废话不多说,上个测试代码(通过记忆流水灯最后熄灭的状态来进行测试),测试通过:

#include<reg52.h>#include<intrins.h>#include<math.h>typedef unsigned char    UINT8;typedef unsigned int     UINT16;typedef unsigned long    UINT32;typedef char             INT8;typedef int              INT16;typedef long             INT32;#define NOP()            _nop_()#define EEPROM_START_ADDRESS 0x2000#define LED_PORT         P1 sfr ISP_DATA =   0xe2;sfr ISP_ADDRH =   0xe3; sfr ISP_ADDRL =   0xe4;sfr ISP_CMD =   0xe5; sfr ISP_TRIG =   0xe6;   sfr ISP_CONTR =   0xe7;void DelayNus(UINT16 t){UINT16 d=0;d=t;do{NOP();}while(--d>0);}void DelayNms(UINT16 t){do{DelayNus(1000);}while(--t>0);}void EEPROMEnable(void){ISP_CONTR=0x81;}void EEPROMDisable(void){ISP_CONTR=0x00;ISP_CMD=0x00;ISP_TRIG=0x00;ISP_ADDRH=0x00;ISP_ADDRL=0x00;}void EEPROMSetAddress(UINT16 addr){addr+=EEPROM_START_ADDRESS;ISP_ADDRH=(UINT8)(addr>>8);ISP_ADDRL=(UINT8)addr;}void EEPROMStart(){ISP_TRIG=0x46;ISP_TRIG=0xB9;}UINT8 EEPROMReadByte(UINT16 addr){//ISP_DATA=0x00;ISP_CMD=0x01;EEPROMEnable();EEPROMSetAddress(addr);EEPROMStart();DelayNus(10);EEPROMDisable();return(ISP_DATA);}void EEPROMWriteByte(UINT16 addr,UINT8 byte){EEPROMEnable();ISP_CMD=0x02;EEPROMSetAddress(addr);ISP_DATA=byte;EEPROMStart();DelayNus(60);EEPROMDisable();}void EEPROMSectorErase(UINT16 addr){ISP_CMD=0x03;EEPROMEnable();EEPROMSetAddress(addr);EEPROMStart();DelayNms(10);EEPROMDisable();}/*********毫秒延时程序**************/void Delay1ms(unsigned int count){unsigned int ac,jc;for(ac=0;ac<count;ac++)for(jc=0;jc<120;jc++);}/***********************************/    void main(void){UINT8 i=0xff;UINT8 j=0;//EEPROMSectorErase(0);//EEPROMWriteByte(0,i);j=EEPROMReadByte(0);LED_PORT=j;Delay1ms(1000);Delay1ms(1000);while(1){i = i-1;if(i == 0x00)i = 0xff;EEPROMSectorErase(0);EEPROMWriteByte(0,i);j=EEPROMReadByte(0);LED_PORT=j;Delay1ms(1000);}}


1 0
原创粉丝点击