久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機(jī)教程網(wǎng) >> MCU設(shè)計(jì)實(shí)例 >> 瀏覽文章

治標(biāo)治本,徹底解決AVR單片機(jī)EEPROM數(shù)據(jù)丟失問題

作者:劉溫電   來(lái)源:本站原創(chuàng)   點(diǎn)擊數(shù):  更新時(shí)間:2013年11月26日   【字體:

編譯環(huán)境:WinAVR-20060421 + AVR Studio 4.12.498  Service Pack 4


基本思路:每份寫到EEPRM的數(shù)據(jù),都做三個(gè)備份,每個(gè)備份的數(shù)據(jù)都做CRC16校驗(yàn),只要系統(tǒng)運(yùn)行中出錯(cuò),錯(cuò)誤地修改了EEPROM數(shù)據(jù),
          那么根據(jù)校驗(yàn)字節(jié)就知道哪個(gè)備份的數(shù)據(jù)被修改了,然后用正確的備份覆蓋出錯(cuò)的備份,達(dá)到數(shù)據(jù)恢復(fù)的目的。


EEPROMSave.h 文件:

/*   EEPROM管理定義   */

#define EepromPageSize 64 //頁(yè)容量定義

#define EepromPage0Addr 0x0000 //各個(gè)頁(yè)的其始地址定義
#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)

/*
最后兩個(gè)字節(jié)為CRC16校驗(yàn)碼,其余為數(shù)據(jù)

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

#define VALID 0x01
#define INVALID 0x00

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

EEPROMSave.c 文件:

/*******************************************************************
*函數(shù)名稱:EepromReadByte()
*函數(shù)功能:寫一個(gè)Byte的數(shù)據(jù)進(jìn)EEPROM
*輸入?yún)?shù):address:地址
*返回參數(shù):從指定地址讀出來(lái)的數(shù)據(jù)
*編寫作者:my_avr
*編寫時(shí)間:2007年8月13日
*相關(guān)說(shuō)明:
********************************************************************/
unsigned char EepromReadByte(unsigned char *address)
{
unsigned char data;

data = 0;

eeprom_busy_wait();
data  = eeprom_read_byte(address);

return data;
}

/*******************************************************************
*函數(shù)名稱:EepromReadWord();
*函數(shù)功能:寫一個(gè)Word的數(shù)據(jù)進(jìn)EEPROM
*輸入?yún)?shù):address:地址
*返回參數(shù):從指定地址讀出來(lái)的數(shù)據(jù)
*編寫作者:my_avr
*編寫時(shí)間:2007年8月13日
*相關(guān)說(shuō)明:
********************************************************************/
uint16_t EepromReadWord(uint16_t *address)
{
uint16_t data;

data = 0;

eeprom_busy_wait();
data  = eeprom_read_word(address);

return data;
}

/*******************************************************************
*函數(shù)名稱:EepromWriteByte()
*函數(shù)功能:寫一個(gè)Byte的數(shù)據(jù)進(jìn)EEPROM
*輸入?yún)?shù):address:地址;data:數(shù)據(jù)
*返回參數(shù):無(wú)
*編寫作者:my_avr
*編寫時(shí)間:2007年8月13日
*相關(guān)說(shuō)明:
********************************************************************/
void EepromWriteByte(unsigned char *address,unsigned char data)
{
eeprom_busy_wait();
eeprom_write_byte(address,data);
}

/*******************************************************************
*函數(shù)名稱:EepromWriteWord()
*函數(shù)功能:寫一個(gè)Word的數(shù)據(jù)進(jìn)EEPROM
*輸入?yún)?shù):address:地址;data:數(shù)據(jù)
*返回參數(shù):
*編寫作者:my_avr
*編寫時(shí)間:2007年8月13日
*相關(guān)說(shuō)明:
********************************************************************/
void EepromWriteWord(unsigned int *address,unsigned int data)
{
eeprom_busy_wait();
eeprom_write_word(address,data);
}

/*******************************************************************
*函數(shù)名稱:EepromWriteBlock()
*函數(shù)功能:將緩沖區(qū)中的n個(gè)數(shù)據(jù)寫進(jìn)EEPROM
*輸入?yún)?shù):address:地址;data:數(shù)據(jù)
*返回參數(shù):
*編寫作者:my_avr
*編寫時(shí)間:2007年8月13日
*相關(guān)說(shuō)明:
********************************************************************/
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++;
}
}

/******************************************************************
*函數(shù)名稱:unsigned char EepromCheck(unsigned char *pdata,unsigned char packsize)
*函數(shù)功能:檢查EEPROM的數(shù)據(jù)是否有效,采用CRC16校驗(yàn)技術(shù)。
  一次校驗(yàn)?zāi)J(rèn)最后兩個(gè)字節(jié)為校驗(yàn)碼,
  需要注意,packsize包括數(shù)據(jù)長(zhǎng)度和校驗(yàn)碼字節(jié)
*輸入?yún)?shù):pdata:數(shù)組指針;packsize:數(shù)據(jù)長(zhǎng)度
*返回參數(shù):數(shù)據(jù)是否有效,有效:VALID,無(wú)效:INVALID
*編寫作者:my_avr
*編寫時(shí)間:2007年8月21日
*相關(guān)說(shuō)明:
********************************************************************/
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;
}
}

