黃 華,李曉鋒,曾小寶
(張家界航空工業(yè)職業(yè)技術(shù)學(xué)院,湖南 張家界 427000)
在嵌入式控制系統(tǒng)中,通常會(huì)使用EEPROM保存一些掉電后不丟失內(nèi)容的參數(shù)。但EEPROM的寫入次數(shù)有限,如果系統(tǒng)需要頻繁更改參數(shù),極有可能超過EEPROM的使用壽命,如果用于保存參數(shù)的EEPROM因?yàn)榉磸?fù)擦寫而失效,將導(dǎo)致系統(tǒng)運(yùn)行需要的重要參數(shù)丟失,使系統(tǒng)不能正??煽康墓ぷ?。
一般來說EEPROM的壽命是100萬次擦寫,現(xiàn)在一些低成本單片機(jī)使用Flash ROM來模擬EEPROM,保存參數(shù)數(shù)據(jù),它們往往只有10萬次的擦寫壽命。如果參數(shù)不需要頻繁的改動(dòng),10萬次的擦寫次數(shù)完全夠用了,比如即便10分鐘擦寫一次,可以工作694年。但是,假如系統(tǒng)10秒擦寫一次數(shù)據(jù),10萬次的使用壽命只夠系統(tǒng)運(yùn)行100000/(360*24) = 11.5天,這時(shí)就希望EEPROM能有更長的使用壽命。
各種延長EEPROM使用壽命的基本原理都是利用空間換時(shí)間,一般來說嵌入式控制系統(tǒng)需要保存的參數(shù)數(shù)據(jù)只有幾個(gè)字節(jié),相對(duì)而言EEPROM的容量比要存儲(chǔ)的數(shù)據(jù)量大得多。如果我們將這些信息保存到EEPROM中固定的地址處,就會(huì)出現(xiàn)這樣的情況:一方面保存參數(shù)的存儲(chǔ)單元因?yàn)榉磸?fù)擦寫已經(jīng)損壞,另一方面EEPROM中還剩余大量完好未使用的存儲(chǔ)單元。
若我們能將EEPROM所有單元都利用起來,使得數(shù)據(jù)的擦寫均勻分布到EEPROM的每一個(gè)單元,就可以大大延長EEPROM的使用使命[1]。比如,如果需要保存的參數(shù)總共8個(gè)字節(jié),EEPROM的容量有256字節(jié),將參數(shù)保存平均分布到256字節(jié)后,相當(dāng)于將EEPROM的壽命提高了256/8倍,10萬次的擦寫壽命就提高到320萬次,這就大大提高了系統(tǒng)的使用壽命,因而提高了系統(tǒng)的可靠性。如果這樣的擦寫壽命仍然不夠使用,只需要提高EEPROM的容量就可以得到更高的使用壽命。
采用這種方法后,參數(shù)信息就不是保存在EEPROM的固定地址區(qū)域,我們需要一種方法來找到EEPROM中保存參數(shù)的位置,并且每次將參數(shù)寫入到不同的EEPROM地址處[2]。為了確定每次保存參數(shù)的地址,文獻(xiàn)1中介紹了“用后還原法”、“地址指針法”,但這些方法都比較麻煩,通用性不強(qiáng),使得開發(fā)困難,為此筆者研究了一種“打包標(biāo)記”算法,來查找每次參數(shù)的保存位置。
本算法在保存參數(shù)時(shí),并不是直接將參數(shù)保存到EEPROM中,而是先將參數(shù)“打包”后再存放,“打包”后要保存的數(shù)據(jù)包格式為:
這里,F(xiàn)lag1、Flag2是一個(gè)選擇用來標(biāo)記參數(shù)存放位置的特殊數(shù)據(jù),盡量選擇Flag1、Flag2的值與所保存的參數(shù)不一樣,以便于識(shí)別。采用這樣的數(shù)據(jù)包格式存放數(shù)據(jù)后,查找參數(shù)保存地址的算法可描述如下:
1) 設(shè)置搜索地址addr為0,查找次數(shù)search_times為0;
2) 將addr地址處內(nèi)容與Flag1比較,若相等,則執(zhí)行第4步;
3) 搜索地址前進(jìn)1個(gè)單位,如果到了最大的EEPROM地址,折回到0地址,查找次數(shù)加1;
4) 讀入N個(gè)單元的數(shù)據(jù)到緩沖區(qū),查找次數(shù)加N;
5) 讀入第N+1個(gè)單元,并將其與Flag2比較,如果相等,說明找到了數(shù)據(jù)存放的單元,將addr保存到全局變量,成功返回,否則繼續(xù)執(zhí)行第6步;
6) 判斷查找次數(shù)是否大于EEPROM容量,若小于,回到第2步繼續(xù)搜索,若大于,說明沒有找到曾經(jīng)保存了參數(shù),這說明系統(tǒng)并沒有經(jīng)過初始化,返回查找失敗。
寫入?yún)?shù)的算法可描述如下:
1) 每次寫入之前,需要先查找一遍EEPROM,找到以前存放數(shù)據(jù)的起始地址;
2) 向上一次存放參數(shù)的地址的Flag1標(biāo)志擦除清0;
3) 向前跳過N+1個(gè)單元,跳過上一次寫入?yún)?shù)的EEPROM地址,開始寫入數(shù)據(jù)。
該算法的實(shí)現(xiàn)由load_parma、save_parma兩個(gè)函數(shù)組成,算法中調(diào)用eeprom_read函數(shù)和eeprom_write函數(shù)分別實(shí)現(xiàn)數(shù)據(jù)的讀取和寫入,如要將該算法移植到不同的系統(tǒng),只需要實(shí)現(xiàn)這兩個(gè)底層寫入函數(shù)即可。load_parma函數(shù)查找參數(shù)保存的地址并存放到param_start_address全局變量,并將參數(shù)加載到buf數(shù)組緩沖區(qū),save_parma函數(shù)跳過當(dāng)前參數(shù)在EEPROM中存放的區(qū)域,寫入下一個(gè)EEPROM區(qū)域。
bool load_parma(unsigned char *buf, unsigned char len)
{
unsigned int search_times=0;
unsigned int addr;
unsigned char flag=0;
unsigned char check_sum;
unsigned char i=0;
for(search_times=0;search_times { //從當(dāng)前的參數(shù)存放起始地址開始查找 flag=eeprom_read(param_start_address); //當(dāng)前地址不是參數(shù)啟示的標(biāo)志字節(jié) //跳出循環(huán),從下一個(gè)字節(jié)繼續(xù)搜索 if(flag!=PARAM_FLAG1) { param_start_address=next_eeprom_addr(param_start_address); continue; } //找到標(biāo)志字節(jié),加載數(shù)據(jù) addr=param_start_address; //check_sum=PARAM_FLAG; for(i=0;i { addr=next_eeprom_addr(addr); buf[i]=eeprom_read(addr); //check_sum^=buf[i]; } addr=next_eeprom_addr(addr); if(eeprom_read(addr)==PARAM_FLAG2) { //找到參數(shù)存放位置 return true; } //校驗(yàn)和計(jì)算不正確,是錯(cuò)誤的標(biāo)志字節(jié),重新搜索 param_start_address=next_eeprom_addr(param_start_address); } //全部搜索完畢,未找到已保存參數(shù) return false; } bool save_param(unsigned char *buf, unsigned char len){ unsigned char flag=0; //unsigned char check_sum=PARAM_FLAG; unsigned char i=0; unsigned int addr; //如果參數(shù)起始地址為標(biāo)志字節(jié),說明已經(jīng)保存過參數(shù) flag=eeprom_read(param_start_address); if(flag==PARAM_FLAG1){ //擦掉上一次保存的標(biāo)志字節(jié) eeprom_write(param_start_address, 0); //切換下一個(gè)個(gè)區(qū)塊來保存數(shù)據(jù) for(i=0;i param_start_address=next_eeprom_addr(param_start_address); //跳過Flag2單元 param_start_address=next_eeprom_addr(param_start_address); } eeprom_write(param_start_address,PARAM_FLAG1); addr=next_eeprom_addr(param_start_address); for(i=0;i { eeprom_write(addr,buf[i]); //check_sum^=buf[i]; addr=next_eeprom_addr(addr); } eeprom_write(addr,PARAM_FLAG2); return true; } 為了驗(yàn)證算法的有效性,筆者在PC機(jī)上編寫了一個(gè)測試程序,用內(nèi)存模擬EEPROM,將隨機(jī)數(shù)據(jù)先使用save_parma保存,在使用load_parma讀取,將讀取到的數(shù)據(jù)與寫入前的數(shù)據(jù)進(jìn)行比對(duì),經(jīng)過100億次的循環(huán)測試,數(shù)據(jù)沒有出現(xiàn)錯(cuò)誤,這說明該算法是有效可行的。 本文給出一種延長EEPROM使用壽命的算法,在筆者使用該算法設(shè)計(jì)的一個(gè)數(shù)據(jù)記錄儀系統(tǒng)上應(yīng)用,系統(tǒng)已經(jīng)長時(shí)間穩(wěn)定運(yùn)行,經(jīng)實(shí)踐檢驗(yàn)該算法運(yùn)行可靠,具有一定的參考價(jià)值。4 結(jié)語