(玩电子) 电子手艺学习与研究

治标治标,完全处置赏罚赏罚AVR单片机EEPROM数据损掉落效果

作者:刘温电   泉源:本站原创   点击数:x  更新时间:2013年11月26日   【字体:年夜

编译情形:WinAVR-20060421 + AVR Studio 4.12.498  Service Pack 4


基本思绪:每份写到EEPRM的数据,都做三个备份,每个备份的数据都做CRC16校验,只需系统运转中掉落足,弱点地修改了EEPROM数据,
          那么凭证校验字节就知道哪个备份的数据被修改了,然后用准确的备份笼罩掉落足的备份,到达数据恢复的目的。


EEPROMSave.h 文件:

/*   EEPROM治理界说   */

#define EepromPageSize 64 //页容量界说

#define EepromPage0Addr 0x0000 //各个页的其始地址界说
#define EepromPage1Addr (EepromPage0Addr + EepromPageSize)
#define EepromPage2Addr (EepromPage1Addr + EepromPageSize)
#define EepromPage3Addr (EepromPage2Addr + EepromPageSize)
#define EepromPage4Addr (EepromPage3Addr + EepromPageSize)
#define EepromPage5Addr (EepromPage4Addr + EepromPageSize)
#define EepromPage6Addr (EepromPage5Addr + EepromPageSize)
#define EepromPage7Addr (EepromPage6Addr + EepromPageSize)

/*
最后两个字节为CRC16校验码,其他为数据

| 0 | 1 | 2 | |.......................| 61 | 62 | 63 |
Data       Data...................Data.....CRCH CRCL
*/

#define VALID 0x01
#define INVALID 0x00

/*-----------------------------------------------------------------------------------------*/

EEPROMSave.c 文件:

/*******************************************************************
*函数称谓:EepromReadByte()
*函数功效:写一个Byte的数据进EEPROM
*输入参数:address:地址
*前往参数:从指定地址读出来的数据
*编写作者:my_avr
*编写时间:2007年8月13日
*相关诠释:
********************************************************************/
unsigned char EepromReadByte(unsigned char *address)
{
unsigned char data;

data = 0;

eeprom_busy_wait();
data  = eeprom_read_byte(address);

return data;
}

/*******************************************************************
*函数称谓:EepromReadWord();
*函数功效:写一个Word的数据进EEPROM
*输入参数:address:地址
*前往参数:从指定地址读出来的数据
*编写作者:my_avr
*编写时间:2007年8月13日
*相关诠释:
********************************************************************/
uint16_t EepromReadWord(uint16_t *address)
{
uint16_t data;

data = 0;

eeprom_busy_wait();
data  = eeprom_read_word(address);

return data;
}

/*******************************************************************
*函数称谓:EepromWriteByte()
*函数功效:写一个Byte的数据进EEPROM
*输入参数:address:地址;data:数据
*前往参数:无
*编写作者:my_avr
*编写时间:2007年8月13日
*相关诠释:
********************************************************************/
void EepromWriteByte(unsigned char *address,unsigned char data)
{
eeprom_busy_wait();
eeprom_write_byte(address,data);
}

/*******************************************************************
*函数称谓:EepromWriteWord()
*函数功效:写一个Word的数据进EEPROM
*输入参数:address:地址;data:数据
*前往参数:
*编写作者:my_avr
*编写时间:2007年8月13日
*相关诠释:
********************************************************************/
void EepromWriteWord(unsigned int *address,unsigned int data)
{
eeprom_busy_wait();
eeprom_write_word(address,data);
}

/*******************************************************************
*函数称谓:EepromWriteBlock()
*函数功效:将缓冲区中的n个数据写进EEPROM
*输入参数:address:地址;data:数据
*前往参数:
*编写作者:my_avr
*编写时间:2007年8月13日
*相关诠释:
********************************************************************/
void EepromWriteBlock(unsigned char *buff,unsigned char *address,unsigned char n)
{
unsigned char i;

for (i = 0; i < n; i++)
{
EepromWriteByte((unsigned char *)(address + i),*buff);

buff++;
}
}

