重复循环利用整个EEPROM区域进行写,巧妙建立默认的索引。外部EEPROM操作接口可实现模块化,可单独建库。完善的写保护机制。
设计思想可参考《建立MCU通用程序》一贴。
//--------------------------------------------------------
//EEPROM方式的数据管理
//特征字:
// 0xff 空记录
// 0xf0 写锁标志
// 0xf3 有效记录
// 0x0 坏记录
//--------------------------------------------------------
#include "..\..\System\Com.h"
#include "..\..\System\Memory.h"
#define FLAG_EMPTYRECORD 0xff //空记录
#define FLAG_LOCK 0xf0 //写锁标志
#define FLAG_VALIDRECORD 0xf3 //有效记录
#define FLAG_BADRECORD 0x0 //坏记录区
struct EDataBase{
U8 *pRecordBuffer; //记录缓冲区开始指针
};
struct EDataBase sEDataBase;
struct InEDataBase{
U8 mRecordByteSize; //记录大小,比记录缓冲区大1个字节。(特征字节)
bool bWriteRequ; //写请求
U8 *pWriteBuffer; //写EEPROM的数据缓冲区
bool bWriteBusy;
U8 mWriteTask; //写任务号
U16 mEepromStartLocation; //在Eeprom存储起始地址
U16 mEepromEndLocation; //在Eeprom存储结束地址
U16 mCurrentRecordLocation; //当前数据存储所在位置
U16 mTemp;
U8 (*pfEeprom)( U8 mCmd, U16 mId, U8 mData ); //EEPROM操作函数指针
};
struct InEDataBase sInEDataBase;
#define this sInEDataBase
enum EepromCmd{
eReadU8,
eWriteU8,
eReadBusy,
};
#define Eeprom_ReadU8(mId) (*this.pfEeprom)(eReadU8, mId, NULL)
#define Eeprom_WriteU8(mId,mData) do{ (*this.pfEeprom)(eWriteU8, mId, mData);}while(0)
#define Eeprom_ReadBusy() (*this.pfEeprom)(eReadBusy, NULL, NULL)
#define READRECORDFLAG(mId) Eeprom_ReadU8( InEDataBase_FlagLocation(mId) )
#define WRITERECORDFLAG(mId, mData) Eeprom_WriteU8( InEDataBase_FlagLocation(mId), mData )
//--------------------------------------------------------
//得到特征字位置
//入口:记录的起始位置
//--------------------------------------------------------
U16 InEDataBase_FlagLocation( U16 mRecordLocation )
{
return mRecordLocation + this.mRecordByteSize - 1;
}
//--------------------------------------------------------
//记录号+1
//返回+1后的记录号
//--------------------------------------------------------
U16 InEDataBase_RecordIdInc( U16 mId )
{
mId += this.mRecordByteSize;
if( mId >= this.mEepromEndLocation ){
mId = this.mEepromStartLocation;
}
return mId;
}
//--------------------------------------------------------
//记录号-1
//返回-1后的记录号
//--------------------------------------------------------
U16 InEDataBase_RecordIdDec( U16 mId )
{
if( mId < (U16)(this.mEepromStartLocation + this.mRecordByteSize) )
{
mId = this.mEepromEndLocation - this.mRecordByteSize;
}
else {
mId -= this.mRecordByteSize;
}
return mId;
}
//--------------------------------------------------------
//读出数据到缓冲
//--------------------------------------------------------
void InEDataBase_ReadBuffer( void )
{
U8 i = this.mRecordByteSize;
U16 mLocation = this.mCurrentRecordLocation;
U8 *pRecordBuffer = sEDataBase.pRecordBuffer;
while( --i ){
*pRecordBuffer++ = Eeprom_ReadU8( mLocation++ );
}
}
//--------------------------------------------------------
//初始化
//入口:记录字节个数, Eeprom起始地址,Eeprom大小(字节), Eeprom函数操作指针
//--------------------------------------------------------
void EDataBase_Init( U8 mRecordByteSize, U16 mEepromStartLocation, U16 mEepromSize, U8 (*pfEeprom)( U8 mCmd, U16 mId, U8 mData ) )
{
U16 i,j;
U8 k;
Memory_Memset( (U8 *)&this, 0, sizeof(struct InEDataBase) );
sEDataBase.pRecordBuffer = Memory_Malloc( mRecordByteSize );
mRecordByteSize++;
this.pWriteBuffer = Memory_Malloc( mRecordByteSize );
this.mRecordByteSize = mRecordByteSize;
this.pfEeprom = pfEeprom;
this.mEepromStartLocation = mEepromStartLocation;
this.mEepromEndLocation = mEepromStartLocation + mEepromSize - (mEepromSize % mRecordByteSize);
//重建索引
i = this.mEepromStartLocation;
//必定有个空记录
while( i < this.mEepromEndLocation )
{
k = READRECORDFLAG(i);
if( ( k == FLAG_LOCK ) || ( k == FLAG_EMPTYRECORD ) )
{
//找到空记录,倒推最后一个记录位置
j = i;
do{
i = InEDataBase_RecordIdDec( i );
k = READRECORDFLAG(i);
if( k == FLAG_VALIDRECORD ){
//找到最近的有效数据
goto l_LocationFirst;
}
}
while( i!= j );
//没有任何有效数据
i = this.mEepromStartLocation;
goto l_LocationFirst;
}
else {
//继续到下个记录
i = InEDataBase_RecordIdInc( i );
}
}
//无任何数据
i = this.mEepromStartLocation;
l_LocationFirst:
this.mCurrentRecordLocation = i;
//读出数据到缓冲
InEDataBase_ReadBuffer();
}
//--------------------------------------------------------
//写数据存储进EEPROM
//--------------------------------------------------------
void EDataBase_FlushBuffer( void )
{
this.bWriteRequ = true;
}
//--------------------------------------------------------
//循环
//--------------------------------------------------------
void EDataBase_Loop( void )
{
if( this.bWriteBusy && ( Eeprom_ReadBusy() == false ) ){
//检查是否写完
switch( this.mWriteTask ){
case 0: //擦除新记录区,首先找到有效空块
this.mCurrentRecordLocation = InEDataBase_RecordIdInc( this.mCurrentRecordLocation );
if ( READRECORDFLAG( this.mCurrentRecordLocation ) == FLAG_BADRECORD )
{
//是处于坏块上,退出,下次进入时到下个记录位置
break;
}
this.mTemp = this.mCurrentRecordLocation;
this.mWriteTask = 1;
break;
case 1: //擦除当前有效空块后的空块,保证当前有效空块写入数据后至少有一个有效空块.(初始建立索引需要)
this.mTemp = InEDataBase_RecordIdInc( this.mTemp );
if ( READRECORDFLAG( this.mTemp ) == FLAG_BADRECORD )
{
//是处于坏块上,退出,下次进入时到下个记录位置
break;
}
//写空区标志
WRITERECORDFLAG( this.mTemp, FLAG_EMPTYRECORD );
this.mWriteTask = 2;
break;
case 2: //检查是否空区建立
if ( READRECORDFLAG( this.mTemp ) != FLAG_EMPTYRECORD )
{
//失败
WRITERECORDFLAG( this.mTemp, FLAG_BADRECORD );
this.mWriteTask = 1;
break;
}
else {
//开始写数据.首先锁标志
WRITERECORDFLAG( this.mCurrentRecordLocation, FLAG_LOCK );
this.mWriteTask = 3;
}
break;
case 3:
if ( READRECORDFLAG( this.mCurrentRecordLocation ) != FLAG_LOCK )
{
//失败
WRITERECORDFLAG( this.mCurrentRecordLocation, FLAG_BADRECORD );
this.mWriteTask = 0;
}
else {
//开始写数据
this.mTemp = 0;
this.mWriteTask = 4;
}
break;
case 4: //写全部数据
Eeprom_WriteU8( this.mTemp + this.mCurrentRecordLocation, this.pWriteBuffer[ this.mTemp ] );
if( ++this.mTemp == (this.mRecordByteSize - 1) ){
//写完数据
this.mWriteTask = 5;
}
break;
case 5: //校验数据
this.mTemp = 0;
while( this.mTemp != (this.mRecordByteSize - 1) )
{
if( this.pWriteBuffer[ this.mTemp ] != Eeprom_ReadU8( this.mTemp + this.mCurrentRecordLocation ) )
{
//失败
WRITERECORDFLAG( this.mTemp, FLAG_BADRECORD );
this.mWriteTask = 0;
break;
}
this.mTemp++;
}
this.mWriteTask = 6;
break;
case 6: //写完成标志
WRITERECORDFLAG( this.mCurrentRecordLocation, FLAG_VALIDRECORD );
this.mWriteTask = 7;
break;
case 7: //校验写完成标志
if( READRECORDFLAG( this.mCurrentRecordLocation ) != FLAG_VALIDRECORD )
{
//标志错误,失败
WRITERECORDFLAG( this.mTemp, FLAG_BADRECORD );
this.mWriteTask = 0;
break;
}
else {
//完成
this.bWriteBusy = false;
}
break;
}
}
else {
//空闲下检查是否有写请求
if( this.bWriteRequ == true ){
//开始写
this.mWriteTask = 0;
this.bWriteRequ = false;
this.bWriteBusy = true;
Memory_MemCopy( this.pWriteBuffer, sEDataBase.pRecordBuffer, this.mRecordByteSize - 1 );
}
}
}
文章评论(0条评论)
登录后参与讨论