電子產(chǎn)業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 729|回復: 0
收起左側(cè)

怎么讓單片機變量不被初始化?

[復制鏈接]

418

主題

418

帖子

4293

積分

四級會員

Rank: 4

積分
4293
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2024-9-27 11:45:00 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
關注+星標公眾,不錯過精彩內(nèi)容

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


    3.使用方法比如定義變量:Cnt_NoInit
  • __no_init uint16_t Cnt_NoInit;
    提示:不能初始化這個變量(也就是定義時不要賦值)。
    IAR中中使用__no_init
    在IAR中“__no_init”屬于是一個關鍵字,你會發(fā)現(xiàn)在使用這個修飾符之后,字體都是關鍵字顏色。
    直接使用即可,類似上面定義一個不被初始化的變量:
  • __no_init uint16_t Cnt_NoInit;
    參考源碼
    這里給大家分享兩個簡單的Demo(源碼),Keil和IAR工程實現(xiàn)的功能一樣。
    源代碼:
  • __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(); //系統(tǒng)復位  }}
    被Cnt_NoInit修飾,則會打印如下消息:
  • Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 1Cnt_Init = 100
    Start...Cnt_NoInit = 2Cnt_Init = 100
    Start...Cnt_NoInit = 3Cnt_Init = 100
    如果不被修飾:
  • uint16_t Cnt_NoInit;uint16_t Cnt_Init = 100;如果不被修飾:則會打印如下消息:
  • Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 0Cnt_Init = 100
    相信聰明的你,看了上面例子會明白為什么沒有初始化的變量“Cnt_NoInit”在變化,而初始化了的“Cnt_Init”一直不變。
    ------------ END ------------



    ●專欄《嵌入式工具
    ●專欄《嵌入式開發(fā)》
    ●專欄《Keil教程》
    ●嵌入式專欄精選教程

    關注公眾號回復“加群”按規(guī)則加入技術(shù)交流群,回復“1024”查看更多內(nèi)容。




    點擊“閱讀原文”查看更多分享。
  • 回復

    使用道具 舉報

    發(fā)表回復

    您需要登錄后才可以回帖 登錄 | 立即注冊

    本版積分規(guī)則


    聯(lián)系客服 關注微信 下載APP 返回頂部 返回列表