/*******************************************************************
*函數(shù)名稱:unsigned char CheckWriteCRC(unsigned char *pdata,unsigned char packsize)
*函數(shù)功能:為EEPROM數(shù)據(jù)寫CRC校驗(yàn)碼
*輸入?yún)?shù):pdata:數(shù)組指針;packsize:數(shù)據(jù)長(zhǎng)度
*返回參數(shù):操作成功否?,成功:VALID,失敗:INVALID
*編寫作者:my_avr
*編寫時(shí)間:2007年8月21日
*相關(guān)說(shuō)明:
********************************************************************/
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;
}
}

/********************************************************************
*函數(shù)名稱:unsigned char CheckAllPage(void)
*函數(shù)功能:檢查EEPROM數(shù)據(jù)是否有效,檢查三個(gè)備份
*輸入?yún)?shù):無(wú)
*返回參數(shù):操作成功否?,成功:VALID,失敗:INVALID
*編寫作者:my_avr
*編寫時(shí)間:2007年8月21日
*相關(guān)說(shuō)明:
********************************************************************/
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;
}

/*******************************************************************
*函數(shù)名稱:unsigned char DataRecover(void)
*函數(shù)功能:檢查EEPROM數(shù)據(jù)是否被破壞,如果被破壞了,作數(shù)據(jù)恢復(fù)
*輸入?yún)?shù):無(wú)
*返回參數(shù):操作成功否?,成功:VALID,失敗:INVALID
*編寫作者:my_avr
*編寫時(shí)間:2007年8月21日
*相關(guān)說(shuō)明:
********************************************************************/
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) //三個(gè)備份都被破壞了
{
return INVALID; //數(shù)據(jù)完全無(wú)效了
}

while ((page--) > 0) //數(shù)據(jù)恢復(fù)
{
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;
}



使用方法(三個(gè)備份):
1、定義一個(gè)數(shù)組:EEPROMData[EepromPageSize-2] ,數(shù)組定義為EepromPageSize-2是為了給每個(gè)備份留2個(gè)字節(jié)的校驗(yàn)
2、要保存數(shù)據(jù)時(shí),先把數(shù)據(jù)放到數(shù)組中,然后調(diào)用EepromWriteBlock()函數(shù),把這個(gè)數(shù)組的數(shù)據(jù)寫進(jìn)EEPROM,三個(gè)備份要寫三次。
3、寫完了之后,調(diào)用CheckWriteCRC()函數(shù),該函數(shù)會(huì)計(jì)算出當(dāng)前備份的CRC16檢驗(yàn)數(shù)據(jù)并寫到EEPROM備份的尾部,有多少個(gè)備份就要調(diào)用多少次。
4、至此,數(shù)據(jù)的備份工作已經(jīng)完成。

5、校驗(yàn)數(shù)據(jù)(一般在復(fù)位后運(yùn)行),執(zhí)行CheckAllPage()函數(shù),若通過了,則EEPROM數(shù)據(jù)沒有問題,否則要運(yùn)行DataRecover()函數(shù),對(duì)損壞的備份進(jìn)行修復(fù)

------------------修改原因:修改變量的定義形式

關(guān)閉窗口

相關(guān)文章

主站蜘蛛池模板: 国产精品一级 | 综合视频在线 | 中文字幕第三页 | 一区二区伦理电影 | 日日操夜夜操天天操 | 风间由美一区二区三区在线观看 | 午夜精品一区二区三区三上悠亚 | 国产精品视频导航 | 自拍偷拍视频网 | 亚洲视频中文字幕 | 亚洲视频在线看 | 国产在线一区二区 | 午夜免费网站 | 国产91亚洲精品 | 精品中文字幕在线观看 | 在线欧美一区 | 日本色综合 | 国产成人久久精品一区二区三区 | 精品综合| 欧美 日韩 在线播放 | 日本特黄a级高清免费大片 国产精品久久性 | 99精品视频免费观看 | 欧美国产激情二区三区 | 国产大片黄色 | 国产精品高潮呻吟久久av野狼 | 一区二区三区视频 | 在线一区二区三区 | 精品久久九九 | 国产日产精品一区二区三区四区 | 99福利视频 | 国产精品国产成人国产三级 | 久久精品欧美一区二区三区不卡 | 国产在线一区二区三区 | 国产一区二区三区在线视频 | 欧美aaaaa| 日韩a视频 | 黄色一级视频 | 久久国产高清视频 | 婷婷丁香在线视频 | 91精品久久久久久久久久入口 | 日韩精品福利 |