最近有讀者問了一個這樣的問題:看門狗復位之后,能不能保持復位之前的狀態?
這種問題,或者類似的問題,相信很多小伙伴都經歷過,特別是有多年單片機開發經驗的小伙伴,而且現實中的很多項目確實有這樣的需求。
實現的方法有很多種,這里給大家講講在Keil、 IAR編譯環境下,單片機變量不被初始化的實現方法。
處理器復位
處理器復位的方式有很多種,這里結合STM來講述MCU復位的來源:
STM32的復位為三類:系統復位、電源復位和后備域復位。
系統復位:
1. NRST引腳上的低電平(外部復位)
2. 窗口看門狗計數終止(WWDG復位)
3. 獨立看門狗計數終止(IWDG復位)
4. 軟件復位(SW復位)
5. 低功耗管理復位
電源復位:
1. 上電/掉電復位(POR/PDR復位)
2. 從待機模式中返回
備份區域復位:
1. 軟件復位,備份區域復位可由設置備份域控制寄存器(RCC_BDCR)中的BDRST位產生。
2. 在VDD和VBAT兩者掉電的前提下, VDD或VBAT上電將引發備份區域復位。
修飾符
實現處理器復位而變量不被初始化方法之前,讓我們先了解一下修飾符的知識。
修飾符是用于限定類型以及類型成員申明的一種符號。如C語言中常見的修飾符:
1.static靜態修飾符:修飾變量,函數。作用域:變量僅僅在本文件可見,函數在本文件可以被調用;
2.extern聲明修飾符:修飾變量,函數。修飾變量時候,變量的聲明在外面;
3.const常量修飾符:修飾變量,函數。修飾變量時候,不能被重復賦值,只能放在只讀段中;
4.volatile不穩定變量修飾符:這個變量不好翻譯,在c中的作用大概有兩點意思:A.表示變量是易失的,易變的; B.強制訪存操作,防止編譯器去優化,告訴編譯器每次必須去內存中取值,而不是從寄存器或者緩存。
其實,在C++ JAVA中還有更多:
public公共訪問修飾符、private私有訪問修飾符、protected保護訪問修飾符、friendly、abstract等。
而本文會使用到一個修飾符:
__no_init雖然這個修飾符不是C語言標準的修飾符,但在Keil、IAR這種集成開發環境中,他們支持這種修飾符。
而本文說的修飾符,修飾的變量位于RAM中:
在默認情況下,編譯器會將其變量存放在主RAM中,并在啟動時對其進行初始化。而__no_init類型修飾符使編譯器把變量放在非易失RAM區中,在啟動時也不對它們進行初始化,也就是說__no_init在系統啟動時不初始化變量。
Keil中__no_init的配置和使用
在Keil中,__no_init不是標準的修飾符,需要進行配置,配置之后就可以使用了。
1.宏定義__no_init
#define __no_init __attribute__((zero_init))
2.在工程選項中配置__no_init
Project -> Options for Targets -> Target,里面右下有個NoInit,這個就是需要我們配置的區域(可設定某一區域);
?
3.使用方法
比如定義變量:Cnt_NoInit
__no_init uint16_t Cnt_NoInit;
提示:不能初始化這個變量(也就是定義時不要賦值)。
IAR中中使用__no_init
在IAR中“__no_init”屬于是一個關鍵字,你會發現在使用這個修飾符之后,字體都是關鍵字顏色。
直接使用即可,類似上面定義一個不被初始化的變量:
__no_init uint16_t Cnt_NoInit;參考源碼
這里給大家分享兩個簡單的Demo(源碼),Keil和IAR工程實現的功能一樣。
源代碼:
__no_inituint16_t Cnt_NoInit; uint16_t Cnt_Init = 100; int main(void) { System_Initializes(); printf("Start... "); //復位打印 while(1) { printf("Cnt_NoInit = %d ", Cnt_NoInit); //打印變量 Cnt_NoInit++; if(Cnt_NoInit > 1000) { Cnt_NoInit = 0; } printf("Cnt_Init = %d ", Cnt_Init); Cnt_Init++; if(Cnt_Init > 1000) { Cnt_Init = 0; } LED_ON; TIMDelay_Nms(500); LED_OFF; TIMDelay_Nms(500); NVIC_SystemReset(); //系統復位 } }被Cnt_NoInit修飾,則會打印如下消息:
Start... Cnt_NoInit = 0 Cnt_Init = 100 Start... Cnt_NoInit = 1 Cnt_Init = 100 Start... Cnt_NoInit = 2 Cnt_Init = 100 Start... Cnt_NoInit = 3 Cnt_Init=100如果不被修飾:
uint16_t Cnt_NoInit; uint16_t Cnt_Init = 100;如果不被修飾:則會打印如下消息:
Start... Cnt_NoInit = 0 Cnt_Init = 100 Start... Cnt_NoInit = 0 Cnt_Init = 100 Start... Cnt_NoInit = 0 Cnt_Init = 100 Start... Cnt_NoInit = 0 Cnt_Init = 100相信聰明的你,看了上面例子會明白為什么沒有初始化的變量“Cnt_NoInit”在變化,而初始化了的“Cnt_Init”一直不變。
審核編輯:湯梓紅
-
單片機
+關注
關注
6032文章
44521瀏覽量
633092 -
mcu
+關注
關注
146文章
17002瀏覽量
350326 -
看門狗
+關注
關注
10文章
559瀏覽量
70746 -
IAR
+關注
關注
5文章
345瀏覽量
36625 -
初始化
+關注
關注
0文章
49瀏覽量
11837
原文標題:單片機變量不被初始化的實現方法
文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論