學習STM32單片機的時候,總是能遇到 “堆棧” 這個概念。對于了解一點匯編編程的人,就可以知道,堆棧是內存中一段連續的存儲區域,用來保存一些臨時數據。堆棧操作由 PUSH、POP 兩條指令來完成。而程序內存可以分為幾個區:棧區(stack)、堆區(Heap)、全局區(static)、字符常量區、程序代碼區。
棧,用于存放局部變量,局部數組等; 堆,用于malloc申請內存空間; 全局靜態區,用于保存全局變量和靜態變量; 字符常量區,用于保存字符串等; 代碼區,用于保存程序的二進制代碼。
程序編譯之后,全局變量,靜態變量已經分配好內存空間。在函數運行時,程序需要為局部變量分配棧空間,當中斷來時,也需要將函數指針入棧,保護現場,以便于中斷處理完之后再回到之前執行的函數。棧是從高到低分配,堆是從低到高分配。
普通單片機與STM32單片機中堆棧的區別
普通單片機啟動時,不需要用bootloader 將代碼從ROM搬移到RAM;但是STM32單片機需要。這里我們可以先看看單片機程序執行的過程,單片機執行分三個步驟:取指令、分析指令、執行指令。根據PC的值從程序存儲器讀出指令,送到指令寄存器。然后分析、執行。這樣單片機就從內部程序存儲器取代碼指令,從RAM 存取相關數據。RAM 取數據的速度是遠高于 ROM 的,但是普通單片機因為本身運行頻率不高,所以從 ROM 取指令慢并不影響。
而STM32的CPU運行的頻率高,遠大于從ROM讀寫的速度。所以需要用 bootloader 將代碼從ROM搬移到 RAM(請注意,這部分表述不準確)。使用棧就象我們去飯館里吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。使用堆就象是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。 其實堆棧就是單片機中的一些存儲單元,這些存儲單元被指定保存一些特殊信息,比如地址(保護斷點)和數據(保護現場)。如果非要給堆棧加幾個特點的話,那就是:
這些存儲單元中的內容都是程序執行過程中被中斷打斷時,事故現場的一些相關參數。如果不保存這些參數,單片機執行完中斷函數后就無法回到主程序繼續執行了。
這些存儲單元的地址被記在了一個叫做堆棧指針(SP)的地方。
結合STM32的開發講述堆棧
從上面的描述可以看得出來,在代碼中是如何占用堆和棧的。可能很多人還是無法理解,這里再結合STM32的開發過程中與堆棧相關的內容來進行講述。 如何設置STM32的堆棧大小?在基于MDK的啟動文件開始,有一段匯編代碼是分配堆棧大小的。
這里重點知道堆棧數值大小就行。還有一段 AREA(區域),表示分配一段堆棧數據段。數值大小可以自己修改,也可以使用STM32CubeMX數值大小配置,如下圖所示。
STM32F1默認設置值 0x400,也就是1K大小。
Stack_Size EQU 0x400函數體內局部變量:void Fun(void) { chari; intTmp[256];//... }局部變量總共占用了256*4+1字節的棧空間。所以,在函數內有較多局部變量時,就需要注意是否超過我們配置的堆棧大小。 函數參數:voidHAL_GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef *GPIO_Init)要強調一點:傳遞指針只占4字節,如果傳遞的是結構體,就會占用結構大小空間。提示:在函數嵌套,遞歸時,系統仍會占用棧空間。 堆(Heap)的默認設置 0x200(512)字節。Heap_Size EQU 0x200大部分人應該很少使用malloc來分配堆空間。雖然堆上的數據只要程序員不釋放空間就可以一直訪問,但是,如果忘記了釋放堆內存,那么將會造成內存泄漏,甚至致命的潛在錯誤。
MDK中RAM占用大小分析
經常在線調試的人,可能會分析一些底層的內容。這里結合MDK-ARM來分析一下RAM 占用大小的問題。在MDK編譯之后,會有一段 RAM大小信息:
這里4+1636=1640,轉換成16進制就是0x668,在線進行調試時,會出現:
這個MSP就是主堆棧指針,一般我們復位之后指向的位置,復位指向的其實是棧頂:
而MSP指向地址0x20000668是0x20000000偏移0x668 而得來。具體哪些地方占用了RAM,可以參看map文件中【Image Symbol Table】處的內容:
STM32棧空間溢出的處理方法
在寫STM32程序時會用到一些局部變量,函數中的局部變量是存在棧空間當中,在
STM32的啟動文件當中可以設置棧空間大小。如果在函數當中定義的局部變量超過棧空間大小編譯時不會報錯,但運行時極有可能出現錯誤,甚至會導致程序卡死,那么該如何處理呢?
方法一:修改棧空間大小1、找到啟動文件hd.s (例如:是stm32f103 則是 startup_stm32f10x_hd.s) 2、找到啟動文件當中的棧空間大小定義:
//系統默認棧空間大小為 1K Stack_SizeEQU0x000004003、修改棧空間大小//我們修改為4K Stack_SizeEQU0x00001000方法二:將局部變量改為全局變量。
-
單片機
+關注
關注
6037文章
44558瀏覽量
635298 -
寄存器
+關注
關注
31文章
5343瀏覽量
120363 -
STM32
+關注
關注
2270文章
10900瀏覽量
356006 -
堆棧
+關注
關注
0文章
182瀏覽量
19761
原文標題:學習STM32單片機,要理解它的堆棧
文章出處:【微信號:雨飛工作室,微信公眾號:雨飛工作室】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論