新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 單片機中的掉電存儲管理

        單片機中的掉電存儲管理

        作者: 時間:2016-11-30 來源:網絡 收藏
        各位單片機程序猿們,在單片機程序設計的時候,經常碰到一些數據的掉電存儲問題。往往這些數據量又不是很大,但是操作起來特別麻煩。每次變更數據都得調用存儲函數進行讀寫操作。今天總結一下近幾天的思路,對普通單片機的的NV變量的管理給出一個較為方便的操作方法。

        一般,我們的數據都由8,16,32位組成,因此,在此例中,我給出16長度數據的接口函數,旨在表明這種方法的思路。具體讀者可以根據自己的使用環境,自己改進。

        本文引用地址:http://www.104case.com/article/201611/323956.htm

        首先,說明下筆者的編程習慣,筆者在編寫單片機C程序的過程中,往往喜歡把程序中涉及的東西封裝成類似于面向對象思想中的類。把數據結構假想成類的屬性,把對相應數據結構操作的函數,假想成類的方法。這種方法在實際編程過程中,往往給自己帶來很大的便利。不僅思路清晰,而且便于模塊化管理自己的程序。

        現在,我們創建兩個文件,分別為NV.h和NV.C,h文件作為NV管理的模塊。NV.h中我們來定義NV變量的數據結構(即筆者所認為的類的屬性)和聲明對NV操作的函數。
        #ifndef _NV_
        #define _NV_

        //NV操作的狀態定義
        #define NV_Succeed 1

        #defineNV_Failed 0
        //定義16位長度的NV變量數據結構

        structNV_Struct16
        {
        u16 Val; //NV16變量的值
        u16 NVAddr; //NV16變量在存儲器中的首地址
        };
        //聲明外部調用函數
        extern void NV16_Get(struct NV_Struct16 *temp);
        u8 NV16_Set(struct NV_Struct16 *temp,u16 val);
        #endif

        在NV_Struct16中,我們封裝了一個叫做NV16的變量,其成員中有變量的值和在存儲器中的首地址。在這里,只是給它定義了一個數據的結構,并沒有定義實體變量,在C++或C#等面向對象程序設計方法中,這叫類的定義,并沒有創建類的實體。這樣做的目的,就是做到盡量把我們這個NV操作模塊從我們編寫的其他應用程序中抽象出來。

        那么,接下來,我們就來編寫NV16變量的操作函數。在NV.C中,我們添加兩個函數,一個是獲取NV變量的值,另一個是修改NV變量的值。

        #include"NV.h"
        #include"24CXX.h"
        #defineCheckTimes 4 //寫入時校驗次數
        #defineNV8_Enable 1 //NV8使能開關
        #defineNV16_Enable 1 //NV16使能開關
        #defineNV32_Enable 1 //NV32使能開關

        //以下是NV_Struct16的操作函數

        #ifNV16_Enable
        voidNV16_Get(struct NV_Struct16 *temp)
        {
        temp->Val=AT24CXX_ReadLenByte(temp->NVAddr,2);
        }
        u8NV16_Set(struct NV_Struct16 *temp,u16 val)
        {
        u8 cnt=0;
        if(temp->Val==val)returnNV_Succeed;
        temp->Val=val;
        AT24CXX_WriteLenByte(temp->NVAddr,temp->Val,2);
        while(cntNVAddr,2)!=temp->Val)
        cnt++;
        if(cnt else return NV_Succeed;
        }

        #endif
        在這個文件中,我們調用了一個24CXX.h文件中提供的24CXX的讀寫函數,這部分在我們移植的過程中是需要考慮的。下面貼出這個函數的原型,如果這個都不知道怎么寫出來,那我也無語了。

        //在AT24CXX里面的指定地址開始讀出長度為Len的數據
        //該函數用于讀出16bit或者32bit的數據.
        //ReadAddr :開始讀出的地址
        //返回值 :數據
        //Len :要讀出數據的長度2,4
        u32AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
        {
        u8 t;
        u32 temp=0;
        for(t=0;t {
        temp<<=8;
        temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);
        }
        return temp;
        }

        //在AT24CXX里面的指定地址開始寫入長度為Len的數據
        //該函數用于寫入16bit或者32bit的數據.
        //WriteAddr :開始寫入的地址
        //DataToWrite:數據數組首地址
        //Len :要寫入數據的長度2,4
        voidAT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)

        {
        u8 t;
        for(t=0;t {
        AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
        }
        }


        用以上方法來管理我們的NV變量,在程序中會大大地減少我們的工作量。下面來舉一個簡單的例子。記錄設備開機次數,并從串口打印出來。
        #include “相關頭文件”
        #include "NV.H"

        #define Flag 0x33 //存儲器初始化標志
        #define FlagAddr 0x00
        #define PowerOnTimesAddr 0x10 //將開機次數數據存儲在0x10位置
        //創建NV16非易失變量實體
        struct NV_Struct16 PowerOnTimes;
        struct NV_Struct16 MemFlag;

        void NV_Init()
        {
        //NV地址裝入
        MemFlag.NVAddr=FlagAddr;
        PowerOnTimes.NVAddr=PowerOnTimesAddr;
        //檢查存儲器是否初始化
        if(NV16_Get(&MemFlag)!=Flag)
        {
        NV16_Set(&MemFlag,Flag);
        NV16_Set(&PowerOnTimes,0);
        }
        }

        void main()
        {
        u16 times;
        NV_Init();
        times=NV16_Get(&PowerOnTimes);
        NV16_Set(&PowerOnTimes,times++);
        printf("%d",times);
        while(1);
        }
        哈哈,這樣子,你的應用程序是不是很簡潔呀。喜歡那就嘗試下吧!



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 佛山市| 旺苍县| 绩溪县| 天镇县| 盐边县| 昔阳县| 策勒县| 山东省| 安西县| 稷山县| 霞浦县| 湘乡市| 嘉禾县| 聊城市| 巍山| 历史| 微博| 长沙市| 桐乡市| 广丰县| 凌海市| 丹凤县| 鹤峰县| 晋城| 宜都市| 荣成市| 福贡县| 邮箱| 宁波市| 霍城县| 肥西县| 理塘县| 弥勒县| 高阳县| 宁乡县| 洞口县| 富顺县| 通江县| 湟中县| 静海县| 长白|