重复循环利用整个EEPROM区域进行写,巧妙建立默认的索引。外部EEPROM操作接口可实现模块化,可单独建库。完善的写保护机制。 设计思想可参考《建立MCU通用程序》一贴。
//-------------------------------------------------------- //EEPROM方式的数据管理 //特征字: // 0xff 空记录 // 0xf0 写锁标志 // 0xf3 有效记录 // 0x0 坏记录 //-------------------------------------------------------- #include "....SystemCom.h" #include "....SystemMemory.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 ); } } }
|