一種往Flash中存放用戶數(shù)據(jù)的存儲(chǔ)方法及讀取方法
【技術(shù)領(lǐng)域】
[0001]本發(fā)明涉及一種往Flash中存放用戶數(shù)據(jù)的存儲(chǔ)方法及讀取方法。
【背景技術(shù)】
[0002]家電控制板常常需要保存一些用戶數(shù)據(jù),比如說控制目標(biāo)溫度、工作模式等等。早期都用EEPR0M來儲(chǔ)存用戶數(shù)據(jù),EEPR0M具有存儲(chǔ)速度快,重復(fù)擦寫次數(shù)多(高達(dá)100萬次)的優(yōu)點(diǎn),但是價(jià)格昂貴。隨著MCU工藝技術(shù)的發(fā)展,MCU的R0M(以下簡稱Flash)空間越來越大,而且制作成本低廉。Flash的缺點(diǎn)是擦除速度慢,重復(fù)擦寫的次數(shù)少,絕大多數(shù)都在1萬次以下。因?yàn)镕lash空間大,這恰恰擬補(bǔ)擦寫次數(shù)少的問題;比如將2byte的用戶數(shù)據(jù)存儲(chǔ)到2K的Flash空間里,就能寫1000萬次(2k*l萬/2)。由于Flash便宜(MCU自帶的ROM空間,產(chǎn)品控制程序用不完部分可以用來做用戶數(shù)據(jù)存儲(chǔ)),很多設(shè)計(jì)工程師為了節(jié)約成本開始用Flash做用戶數(shù)據(jù)存儲(chǔ),但是經(jīng)過實(shí)踐,發(fā)現(xiàn)有用戶數(shù)據(jù)存儲(chǔ)存在偶發(fā)性丟失,設(shè)計(jì)出來的產(chǎn)品也偶然遭到用戶的投訴;也有些在用戶使用一兩年后,存儲(chǔ)永久失效,造成產(chǎn)品批量問題。諸多原因都可以引起存儲(chǔ)不良和失效:很多工程師采用擦除一次,保存一次的方法,這樣嚴(yán)重影響了 Flash的使用壽命(只能擦除1萬次),在用戶使用一段時(shí)間后存儲(chǔ)失效;還有些工程師采用開環(huán)存儲(chǔ),沒有閉環(huán)驗(yàn)證過程,保存的數(shù)據(jù)是否正確沒有得到驗(yàn)證,得出來的數(shù)據(jù)有可能是錯(cuò)誤的數(shù)據(jù);也有些工程師對同一個(gè)空間只保存一次,由于MCU內(nèi)部增壓電路可能受干擾,出現(xiàn)瞬間燒錄電壓過低時(shí),單次燒錄無法確保對Flash單元燒錄成功;更重要的是,F(xiàn)lash空間存在“壞道”(部分存儲(chǔ)空間壞了),很多工程師不懂得如何識(shí)別和避開“壞道”。沒有正確的數(shù)據(jù)保存,正確的數(shù)據(jù)讀取就無從談起。正是這些原因,使得絕大部分工程師至今還在使用外部EEPR0M做數(shù)據(jù)保存,造成了極大的資源浪費(fèi)。
【發(fā)明內(nèi)容】
[0003]本發(fā)明所要解決的技術(shù)問題是針對上述現(xiàn)有技術(shù)提供一種往Flash中存放用戶數(shù)據(jù)的存儲(chǔ)方法及讀取方法,該方法能很好避免用戶數(shù)據(jù)存儲(chǔ)過程中數(shù)據(jù)偶發(fā)性丟失的問題;該方法能很好解決用戶數(shù)據(jù)存儲(chǔ)過程中數(shù)據(jù)Flash使用時(shí)間不長的問題;該方法能正確的識(shí)別和避開“壞道”;該方法還能在眾多已經(jīng)保存的用戶數(shù)據(jù)中正確識(shí)別最后一次存儲(chǔ)的用戶數(shù)據(jù)。
[0004]本發(fā)明解決上述技術(shù)問題所采用的第一種技術(shù)方案為:一種往Flash中存放用戶數(shù)據(jù)的存儲(chǔ)方法及讀取方法,用于將電器終端控制板需要保存的具有固定長度的用戶數(shù)據(jù)存放至電器終端控制板中單片機(jī)自帶的Flash空間中,其特征在于:將要存儲(chǔ)的長度固定的N個(gè)用戶數(shù)據(jù)按照以下方式打包成數(shù)據(jù)包,每個(gè)數(shù)據(jù)包從前到后依次包括帖頭、N個(gè)用戶數(shù)據(jù)和校驗(yàn)碼;將單片機(jī)自帶的Flash空間中的空閑部分按照地址順序分為若干存儲(chǔ)塊,不同的存儲(chǔ)塊塊保存不同類型的數(shù)據(jù),對于數(shù)據(jù)單一的情況,可以只分1個(gè)存儲(chǔ)塊,再把其中的存儲(chǔ)塊按數(shù)據(jù)包的長度分若干區(qū);
[0005]前述打包后的數(shù)據(jù)包往Flash中以區(qū)為單位按循序依次存放,其存儲(chǔ)方法為:
[0006]首先定義一個(gè)數(shù)組變量user_data[data_size],其中data_size =幀頭長度+用戶數(shù)據(jù)長度N+校驗(yàn)碼長度,單位byte,使user_data[0]=帖頭,然后把長度固定的N個(gè)用戶數(shù)據(jù)保存到 user_data[l]?user_data[N]中,N = data_size_2,user_data[data_size-1]=校驗(yàn)碼;再定義一個(gè)指向 const 的指針 unsigned char const氺write_addr,使ffrite_addr指向存儲(chǔ)塊a首地址,將存儲(chǔ)塊a的存儲(chǔ)空間以data_Size為長度分為若干區(qū),對的數(shù)據(jù)包存儲(chǔ)前先對存儲(chǔ)塊a按循序以區(qū)為單位來查“空”,查空“空”,只要對每個(gè)區(qū)的幀頭查詢即可,而幀頭剛好是每個(gè)區(qū)的首地址,按循序查到第一個(gè)“空”的區(qū)首地址后(即該區(qū)的幀頭為“空”),開始寫入打包好的數(shù)據(jù)包,待寫數(shù)據(jù)的操作結(jié)束后,對寫入的數(shù)據(jù)進(jìn)行驗(yàn)證是否已經(jīng)寫入成功,如果沒有寫入成功,則執(zhí)行再次寫入操作;如果寫入動(dòng)作執(zhí)行了Μ次仍未成功,則查找下一個(gè)“空”區(qū),再執(zhí)行上述寫入操作,最多允許更換X個(gè)區(qū)執(zhí)行寫入操作,如果X個(gè)區(qū)都無法寫入成功,則認(rèn)為存儲(chǔ)塊a損壞,退出存儲(chǔ)操作;
[0007]對Flash中存放的用戶數(shù)據(jù)進(jìn)行讀取的讀取方法為:
[0008]設(shè)置一個(gè)指向const的指針unsigned char const*P,設(shè)單片機(jī)自帶的Flash空間擦“空”后的值為Oxff;
[0009]步驟1、使P = block_a,block_a為存儲(chǔ)塊a的首地址;
[0010]步驟2、判斷P是否小于block_a_end,block_a_end為存儲(chǔ)塊的尾地址,如是,執(zhí)行步驟3,如不是,結(jié)束;
[0011]步驟3、判斷P[0]==帖頭,且P[data_size] = = Oxff ?如是,執(zhí)行步驟4,如不是,令P+ = data_size,并返回步驟2 ;
[0012]步驟4、求 P[0]?P[data_size_2]的校驗(yàn)碼;
[0013]步驟5、判斷P[data_size_l]是否等于校驗(yàn)碼?如是執(zhí)行步驟6,如不是,初始化用戶數(shù)據(jù),置保存用戶數(shù)據(jù)標(biāo)志位=true,結(jié)束;
[0014]步驟6、把用戶數(shù)據(jù)調(diào)出來,保存至RAM中,結(jié)束。
[0015]本發(fā)明解決上述技術(shù)問題所采用的第二種技術(shù)方案為:一種往Flash中存放用戶數(shù)據(jù)的存儲(chǔ)方法及讀取方法,用于將電器終端控制板需要保存的可變長度用戶數(shù)據(jù)存放至電器終端控制板中單片機(jī)自帶的Flash空間中,其特征在于:將要存儲(chǔ)的長度不固定的Μ個(gè)用戶數(shù)據(jù)按照以下方式打包成數(shù)據(jù),Μ為大于0的自然數(shù),每個(gè)數(shù)據(jù)包從前到后依次包括帖頭、Ν個(gè)用戶數(shù)據(jù)、預(yù)留字長度Υ、幀尾和校驗(yàn)碼;¥大于等于0,數(shù)據(jù)包的總長度data_Size=預(yù)定的可能出現(xiàn)的最長用戶數(shù)據(jù)個(gè)數(shù)N+3,N大于等于M,即Y = data_size-(N+3);將單片機(jī)自帶的Flash空間中的空閑部分按照地址順序分為若干存儲(chǔ)塊,不同的塊保存不同類型的數(shù)據(jù),對于數(shù)據(jù)單一的情況,只分一個(gè)存儲(chǔ)塊,再把其中1個(gè)存儲(chǔ)塊按長度data_Size分若干區(qū);
[0016]前述打包后的數(shù)據(jù)包往Flash中存放的存儲(chǔ)方法為:
[0017]首先定義一個(gè)數(shù)組變量user_data[data_size],其中data_size =幀頭長度+N+預(yù)留字長度Y+幀尾長度+校驗(yàn)碼長度,即data_size> = (N+3),單位byte,使user_data[0]=帖頭,然后把長度為Μ的用戶數(shù)據(jù)保存到user_data[l]?user_data[N]中,如果 data_size 大于 N+3 則長度為 Y 的預(yù)留字:user_data[N+l]?user_data[data_size_3]都清零;如果data_size等于N+3,則預(yù)留字長度Y = 0,user_data[data_size_2]=帖尾,user_data[data_size_l]=校驗(yàn)碼;再定義一個(gè)指向 const 的指針 unsigned charconst*write_addr,使Write_addr指向存儲(chǔ)塊a首地址,將存儲(chǔ)塊a的存儲(chǔ)空間以data_size為長度分為若干區(qū),對的數(shù)據(jù)包存儲(chǔ)前先對存儲(chǔ)塊a按循序以區(qū)為單位來查“空”,查空“空”,只要對每個(gè)區(qū)的幀頭查詢即可,而幀頭剛好是每個(gè)區(qū)的首地址,按循序查到第一個(gè)“空”的區(qū)首地址后(即該區(qū)的幀頭為“空”),開始寫入打包好的數(shù)據(jù)包,待寫數(shù)據(jù)的操作結(jié)束后,對寫入的數(shù)據(jù)進(jìn)行驗(yàn)證是否已經(jīng)寫入成功,如果沒有寫入成功,則執(zhí)行再次寫入操作;如果寫入動(dòng)作執(zhí)行了 Μ次仍未成功,則查找下一個(gè)“空”區(qū),再執(zhí)行上述寫入操作,最多允許更換X個(gè)區(qū)執(zhí)行寫入操作,如果X個(gè)區(qū)都無法寫入成功,則認(rèn)為存儲(chǔ)塊a損壞,退出存儲(chǔ)操作;
[0018]對Flash中存放的用戶數(shù)據(jù)進(jìn)行讀取的讀取方法為:
[0019]設(shè)置一個(gè)指向const的指針unsigned char const*P,設(shè)單片機(jī)自帶的Flash空間擦空后的值為Oxff ;
[0020]步驟1、使P = block_a,block_a為存儲(chǔ)塊a的首地址;
[0021]步驟2、判斷P是否小于block_a_end,block_a_end為存儲(chǔ)塊a的尾地址,如是,執(zhí)行步驟3,如不是,結(jié)束;
[0022]步驟3、判斷P[0]==帖頭,且P[data_size] = = Oxff ?如是,執(zhí)行步驟4,如不是,令P+ = data_size,并返回步驟2 ;
[0023]步驟4、判斷P[data_size_2]==帖尾?如是,執(zhí)行步驟5,如不是,執(zhí)行步驟7 ;