/******************************************************************
*函数称谓:unsigned char EepromCheck(unsigned char *pdata,unsigned char packsize)
*函数功效:检查EEPROM的数据能否有用,接纳CRC16校验手艺。
  一次校验默许最后两个字节为校验码,
  须要重视,packsize网罗数据长度和校验码字节
*输入参数:pdata:数组指针;packsize:数据长度
*前往参数:数据能否有用,有用:VALID,有用:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关诠释:
********************************************************************/
unsigned char EepromCheck(unsigned char *pdata,unsigned char packsize)
{
unsigned char i,j;
unsigned int  crc,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)
{
return VALID;
}
else
{
return INVALID;
}
}

/*******************************************************************
*函数称谓:unsigned char CheckWriteCRC(unsigned char *pdata,unsigned char packsize)
*函数功效:为EEPROM数据写CRC校验码
*输入参数:pdata:数组指针;packsize:数据长度
*前往参数:操作告成否?,告成:VALID,掉落败:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关诠释:
********************************************************************/
unsigned char CheckWriteCRC(unsigned char *pdata,unsigned char packsize)
{
unsigned char i,j;
unsigned int  crc;

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))
{
return VALID;
}
else
{
return INVALID;
}
}

/********************************************************************
*函数称谓:unsigned char CheckAllPage(void)
*函数功效:检查EEPROM数据能否有用,检查三个备份
*输入参数:无
*前往参数:操作告成否?,告成:VALID,掉落败:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关诠释:
********************************************************************/
uint8_t CheckAllPage(void)
{
if ((EepromCheck((unsigned char *)EepromPage1Add,EepromPageSize) == VALID)
  &&(EepromCheck((unsigned char *)EepromPage2Add,EepromPageSize) == VALID)
  &&(EepromCheck((unsigned char *)EepromPage3Add,EepromPageSize) == VALID))
{
return VALID;
}

return INVALID;
}

/*******************************************************************
*函数称谓:unsigned char DataRecover(void)
*函数功效:检查EEPROM数据能否被破损,假定被破损了,作数据恢复
*输入参数:无
*前往参数:操作告成否?,告成:VALID,掉落败:INVALID
*编写作者:my_avr
*编写时间:2007年8月21日
*相关诠释:
********************************************************************/
uint8_t DataRecover(void)
{
unsigned char i;
unsigned char temp;
unsigned char page;
unsigned int  invalidpage[3];
unsigned int  validpage;

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) //三个备份都被破损了
{
return INVALID; //数据完全有用了
}

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)
{
return VALID;
}

return INVALID;
}



应用措施(三个备份):
1、界说一个数组:EEPROMData[EepromPageSize-2] ,数组界说为EepromPageSize-2是为了给每个备份留2个字节的校验
2、要生涯数据时,先把数据放到数组中,然后挪用EepromWriteBlock()函数,把这个数组的数据写进EEPROM,三个备份要写三次。
3、写完了以后,挪用CheckWriteCRC()函数,该函数会盘算出以后备份的CRC16磨练数据并写到EEPROM备份的尾部,有若干个备份就要挪用若干次。
4、至此,数据的备份使命曾经完成。

5、校验数据(浅易在复位后运转),推行CheckAllPage()函数,若经由历程了,则EEPROM数据没有用果,否则要运转DataRecover()函数,对破损的备份阻拦修复

------------------修改启事:修改变量的界讨形式

文章议论

相关文章

助赢时时彩-韩国时时彩助赢-韩国时时彩助赢计划 捕鱼达人3-捕鱼达人3无限金币免费版 幸运五张-幸运五张规则-掌联幸运五张安卓版 北京pk10-北京pk10新凤凰-凤凰pk10预测 888棋牌游戏-盛大娱乐棋牌平台-棋牌电玩城送彩金 时时彩后二-时时彩后二技巧-时时彩后二计划 安徽福彩网-安徽福彩快3网上购买 巨鳄棋牌-禾城棋牌牛牛-1比1现金棋牌 亿酷棋牌-象棋棋牌-棋牌游戏娱乐下载 qq捕鱼大亨-千炮捕鱼-qq游戏捕鱼大亨 北京pk10开奖-pk10赛车群-pk10开奖首选网上手游 波克棋牌-现金牛牛棋牌-亲朋棋牌游戏手游 冠通棋牌-棋牌现金-手机禾城棋牌 开心棋牌-娱乐棋牌送救济金-四方棋牌送救济金 亲朋棋牌-舟山99棋牌-唐朝电玩城棋牌