我們進行程式設計的時候,都會知道,系統上電或複位時,會執行變量初始化操作,但是有些情況下,我們并不希望變量初始化,例如,在系統異常複位發生後,我們希望系統能夠迅速恢複複位前的現場狀況,這樣就希望變量能夠保留原先的值,而不被初始化。實際上,大家都知道,變量是存儲在RAM中的,隻要不掉電,變量的數值是不會改變的,隻要我們不讓系統進行初始化操作就可以了。
不同的編譯環境,有不同的設定方法,本文介紹在Keil中設定不初始化變量的方法。在這裡需要說明的是,網上介紹了許多的設定方法,但并不是所有的方法都起作用,本文将介紹一種最為直接的方法。
1、打開Options for Target對話框Linker标簽,勾選掉Use Memory Layout from Target Dialog,這個選項的意思是使用Target标簽進行連結設定,是以在其勾選的情況下,分散檔案是不能自己編輯的,勾選掉以後,我們就可以進行分散檔案的設定了。

2、點選分散檔案後面的Edit按鈕,打開分散檔案,按下圖所示的方法,增加節點。原先僅有一個RAM節點,其起始位址是0x20000000,其長度是0x00008000。我們新編輯的分散檔案,将RAM分為2部分,第1部分長度為0x7000,第2部分長度為0x1000,并将第2部分設定為UNINIT,也就是不初始化,顯式節點名為NO_INIT。
3、有了上述設定後,我們就可以進行變量設定了,在這裡需要注意的是變量需定義為全局變量,且不能賦初值,後面要加入存放的節點,如下面程式所示。我們定義了5個變量,第1個為u16_Start,後面為4個數組(僅是舉例子,沒有什麼實際意義)。
uint16_t u16_Start __attribute__((section("NO_INIT"),zero_init));
uint16_t u16_a[2] __attribute__((section("NO_INIT"),zero_init));
uint16_t u16_b[2] __attribute__((section("NO_INIT"),zero_init));
uint16_t u16_c[2] __attribute__((section("NO_INIT"),zero_init));
uint16_t u16_d[2] __attribute__((section("NO_INIT"),zero_init));
4、正确編譯後,将程式下載下傳到目标闆,我們就可以觀察到這些變量不會因為單片機複位,而被初始化了。不過這又産生了一個新的問題,由于我們沒有給這些變量賦初值,當系統上電時,這些變量的值是随機的,是以我們還需要辨識是系統上電,還是系統複位,使用下面的程式就可以了,這也是變量u16_Start的作用。當系統上電時,由于RAM是剛剛加電,是以變量u16_Start為12345的可能性幾乎為0,我們認為這是系統上電,将u16_Start設定為12345後,并初始化這些變量。當系統複位時,u16_Start中的數值仍然保留,是以還為12345,這樣就不再初始化變量。
if (u16_Start != 12345)
{
u16_Start = 12345;
u16_a[0] = 0;
u16_a[1] = 0;
u16_b[0] = 0;
u16_b[1] = 0;
u16_c[0] = 0;
u16_c[1] = 0;
u16_d[0] = 0;
u16_d[1] = 0;
}
//=====================================================================
可以有另外的方法:
最近一個項目需要儲存一下臨時資料,而産品容易受幹擾而複位。是以需要儲存一下資料,那麼隻有在系統複位時候不再初始化變量即可。對應MDK(keil)來說是一個比較麻煩的問題。通過網絡上找了大量資料和測試發現終于可以了。
如果要實作以上要求,必須設定兩點,缺一不可:
-
在MDK的選項中設定如下:
2
在keil中使用不初始化變量 - 必須在程式代碼中如下編寫:
#define noinit attribute((zero_init)) // 變量不初始化為0
noinit int tmp; // 變量前加上宏__noinit__
當然也可以直接:
attribute((zero_init)) int tmp;
說明:noinit 不是mdk的關鍵字
//====================================================
參考文章:http://blog.csdn.net/qingwufeiyang12346