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

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

搜索
查看: 4722|回復(fù): 3
收起左側(cè)

詳解STM32單片機的堆棧

[復(fù)制鏈接]

131

主題

512

帖子

1666

積分

三級會員

Rank: 3Rank: 3

積分
1666
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2021-4-3 14:52:57 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
學(xué)習(xí)STM32單片機的時候,總是能遇到“堆棧”這個概念。分享本文,希望對你理解堆棧有幫助。
    對于了解一點匯編編程的人,就可以知道,堆棧是內(nèi)存中一段連續(xù)的存儲區(qū)域,用來保存一些臨時數(shù)據(jù)。堆棧操作由PUSH、POP兩條指令來完成。而程序內(nèi)存可以分為幾個區(qū):
棧區(qū)(stack)
堆區(qū)(Heap)
全局區(qū)(static)
文字常亮區(qū)程序代碼區(qū)
    程序編譯之后,全局變量,靜態(tài)變量已經(jīng)分配好內(nèi)存空間,在函數(shù)運行時,程序需要為局部變量分配?臻g,當中斷來時,也需要將函數(shù)指針入棧,保護現(xiàn)場,以便于中斷處理完之后再回到之前執(zhí)行的函數(shù)。
    棧是從高到低分配,堆是從低到高分配。
普通單片機與STM32單片機中堆棧的區(qū)別
    普通單片機啟動時,不需要用bootloader將數(shù)據(jù) 從ROM搬移到RAM。
    但是STM32單片機需要。
    這里我們可以先看看單片機程序執(zhí)行的過程,單片機執(zhí)行分三個步驟:
取執(zhí)行
分析指令
執(zhí)行指令
    根據(jù)PC的值從程序存儲器讀出指令,送到指令寄存器。然后分析執(zhí)行執(zhí)行。這樣單片機就從內(nèi)部程序存儲器去代碼指令,從RAM存取相關(guān)數(shù)據(jù)。
    RAM取數(shù)的速度是遠高于ROM的,但是普通單片機因為本身運行頻率不高,所以從ROM取指令慢并不影響。
    而STM32的CPU運行的頻率高,遠大于從ROM讀寫的速度。所以需要用bootloader將數(shù)據(jù) 從ROM搬移到RAM。
    使用棧就象我們?nèi)ワ堭^里吃飯,只管點菜(發(fā)出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。使用堆就象是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。
    其實堆棧就是單片機中的一些存儲單元,這些存儲單元被指定保存一些特殊信息,比如地址(保護斷點)和數(shù)據(jù)(保護現(xiàn)場)。
    如果非要給他加幾個特點的話那就是:
這些存儲單元中的內(nèi)容都是程序執(zhí)行過程中被中斷打斷時,事故現(xiàn)場的一些相關(guān)參數(shù)。如果不保存這些參數(shù),單片機執(zhí)行完中斷函數(shù)后就無法回到主程序繼續(xù)執(zhí)行了。
這些存儲單元的地址被記在了一個叫做堆棧指針(SP)的地方。
結(jié)合STM32的開發(fā)講述堆棧
    從上面的描述可以看得出來,在代碼中是如何占用堆和棧的?赡芎芏嗳诉是無法理解,這里再結(jié)合STM32的開發(fā)過程中與堆棧相關(guān)的內(nèi)容來進行講述。
    如何設(shè)置STM32的堆棧大。
    在基于MDK的啟動文件開始,有一段匯編代碼是分配堆棧大小的。


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


    在IAR中,是通過工程配置堆棧大小,如下圖所示。


    STM32F1默認設(shè)置值0x400,也就是1K大小。
Stack_Size EQU 0x400
    函數(shù)體內(nèi)局部變量:
void Fun(void){ char i; int Tmp[256]; //...}
    局部變量總共占用了256*4 + 1字節(jié)的棧空間。所以,在函數(shù)內(nèi)有較多局部變量時,就需要注意是否超過我們配置的堆棧大小。
    函數(shù)參數(shù):
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
    這里要強調(diào)一點:傳遞指針只占4字節(jié),如果傳遞的是結(jié)構(gòu)體,就會占用結(jié)構(gòu)大小空間。提示:在函數(shù)嵌套,遞歸時,系統(tǒng)仍會占用?臻g。
    堆(Heap)的默認設(shè)置0x200(512)字節(jié)。
Heap_Size EQU 0x200
    大部分人應(yīng)該很少使用malloc來分配堆空間。雖然堆上的數(shù)據(jù)只要程序員不釋放空間就可以一直訪問,但是,如果忘記了釋放堆內(nèi)存,那么將會造成內(nèi)存泄漏,甚至致命的潛在錯誤。
MDK中RAM占用大小分析
    經(jīng)常在線調(diào)試的人,可能會分析一些底層的內(nèi)容。這里結(jié)合MDK-ARM來分析一下RAM占用大小的問題。在MDK編譯之后,會有一段RAM大小信息:


    這里4+6=1640,轉(zhuǎn)換成16進制就是0x668,在進行在調(diào)試時,會出現(xiàn):


    這個MSP就是主堆棧指針,一般我們復(fù)位之后指向的位置,復(fù)位執(zhí)向的其實是棧頂:


    而MSP指向地址0x20000668是0x20000000偏移0x668而得來。具體哪些地方占用了RAM,可以參看map文件中【Image Symbol Table】處的內(nèi)容:













回復(fù)

使用道具 舉報

131

主題

512

帖子

1666

積分

三級會員

Rank: 3Rank: 3

積分
1666
沙發(fā)
發(fā)表于 2021-4-3 14:53:13 | 只看該作者
需要做PCB線路板的可以聯(lián)系我

13651479995
回復(fù) 支持 反對

使用道具 舉報

lyl

1

主題

1119

帖子

3525

積分

四級會員

Rank: 4

積分
3525
板凳
發(fā)表于 2021-5-6 08:34:04 | 只看該作者
資料很好,學(xué)習(xí)學(xué)習(xí)
回復(fù) 支持 反對

使用道具 舉報

3

主題

2721

帖子

3052

積分

四級會員

Rank: 4

積分
3052
地板
發(fā)表于 2021-6-4 11:39:00 | 只看該作者
1111111111111111111111111
回復(fù) 支持 反對

使用道具 舉報

發(fā)表回復(fù)

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

本版積分規(guī)則


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