打印

模块化的EEPROM的循环利用管理程序

[复制链接]
3865|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
农民讲习所|  楼主 | 2007-6-15 15:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
重复循环利用整个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 );
        }
    }
}

相关帖子

沙发
古道热肠| | 2007-6-15 15:32 | 只看该作者

好东西,先保留一份

  循环使用EEPROM或FLash有实用价值,也许哪天用得着,大家都备份吧!

使用特权

评论回复
板凳
gyt| | 2007-6-15 16:01 | 只看该作者

好办法

值得推广!

使用特权

评论回复
地板
hotpower| | 2007-6-15 23:49 | 只看该作者

~~~

使用特权

评论回复
5
makesoft| | 2007-6-16 00:34 | 只看该作者

好东西

不过CODE资源开销有点大

使用特权

评论回复
6
lixun00| | 2007-6-18 10:38 | 只看该作者

不错,不知和随机比哪个更好,但代码肯定更大

使用特权

评论回复
7
people12| | 2008-1-28 14:34 | 只看该作者

你的东西被你洗掉拉!!

 if( ( k == FLAG_LOCK ) || ( k == FLAG_EMPTYRECORD ) )
        {
            //找到空记录,倒推最后一个记录位置
            j = i;
            do{
                i = InEDataBase_RecordIdDec( i );
                k = READRECORDFLAG(i);
                if( k == FLAG_VALIDRECORD ){
                    //找到最近的有效数据???
你大概是循环检视反复记录的程序!!!
你在好好想想???

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

1275

帖子

15

粉丝