編譯環境: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()函數,對損壞的備份進行修復
------------------修改原因:修改變量的定義形式