你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

详解STM32单片机的堆栈

[复制链接]
STMCU小助手 发布时间:2022-10-31 22:13
学习STM32单片机的时候,总是能遇到“堆栈”这个概念。分享本文,希望对你理解堆栈有帮助。    对于了解一点汇编编程的人,就可以知道,堆栈是内存中一段连续的存储区域,用来保存一些临时数据。堆栈操作由PUSH、POP两条指令来完成。而程序内存可以分为几个区:
  • 栈区(stack)
  • 堆区(Heap)
  • 全局区(static)
  • 文字常亮区程序代码区
    ) q+ e) }  a* g1 x& d6 W* T2 _6 a6 t
    程序编译之后,全局变量,静态变量已经分配好内存空间,在函数运行时,程序需要为局部变量分配栈空间,当中断来时,也需要将函数指针入栈,保护现场,以便于中断处理完之后再回到之前执行的函数。    栈是从高到低分配,堆是从低到高分配。# A# H- h. ]  d7 u% a
普通单片机与STM32单片机中堆栈的区别
! v, s$ x2 C  ]% H6 r8 m    普通单片机启动时,不需要用bootloader将代码从ROM搬移到RAM。
这里我们可以先看看单片机程序执行的过程,单片机执行分三个步骤:
  • 取指令
  • 分析指令
  • 执行指令) t; l: v! v$ M
    根据PC的值从程序存储器读出指令,送到指令寄存器。然后分析执行执行。这样单片机就从内部程序存储器去代码指令,从RAM存取相关数据。
* \* [7 U( e9 U& K- L! F    RAM取数的速度是远高于ROM的,但是普通单片机因为本身运行频率不高,所以从ROM取指令慢并不影响。
% r) i. J! Z  G. z+ c: S. Y$ O    而STM32的CPU运行的频率高,远大于从ROM读写的速度。所以需要用bootloader将代码从ROM搬移到RAM。
. u% c7 ^: y9 ]7 }" y  使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
6 @+ `: ~% E7 t; N4 C  C  O4 Y" M    其实堆栈就是单片机中的一些存储单元,这些存储单元被指定保存一些特殊信息,比如地址(保护断点)和数据(保护现场)。/ ?- o# R. @$ h) d
    如果非要给他加几个特点的话那就是:
  • 这些存储单元中的内容都是程序执行过程中被中断打断时,事故现场的一些相关参数。如果不保存这些参数,单片机执行完中断函数后就无法回到主程序继续执行了。
  • 这些存储单元的地址被记在了一个叫做堆栈指针(SP)的地方。" F* [# R9 h, x8 t; W6 L3 Q

- v6 f" M0 |! n" J" s/ o: w# q9 I
- h* O9 ~0 A) B  }9 k2 D* `
结合STM32的开发讲述堆栈2 T7 y$ O4 X& A; P  X% H/ n
    从上面的描述可以看得出来,在代码中是如何占用堆和栈的。可能很多人还是无法理解,这里再结合STM32的开发过程中与堆栈相关的内容来进行讲述。
& R$ s, r# `, m4 Y7 S    如何设置STM32的堆栈大小?0 \4 r0 ?! h# k3 i2 f5 A/ e
    在基于MDK的启动文件开始,有一段汇编代码是分配堆栈大小的。  R7 b2 }  m7 F
4 ?- t+ ?* M4 ^

. k' n9 t, b4 o# n  \ 微信图片_20221031215329.png
2 _; \/ ?5 z3 t" m  \5 x3 E. c' M6 Z3 m

0 m+ m9 r7 G, j  u# l    这里重点知道堆栈数值大小就行。还有一段AREA(区域),表示分配一段堆栈数据段。数值大小可以自己修改,也可以使用STM32CubeMX数值大小配置,如下图所示。
3 a" o4 N3 X% K6 ~3 x+ \3 F+ s4 L0 L% V) F( b0 G/ {+ f

5 x2 ^1 Z( t) a* q+ D0 N 微信图片_20221031215326.png 7 u* L& ]$ S+ b# Y: ?; U' X5 z

