×
单片机 > 单片机程序设计 > 详情

avr eeprom保护方法

发布时间:2020-09-02 发布时间:
|
在项目中复制出来的程序,使用时可能有些地方需要修改。
编译环境:WinAVR-20060421 AVR Studio 4.12.498  Service Pack 4


基本思路:每份写到EEPRM的数据,都做三个备份,每个备份的数据都做CRC16校验,只要系统运行中出错,错误地修改了EEPROM数据,
          那么根据校验字节就知道哪个备份的数据被修改了,然后用正确的备份覆盖出错的备份,达到数据恢复的目的。


EEPROMSave.h 文件:



#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)



#define VALID 0x01
#define INVALID 0x00



EEPROMSave.c 文件:


unsigned char EepromReadByte(unsigned char *address)
{
unsigned char data;

data 0;

eeprom_busy_wait();
data  eeprom_read_byte(address);

return data;
}


uint16_t EepromReadWord(uint16_t *address)
{
uint16_t data;

data 0;

eeprom_busy_wait();
data  eeprom_read_word(address);

return data;
}


void EepromWriteByte(unsigned char *address,unsigned char data)
{
eeprom_busy_wait();
eeprom_write_byte(address,data);
}


void EepromWriteWord(unsigned int *address,unsigned int data)
{
eeprom_busy_wait();
eeprom_write_word(address,data);
}


void EepromWriteBlock(unsigned char *buff,unsigned char *address,unsigned char n)
{
unsigned char i;

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

buff++;
}
}


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; (packsize 2); ++)
{
crc crc ((uint16_t) EepromReadByte(pdata) <8);

for (j 0; 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)
{
unsigned char i,j;
unsigned int  crc;

crc     0;

for (i 0; (packsize 2); ++)
{
crc crc ((uint16_t) EepromReadByte(pdata) <8);

for (j 0; 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;
}
}


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;
}


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; EepromPageSize; ++)
{
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()函数,对损坏的备份进行修复






------------------修改原因:修改变量的定义形式


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址