日本a√视频在线,久久青青亚洲国产,亚洲一区欧美二区,免费g片在线观看网站

        <style id="k3y6c"><u id="k3y6c"></u></style>
        <s id="k3y6c"></s>
        <mark id="k3y6c"></mark>
          
          

          <mark id="k3y6c"></mark>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 詳解STM32單片機的堆棧

          詳解STM32單片機的堆棧

          作者:睡夢中的雄師 時間:2025-07-15 來源:EEPW 收藏

          學習單片機的時候,總是能遇到“堆?!边@個概念。分享本文,希望對你理解堆棧有幫助。對于了解一點匯編編程的人,就可以知道,堆棧是內存中一段連續(xù)的存儲區(qū)域,用來保存一些臨時數據:嵌入式開發(fā)中更接近底層的匯編與C 語言。堆棧操作由PUSH、POP兩條指令來完成。而程序內存可以分為幾個區(qū):

          ●   棧區(qū)(stack)

          ●   堆區(qū)(Heap)

          ●   全局區(qū)(static)

          1   文字常量區(qū)程序代碼區(qū)

          程序編譯之后,全局變量、靜態(tài)變量已經分配好內存空間,在函數運行時,程序需要為局部變量分配棧空間,當中斷來時,也需要將函數指針入棧,保護現場,以便于中斷處理完之后再回到之前執(zhí)行的函數。

          棧是從高到低分配,堆是從低到高分配。

          2   普通單片機與單片機中堆棧的區(qū)別

          普通單片機啟動時,不需要用bootloader將代碼從ROM搬移到RAM。

          但是單片機需要。

          這里我們可以先看看單片機程序執(zhí)行的過程,單片機執(zhí)行分三個步驟:

          ●   取指令

          ●   分析指令

          ●   執(zhí)行指令

          根據PC的值從程序存儲器讀出指令,送到指令寄存器。然后分析執(zhí)行執(zhí)行。這樣單片機就從內部程序存儲器去代碼指令,從RAM存取相關數據。

          RAM取數的速度是遠高于ROM的,但是普通單片機因為本身運行頻率不高,所以從ROM取指令慢并不影響。

          而STM32的CPU運行的頻率高,遠大于從ROM讀寫的速度。所以需要用bootloader 將代碼從ROM 搬移到RAM。

          使用棧就象我們去飯館里吃飯,只管點菜(發(fā)出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。使用堆就象是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。

          其實堆棧就是單片機中的一些存儲單元,這些存儲單元被指定保存一些特殊信息,比如地址(保護斷點)和數據(保護現場)。

          如果非要給他加幾個特點的話那就是:這些存儲單元中的內容都是程序執(zhí)行過程中被中斷打斷時,事故現場的一些相關參數。如果不保存這些參數,單片機執(zhí)行完中斷函數后就無法回到主程序繼續(xù)執(zhí)行了。

          這些存儲單元的地址被記在了一個叫做堆棧指針(SP)的地方。

          3   結合STM32 的開發(fā)講述堆棧

          從上面的描述可以看得出來,在代碼中是如何占用堆和棧的??赡芎芏嗳诉€是無法理解,這里再結合STM32的開發(fā)過程中與堆棧相關的內容來進行講述。

          如何設置STM32的堆棧大小?

          在基于MDK的啟動文件開始,有一段匯編代碼是分配堆棧大小的。

          1752582205437792.png

          這里重點知道堆棧數值大小就行。還有一段AREA(區(qū)域),表示分配一段堆棧數據段。數值大小可以自己修改,也可以使用STM32CubeMX數值大小配置,如下圖所示。

          image.png

          STM32F1默認設置值0×400,也就是1K大小。

          Stack_Size EQU 0×400

          函數體內局部變量:

          void Fun(void){ char i; int Tmp[256]; //...}

          局部變量總共占用了256*4 +1字節(jié)的棧空間。所以,在函數內有較多局部變量時,就需要注意是否超過我們配置的堆棧大小。

          函數參數:

          void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)

          這里要強調一點:傳遞指針只占4 字節(jié),如果傳遞的是結構體,就會占用結構大小空間。提示:在函數嵌套,遞歸時,系統(tǒng)仍會占用??臻g。

          堆(Heap)的默認設置0×200(512)字節(jié)。

          Heap_Size EQU 0×200

          大部分人應該很少使用malloc 來分配堆空間。雖然堆上的數據只要程序員不釋放空間就可以一直訪問,但是,如果忘記了釋放堆內存,那么將會造成內存泄漏,甚至致命的潛在錯誤。

          4   MDK 中RAM占用大小分析

          經常在線調試的人,可能會分析一些底層的內容。這里結合MDK-ARM來分析一下RAM占用大小的問題。在MDK編譯之后,會有一段RAM大小信息:

          1752582436478072.png

          這里4+6=1640,轉換成16進制就是0×668,在進行在調試時,會出現:

          1752582475460064.png

          這個MSP就是主堆棧指針,一般我們復位之后指向的位置,復位指向的其實是棧頂:

          1752582520287457.png

          而MSP指向地址0×20000668是0×20000000偏移0×668而得來。具體哪些地方占用了RAM,可以參看map文件中【Image Symbol Table】處的內容:

          1752582572989699.png

          (本文來源于《EEPW》


          評論


          相關推薦

          技術專區(qū)

          關閉