" k- |! ~+ u: a9 L5 Y. e

- h  |" C& f& G: s# L. p    STM32F1默认设置值0x400,也就是1K大小。
! E' f1 ]. ], W$ j' a5 v5 Y6 F' K  e" M& I) a) f
9 L: m/ l& [7 h9 S. u) ^
Stack_Size EQU 0x400 8 B* Z) ]3 x+ Z

4 K" q" O! I+ A5 n# k6 b, G  @$ Q

. @# ]5 C/ U* B/ p; d# c* q3 ?+ n   函数体内局部变量:4 a' Q, `( N! J9 \
void Fun(void){ char i; int Tmp[256]; //...}    局部变量总共占用了256*4 + 1字节的栈空间。所以,在函数内有较多局部变量时,就需要注意是否超过我们配置的堆栈大小。+ w+ X4 Q- U- N7 W! m9 e
. p* ]6 ?$ G" Y& |
8 |: c0 U1 p. r% G/ P  j6 u: k0 `
    函数参数:7 R5 u6 C; ?1 j( V: r2 u
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)    这里要强调一点:传递指针只占4字节,如果传递的是结构体,就会占用结构大小空间。提示:在函数嵌套,递归时,系统仍会占用栈空间。( T4 J/ Q4 `5 s  r2 {! g

4 o( o6 t# w8 |0 ^. I
$ V: H7 z7 b& |& n% g$ q
    堆(Heap)的默认设置0x200(512)字节。
1 L, l- k2 P  p6 g1 P
Heap_Size EQU 0x200, a- {' N/ G) [9 {% w: R" W
; h' j" k! r+ @4 [; t

: c4 J5 l8 C5 k+ w: q/ o    大部分人应该很少使用malloc来分配堆空间。虽然堆上的数据只要程序员不释放空间就可以一直访问,但是,如果忘记了释放堆内存,那么将会造成内存泄漏,甚至致命的潜在错误。
8 l, R8 |$ W% G  ]7 F* |# D! U0 Z% H9 e
3 U8 A; q" W* N; v
MDK中RAM占用大小分析
: t3 u, H) L% c( ^   经常在线调试的人,可能会分析一些底层的内容。这里结合MDK-ARM来分析一下RAM占用大小的问题。在MDK编译之后,会有一段RAM大小信息:/ M( Z* g1 R& J6 T& P

& q7 l6 @  k2 g  ]+ F1 C$ z
1 Y  r! O; v- i8 R' \! A$ d9 P
微信图片_20221031215322.png    
& ~' Z# T% Y9 w3 y( |) w& H. k7 t3 x/ G$ u7 T+ e

( y  ?6 a, T! P- R" R# e这里4+6=1640,转换成16进制就是0x668,在进行在调试时,会出现:* X' F# [2 \# r1 p6 L8 Y8 f& B

* ?8 {: u# W2 m4 T
微信图片_20221031215319.png
, K9 x8 n7 `* t" z8 h
6 q' {0 u3 W& j* v) p. }' ?

# y0 V& h( m# y% S" x    这个MSP就是主堆栈指针,一般我们复位之后指向的位置,复位指向的其实是栈顶:
/ Z9 U6 M* n8 x" Y" [4 `7 N% l6 p4 H

5 @% O7 F6 r; b! K" f 微信图片_20221031215316.png    
4 b' K( A3 Y  S) T! e6 O, }) n  t( e5 d6 v9 v, I6 W$ s
! ~6 ^8 P9 X3 _& `! {
而MSP指向地址0x20000668是0x20000000偏移0x668而得来。具体哪些地方占用了RAM,可以参看map文件中【Image Symbol Table】处的内容:
0 ?2 \6 i" }' _7 H8 u# S9 J" p& _/ w2 ?1 s+ Z6 e
微信图片_20221031215312.png
5 A$ t: v& u, F2 J' P& m4 L1 k  R
' q# k/ w; v, C  f1 X4 G" q  x( L+ r" l1 M
转载自:STM32嵌入式开发* O! [0 R$ a- C, q
收藏 评论0 发布时间:2022-10-31 22:13

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版