编译环境:WinAVR-20060421+AVRStudio4.12.498ServicePack4
EEPROMSave.h文件:
/*EEPROM管理定义*/
#defineEepromPageSize 64 //页容量定义
#defineEepromPage0Addr 0x0000 //各个页的其始地址定义
#defineEepromPage1Addr (EepromPage0Addr+EepromPageSize)
#defineEepromPage2Addr (EepromPage1Addr+EepromPageSize)
#defineEepromPage3Addr (EepromPage2Addr+EepromPageSize)
#defineEepromPage4Addr (EepromPage3Addr+EepromPageSize)
#defineEepromPage5Addr (EepromPage4Addr+EepromPageSize)
#defineEepromPage6Addr (EepromPage5Addr+EepromPageSize)
#defineEepromPage7Addr (EepromPage6Addr+EepromPageSize)
/*
最后两个字节为CRC16校验码,其余为数据
|0|1|2| |.......................|61|62|63|
Data Data...................Data.....CRCHCRCL
*/
#defineVALID 0x01
#defineINVALID 0x00
/*-----------------------------------------------------------------------------------------*/
EEPROMSave.c文件:
/*******************************************************************
*函数名称:EepromReadByte()
*函数功能:写一个Byte的数据进EEPROM
*输入参数:address:地址
*返回参数:从指定地址读出来的数据
*编写作者:my_avr
*编写时间:2007年8月13日
*相关说明:
********************************************************************/
unsignedcharEepromReadByte(unsignedchar*address)
{
unsignedchardata;
data=0;
eeprom_busy_wait();
data=eeprom_read_byte(address);
returndata;
}
/*******************************************************************
*函数名称:EepromReadWord();
*函数功能:写一个Word的数据进EEPROM
*输入参数:address:地址
*返回参数:从指定地址读出来的数据
*编写作者:my_avr
*编写时间:2007年8月13日
*相关说明:
********************************************************************/
uint16_tEepromReadWord(uint16_t*address)
{
uint16_tdata;
data=0;
eeprom_busy_wait();
data=eeprom_read_word(address);
returndata;
}
/*******************************************************************
*函数名称:EepromWriteByte()
*函数功能:写一个Byte的数据进EEPROM
*输入参数:address:地址;data:数据
*返回参数:无
*编写作者:my_avr
*编写时间:2007年8月13日
*相关说明:
********************************************************************/
voidEepromWriteByte(unsignedchar*address,unsignedchardata)
{
eeprom_busy_wait();
eeprom_write_byte(address,data);
}
/*******************************************************************
*函数名称:EepromWriteWord()
*函数功能:写一个Word的数据进EEPROM
*输入参数:address:地址;data:数据
*返回参数:
*编写作者:my_avr
*编写时间:2007年8月13日
*相关说明:
********************************************************************/
voidEepromWriteWord(unsignedint*address,unsignedintdata)
{
eeprom_busy_wait();
eeprom_write_word(address,data);
}
/*******************************************************************
*函数名称:EepromWriteBlock()
*函数功能:将缓冲区中的n个数据写进EEPROM
*输入参数:address:地址;data:数据
*返回参数:
*编写作者:my_avr
*编写时间:2007年8月13日
*相关说明:
********************************************************************/
voidEepromWriteBlock(unsignedchar*buff,unsignedchar*address,unsignedcharn)
{
unsignedchari;
for(i=0;i<n;i++)
{
EepromWriteByte((unsignedchar*)(address+i),*buff);
buff++;
}
}
/******************************************************************
*函数名称:unsignedcharEepromCheck(unsignedchar*pdata,unsignedcharpacksize)
*函数功能:检查EEPROM的数据是否有效,采用CRC16校验技术。
一次校验默认最后两个字节为校验码,
需要注意,packsize包括数据长度和校验码字节
*输入参数:pdata:数组指针;packsize:数据长度
*返回参数:数据是否有效,有效:VALID,无效:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关说明:
********************************************************************/
unsignedcharEepromCheck(unsignedchar*pdata,unsignedcharpacksize)
{
unsignedchari,j;
unsignedintcrc,ref_crc;
crc=0;
ref_crc=0;
for(i=0;i<(packsize-2);i++)
{
crc=crc^((uint16_t)EepromReadByte(pdata)<<8);
for(j=0;j<8;j++)
{
if(crc&0x8000)
{
crc=(crc<<1)^0x1021;
}
else
{
crc=crc<<1;
}
}
pdata++;
}
ref_crc=(uint16_t)EepromReadByte(pdata);
ref_crc=ref_crc<<8;
pdata++;
ref_crc|=(uint16_t)EepromReadByte(pdata);
if(crc==ref_crc)
{
returnVALID;
}
else
{
returnINVALID;
}
}
/*******************************************************************
*函数名称:unsignedcharCheckWriteCRC(unsignedchar*pdata,unsignedcharpacksize)
*函数功能:为EEPROM数据写CRC校验码
*输入参数:pdata:数组指针;packsize:数据长度
*返回参数:操作成功否?,成功:VALID,失败:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关说明:
********************************************************************/
unsignedcharCheckWriteCRC(unsignedchar*pdata,unsignedcharpacksize)
{
unsignedchari,j;
unsignedintcrc;
crc=0;
for(i=0;i<(packsize-2);i++)
{
crc=crc^((uint16_t)EepromReadByte(pdata)<<8);
for(j=0;j<8;j++)
{
if(crc&0x8000)
{
crc=(crc<<1)^0x1021;
}
else
{
crc=crc<<1;
}
}
pdata++;
}
EepromWriteByte(pdata,(uint8_t)(crc>>8));
pdata++;
EepromWriteByte(pdata,(uint8_t)crc);
pdata++;
if(EepromCheck((pdata-packsize),packsize))
{
returnVALID;
}
else
{
returnINVALID;
}
}
/********************************************************************
*函数名称:unsignedcharCheckAllPage(void)
*函数功能:检查EEPROM数据是否有效,检查三个备份
*输入参数:无
*返回参数:操作成功否?,成功:VALID,失败:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关说明:
********************************************************************/
uint8_tCheckAllPage(void)
{
if((EepromCheck((unsignedchar*)EepromPage1Add,EepromPageSize)==VALID)
&&(EepromCheck((unsignedchar*)EepromPage2Add,EepromPageSize)==VALID)
&&(EepromCheck((unsignedchar*)EepromPage3Add,EepromPageSize)==VALID))
{
returnVALID;
}
returnINVALID;
}
/*******************************************************************
*函数名称:unsignedcharDataRecover(void)
*函数功能:检查EEPROM数据是否被破坏,如果被破坏了,作数据恢复
*输入参数:无
*返回参数:操作成功否?,成功:VALID,失败:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关说明:
********************************************************************/
uint8_tDataRecover(void)
{
unsignedchari;
unsignedchartemp;
unsignedcharpage;
unsignedintinvalidpage[3];
unsignedintvalidpage;
invalidpage[0]=0;
invalidpage[1]=0;
invalidpage[2]=0;
validpage=0;
temp=0;
page=0;
if(EepromCheck((uint8_t*)EepromPage1Add,EepromPageSize)==VALID)
{
validpage=EepromPage1Add;
}
else
{
invalidpage[page]=EepromPage1Add;
page++;
}
if(EepromCheck((uint8_t*)EepromPage2Add,EepromPageSize)==VALID)
{
validpage=EepromPage2Add;
}
else
{
invalidpage[page]=EepromPage2Add;
page++;
}
if(EepromCheck((uint8_t*)EepromPage3Add,EepromPageSize)==VALID)
{
validpage=EepromPage3Add;
}
else
{
invalidpage[page]=EepromPage3Add;
page++;
}
if(page==3) //三个备份都被破坏了
{
returnINVALID; //数据完全无效了
}
while((page--)>0) //数据恢复
{
for(i=0;i<EepromPageSize;i++)
{
temp=EepromReadByte((uint8_t*)(validpage+i));
EepromWriteByte((uint8_t*)(invalidpage[page]+i),temp);
}
}
if(CheckAllPage()==VALID)
{
returnVALID;
}
returnINVALID;
}
使用方法(三个备份):
1、定义一个数组:EEPROMData[EepromPageSize-2],数组定义为EepromPageSize-2是为了给每个备份留2个字节的校验
2、要保存数据时,先把数据放到数组中,然后调用EepromWriteBlock()函数,把这个数组的数据写进EEPROM,三个备份要写三次。
3、写完了之后,调用CheckWriteCRC()函数,该函数会计算出当前备份的CRC16检验数据并写到EEPROM备份的尾部,有多少个备份就要调用多少次。
4、至此,数据的备份工作已经完成。
5、校验数据(一般在复位后运行),执行CheckAllPage()函数,若通过了,则EEPROM数据没有问题,否则要运行DataRecover()函数,对损坏的备份进行修复
------------------修改原因:修改变量的定义形式