📄 eepdemo.c
字号:
/*========================================================================
IAP操作使用片内flash作为eeprom使用的驱动程序。参考来源:www.mcu-memory.com
本演示代码通过对用户数据的读写操作,具体实现数据存储的组织方法,最大限度的
利用eeprom的空间。这只是对eeprom进行分配轮换使用的一种方法。
实现分配的思路:用户数组(需要记忆的部分)应该在4,8,16,32,64等字节以内,将第
一字节留作索引头:如果读到该字节为0x55(也可以定义为其他数),则认为已经找到
了有效的最后纪录,将本小区域数据读出。如果不是则继续跳到下一个小区域继续上
述操作,直到找到上一次的纪录为止,如果超出了eeprom的有效范围还没有找到,则
认为这是一块新的芯片,将默认的数据写入。
保存的时候,首先将刚才读到的那个数组的对应eeprom中的第一字节清零,以便下次
跳过,然后再推后一个小区域(记录长度),将数据写入。如果出现写入失败,接着到
再下一个区域,直到写入正确为止。
这里有一个问题就是,写到下一个小区域的时候会遇到跨扇区,只要判断出跨区,就
将上一个扇区擦除,以备下一轮循环再使用。
程序利用stc提供的下载板上的LED显示当前读或者写的地址,你可以看到led的"递减"
过程,演示读写256次,从第一次的全亮,到演示完毕也全亮,刚好256次。如果中途
断电,即会出现不同的结果,但再进行完演示的话,会发现结束时的led状态与开始
时的一样,否则就说明你的芯片内部eeprom有损坏。
演示代码仅针对stc89c54rd+/51rc进行了调试,但可以给其他芯片编程时作为参考。
晓奇工作室 http://www.xiao-qi.com/
---- xiaoqi 2005.12
======================================================================= */
//#include "src51rd.h"
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
/* STC89C54RD+的flash空间从0x4000~0xf3ff 共90个扇区,每扇区512字节 */
// #define BaseAddr 0x1000 /* 51rc */
// #define EndSectoraddr 0x3d00 /* 51rc */
// #define EndAddr 0x3fff /* 51rc 12K eeprom */
#define BaseAddr 0x4000
#define EndSectoraddr 0xf200
#define EndAddr 0xf3ff
/* ------------- 定义扇区大小 ------------- */
#define PerSector 512
/* 用户程序需要记忆的数组, 用户实际使用了n-1个数据,数组长度规整到
2 4 8 16 32 64 上 */
uchar Ttotal[16] =
{
0x55, /* 作为判别引导头使用,用户程序请不要修改它 */
/* 用户保存记忆的数据 */
0x01, /* 用途说明....*/
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e,
0x0f,
};
uint timerForDelay, /* 专供延时用的变量 */
i, /* 循环变量 */
EepromPtr; /* eeprom读写指针 */
/* ======================= IAP外部函数列表 =======================*/
/* 扇区擦除 */
extern void SectorErase(uint sector_addr);
/* byte 读 */
extern uchar byte_read(uint byte_addr);
/* byte 写 */
extern void byte_write(uint byte_addr, uchar original_data);
/* byte写并校验 */
extern uchar byte_write_verify(uint byte_addr, uchar original_data);
/* byte数组写并校验 */
extern uchar ArrayWrite(uint begin_addr, uint len, uchar *array);
/* byte数组读, 存在Ttotal[] */
extern void ArrayRead(uint begin_addr, uchar len);
/* ============================ 延时 ========================= */
void delayeeprom(uint counter)
{
timerForDelay = counter;
while(timerForDelay);
}
/* ==============================================================
初始化开启定时器2,定时周期设定为10mS(下载板上 18.432M 晶振)
============================================================== */
void initCT2()
{
/* 时钟倍频时用 0x8800*/
RCAP2H = 0xc4;
RCAP2L = 0x00;
TH2 = 0xc4; // 定时器初值
TL2 = 0x00;
ET2 = 1; // 允许T2中断
T2CON = 4; // 自动重装的定时器
TR2 = 1; // 启动
EA = 1;
}
/* ==============================================================
定时器CT2中断服务程序
============================================================== */
void timer2Int(void) interrupt 5
{
TF2 = 0; /* 溢出标志必须由软件清零*/
EXF2 = 0; /* 捕获标志必须由软件清零*/
if(timerForDelay)timerForDelay--; /* 定时变量处理 */
}
/* ==============================================================
从eeprom中读取数据
============================================================== */
void DataRestore()
{
EepromPtr = BaseAddr; /* 指向eeprom的起始点 */
while(EepromPtr < EndAddr) /* 在eeprom的可用区域内 */
{
if(byte_read(EepromPtr) == 0x55)/* 找到了上一次有效纪录 */
{
break; /* 寻找完成 */
}
EepromPtr += 0x10; /* 指向下一个小区 */
}
if(EepromPtr >= EndAddr) /* 如果照遍都没有,是新片*/
{
EepromPtr = BaseAddr; /* 指向eeprom的起始点 */
for(i=0;i<90;i++)
{
SectorErase(EepromPtr+0x200*i); /* 全部扇区擦除 */
}
while(ArrayWrite(EepromPtr, 0x10, Ttotal)) /* 写默认值 */
{ /* 写入失败才运行的部分 */
byte_write(EepromPtr, 0); /* 该单元已经失效 */
if(EepromPtr < EndAddr)
{
EepromPtr += 0x10; /* 换一块新的小区 */
}
else
{
P1=0; /* 指示芯片内eeprom全坏 */
EA= 0; /* 不再做任何事 */
while(1); /* 死机 */
}
}
}
ArrayRead(EepromPtr, 16);
}
/* ==============================================================
将需要记忆的数据保存到eeprom
============================================================== */
void DataSave()
{
uint wrPtr; /* 临时指针 */
NextArea:
byte_write_verify(EepromPtr, 0); /* 将原来的标记清除 */
wrPtr = EepromPtr & 0xfe00; /* 上一个扇区的起始地址 */
EepromPtr += 0x10; /* 目标存入地址 */
/* ------------------ 判断是否启用新的扇区 ---------------- */
if((EepromPtr & 0x1ff)==0)
{
SectorErase(wrPtr); /* 将上一个扇区擦除,备用 */
if(EepromPtr>=EndAddr) /* 已经用完了最后一个区域 */
{
EepromPtr = BaseAddr; /* 从头开始 */
}
}
/* -------------------- 数据存入前的准备 ------------------ */
/* 。。。。。。。。。。。。。。转移、处理 */
Ttotal[0] = 0x55; /* 重申启用标记 */
if(ArrayWrite(EepromPtr, 0x10, Ttotal))
{ /* 数据写入,如果有错换一块 */
goto NextArea;
}
}
/* ================================================================
储存于读取的反复测试,每个小区域16字节,每个扇区512字节,即每个
扇区分成32个小块,每次写入顺序往后移动一个小区域,进行256次读写操作
实际上跨越了8个扇区。
按照51rc 12K eeprom计算,可以反复纪录7680万次
按照52rc 8K eeprom计算,可以反复纪录3840万次
按照54rd+45K eeprom计算,可以反复纪录2.88亿次
足够系统对记忆体的要求。
================================================================ */
void saveread()
{
// P1 = 0xff; /* 所有LED熄灭 */
initCT2(); /* CT2初始化,用来做定时器 */
/* ------------------ 演示 256 次读写操作 ----------------- */
for(i=0;i<256;i++)
{
DataRestore(); /* 从eeprom中读取记忆数据 */
P1 = (uchar)((EepromPtr >> 4) & 0xff); /* 显示读取地址 */
delayeeprom(50); /* 延时保留显示状态1秒 */
DataSave(); /* 数据再次保存 */
P1 = (uchar)((EepromPtr >> 4) & 0xff); /* 显示写入地址 */
delayeeprom(20); /* 延时保留显示状态1秒 */
}
while(1); /* 演示完毕 */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -