最近有讀者問(wèn)了一個(gè)這樣的問(wèn)題:看門(mén)狗復(fù)位之后,能不能保持復(fù)位之前的狀態(tài)?
這種問(wèn)題,或者類似的問(wèn)題,相信很多小伙伴都經(jīng)歷過(guò),特別是有多年單片機(jī)開(kāi)發(fā)經(jīng)驗(yàn)的小伙伴,而且現(xiàn)實(shí)中的很多項(xiàng)目確實(shí)有這樣的需求。
實(shí)現(xiàn)的方法有很多種,這里給大家講講在Keil、 IAR編譯環(huán)境下,單片機(jī)變量不被初始化的實(shí)現(xiàn)方法。
處理器復(fù)位
處理器復(fù)位的方式有很多種,這里結(jié)合STM來(lái)講述MCU復(fù)位的來(lái)源:
STM32的復(fù)位為三類:系統(tǒng)復(fù)位、電源復(fù)位和后備域復(fù)位。
系統(tǒng)復(fù)位:
1. NRST引腳上的低電平(外部復(fù)位)
2. 窗口看門(mén)狗計(jì)數(shù)終止(WWDG復(fù)位)
3. 獨(dú)立看門(mén)狗計(jì)數(shù)終止(IWDG復(fù)位)
4. 軟件復(fù)位(SW復(fù)位)
5. 低功耗管理復(fù)位
電源復(fù)位:
1. 上電/掉電復(fù)位(POR/PDR復(fù)位)
2. 從待機(jī)模式中返回
備份區(qū)域復(fù)位:
1. 軟件復(fù)位,備份區(qū)域復(fù)位可由設(shè)置備份域控制寄存器(RCC_BDCR)中的BDRST位產(chǎn)生。
2. 在VDD和VBAT兩者掉電的前提下, VDD或VBAT上電將引發(fā)備份區(qū)域復(fù)位。
修飾符
實(shí)現(xiàn)處理器復(fù)位而變量不被初始化方法之前,讓我們先了解一下修飾符的知識(shí)。
修飾符是用于限定類型以及類型成員申明的一種符號(hào)。如C語(yǔ)言中常見(jiàn)的修飾符:
1.static靜態(tài)修飾符:修飾變量,函數(shù)。作用域:變量?jī)H僅在本文件可見(jiàn),函數(shù)在本文件可以被調(diào)用;
2.extern聲明修飾符:修飾變量,函數(shù)。修飾變量時(shí)候,變量的聲明在外面;
3.const常量修飾符:修飾變量,函數(shù)。修飾變量時(shí)候,不能被重復(fù)賦值,只能放在只讀段中;
4.volatile不穩(wěn)定變量修飾符:這個(gè)變量不好翻譯,在c中的作用大概有兩點(diǎn)意思:A.表示變量是易失的,易變的; B.強(qiáng)制訪存操作,防止編譯器去優(yōu)化,告訴編譯器每次必須去內(nèi)存中取值,而不是從寄存器或者緩存。
其實(shí),在C++ JAVA中還有更多:
public公共訪問(wèn)修飾符、private私有訪問(wèn)修飾符、protected保護(hù)訪問(wèn)修飾符、friendly、abstract等。
而本文會(huì)使用到一個(gè)修飾符:
__no_init雖然這個(gè)修飾符不是C語(yǔ)言標(biāo)準(zhǔn)的修飾符,但在Keil、IAR這種集成開(kāi)發(fā)環(huán)境中,他們支持這種修飾符。
而本文說(shuō)的修飾符,修飾的變量位于RAM中:
在默認(rèn)情況下,編譯器會(huì)將其變量存放在主RAM中,并在啟動(dòng)時(shí)對(duì)其進(jìn)行初始化。而__no_init類型修飾符使編譯器把變量放在非易失RAM區(qū)中,在啟動(dòng)時(shí)也不對(duì)它們進(jìn)行初始化,也就是說(shuō)__no_init在系統(tǒng)啟動(dòng)時(shí)不初始化變量。
Keil中__no_init的配置和使用
在Keil中,__no_init不是標(biāo)準(zhǔn)的修飾符,需要進(jìn)行配置,配置之后就可以使用了。
1.宏定義__no_init
#define __no_init __attribute__((zero_init))
2.在工程選項(xiàng)中配置__no_init
Project -> Options for Targets -> Target,里面右下有個(gè)NoInit,這個(gè)就是需要我們配置的區(qū)域(可設(shè)定某一區(qū)域);

3.使用方法
比如定義變量:Cnt_NoInit
__no_init uint16_t Cnt_NoInit;
提示:不能初始化這個(gè)變量(也就是定義時(shí)不要賦值)。
IAR中中使用__no_init
在IAR中“__no_init”屬于是一個(gè)關(guān)鍵字,你會(huì)發(fā)現(xiàn)在使用這個(gè)修飾符之后,字體都是關(guān)鍵字顏色。
直接使用即可,類似上面定義一個(gè)不被初始化的變量:
__no_init uint16_t Cnt_NoInit;參考源碼
這里給大家分享兩個(gè)簡(jiǎn)單的Demo(源碼),Keil和IAR工程實(shí)現(xiàn)的功能一樣。
源代碼:
__no_inituint16_t Cnt_NoInit; uint16_t Cnt_Init = 100; int main(void) { System_Initializes(); printf("Start... "); //復(fù)位打印 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(); //系統(tǒng)復(fù)位 } }被Cnt_NoInit修飾,則會(huì)打印如下消息:
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;如果不被修飾:則會(huì)打印如下消息:
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相信聰明的你,看了上面例子會(huì)明白為什么沒(méi)有初始化的變量“Cnt_NoInit”在變化,而初始化了的“Cnt_Init”一直不變。
審核編輯:湯梓紅
-
單片機(jī)
+關(guān)注
關(guān)注
6067文章
44989瀏覽量
650339 -
mcu
+關(guān)注
關(guān)注
146文章
17978瀏覽量
366660 -
看門(mén)狗
+關(guān)注
關(guān)注
10文章
583瀏覽量
71793 -
IAR
+關(guān)注
關(guān)注
5文章
381瀏覽量
37452 -
初始化
+關(guān)注
關(guān)注
0文章
50瀏覽量
12107
原文標(biāo)題:?jiǎn)纹瑱C(jī)變量不被初始化的實(shí)現(xiàn)方法
文章出處:【微信號(hào):strongerHuang,微信公眾號(hào):strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
定義IO初始化結(jié)構(gòu)體
NVMe高速傳輸之?dāng)[脫XDMA設(shè)計(jì)之七:系統(tǒng)初始化
IM 系列設(shè)備過(guò)載保護(hù)機(jī)制下界面初始化中斷的底層邏輯與解決方案
使用jlink連接mcu查看日志,偶發(fā)重新初始化,部分線程未退出,變量錯(cuò)位怎么解決?
STM32CubeMX用于STM32配置和初始化C代碼生成
EE-359:ADSP-CM40x啟動(dòng)時(shí)間優(yōu)化和器件初始化

EE-88:使用21xx編譯器在C中初始化變量

OMAP5912多媒體處理器初始化參考指南

STM32F407 MCU使用SD NAND?不斷電初始化失效解決方案

segger編譯器初始化問(wèn)題
基于旋轉(zhuǎn)平移解耦框架的視覺(jué)慣性初始化方法

TMS320C6000 McBSP初始化

視頻引擎初始化失敗怎么回事
Keil中變量不被初始化方法

評(píng)論