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

【经验分享】MDK+STM32F2X7VG+ucos_II

[复制链接]
STMCU小助手 发布时间:2021-12-4 19:03
20191202183636951.png
6 [; V: S3 ~/ Y4 e$ V, E7 K, F

2 Y9 Z! F- ]9 s8 l" p: q) U以下引用网上资料 理解堆和栈的区别
: N, G. P8 R3 D6 R1 }
! V# K/ s. Q/ E# x3 G2 `(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似
# V/ V$ T$ T% S( l- \9 T2 n5 H4 R( _8 j
于数据结构中的栈。: Q1 a- v8 |% m5 `/ `' z! i
; K$ m5 \( k5 y* D, e5 f9 O
(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配! M, k' @- g4 F$ F7 b# _
7 f2 ^2 A! ^9 H6 s/ b: ~
方式类似于数据结构中的链表。0 Y% S7 s2 d. M) R1 O  g
6 i( Q+ j7 O' @% `5 P
(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态. ]6 V( r  y% \# f

- i5 S" e' n! Z; g变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系! L/ D# h$ @  X3 b

' Q3 ?6 i1 v/ s$ k统自动释放。' D4 ]5 U/ O. d9 M+ Z9 w( V' `9 y
3 ^% w9 d2 B3 O8 }' t9 r- u# u  k: q
(4)文字常量区:常量字符串就是存放在这里的。
4 H% l3 J/ X& z" U& |/ h9 O& Q: k
(5)程序代码区:存放函数体的二进制代码。- M0 D# r& U6 R# K& t, R

6 x; j2 h+ K! @$ F) W( x# n例如:5 r2 U+ h  _( ~" F  E" X
7 t. R- J- Y8 s  {, `
int a=0;   //全局初始化区/ \- v3 w6 A/ y; w$ D: i
$ ?) z3 w. z+ ~
char *p1;   //全局未初始化区* T' n5 ^1 P- \* u! q

5 X7 D. h6 K% e6 Q# ]. \4 hmain()' K9 ]2 g* h5 h9 @/ Z8 g

5 C( ?* }1 k) \  o0 b{
* j7 y+ q/ J$ ~0 d, kint b;   //栈
) a1 F" e5 t- Y+ j, C1 r# t2 J0 W7 C2 S7 T
char s[]="abc";   //栈, |& {- Y1 ^: o3 D) [

  D3 b& y, S# Zchar *p3= "1234567";   //在文字常量区Flash
1 Q* k* r, V' f' M2 r! I8 w9 k. w! z/ ~$ ]& M
static int c =0 ;   //静态初始化区7 L# @8 C+ ]) s

* o! F  F$ w0 a& n# e, Jp1= (char *)malloc(10);   //堆区" C* Y! }6 d" V

( t  P; F  S4 }- A8 x  W! ostrcpy(p1,"123456");   //"123456"放在常量区1 t4 d% h: W" a; j: O; D' i  O6 _
$ {( q. `1 M/ U9 s: O$ ]9 o6 G
}* y; [+ I$ C  b6 j) L, Y+ K( N7 L

+ `6 ~6 z* E+ {1 k所以堆和栈的区别:, i$ G, |0 ~) F  G
4 G$ @" r, b  d% Q
stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。
/ U" U& s4 p  ?& k4 g
9 o$ K0 o4 s( L: m7 vstack的空间有限,heap是很大的自由存储区。. @  d8 `) x+ c. s4 Y6 x8 m
' P7 u- L( f3 e! G" c
程序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。/ Y: c) m  H( I! C  t

5 ~4 U7 M2 C  X6 g# d
' w! I8 r6 m5 |- g: p! |+ U" |( p8 o3 l- A# z  P# h' t
------------------------------------------------------------------------------------------------------
4 |) I/ J4 S7 P  S3 b6 [- v$ `9 h6 o' C# F6 v3 y
1.堆和栈大小( t' {/ \/ y5 \8 ^5 x& e5 p2 i

5 C9 V( a3 s( e; q( o+ J, [定义大小在startup_stm32f2xx.s
: `; H0 W; V, [9 ^( j4 j$ R. j. t1 ^; [4 e' \
Stack_Size  EQU  0x00000400# [  B3 K! D4 y

/ d9 G2 b' x5 |8 ?  ?AREA  STACK, NOINIT, READWRITE, ALIGN=3 8 H4 b9 Y# O6 @& B+ e5 V" N
Stack_Mem  SPACE  Stack_Size
. h$ J$ O; t& n' b# X__initial_sp' E1 u1 J9 ?) H
' B; z5 Y* l6 F8 \: f, ?
; Heap Configuration
5 ?: |1 z! u$ Y% e$ i; x;  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+ f' t5 d5 Y. \2 C;+ i6 R+ g% N: P( J7 Y6 [
3 @5 P: O5 M" Q5 j: |6 M
Heap_Size  EQU  0x00000200
; ]' e! {: M  d1 C5 y9 {5 O' u. ?0 y5 i' h7 _2 J; ^3 u
AREA  HEAP, NOINIT, READWRITE, ALIGN=3 - R* L  r4 M7 C- p4 \" h( \
__heap_base/ V3 |3 M! S% R5 [% v

* s4 O' e  a5 Y0 ]; }3 @. ]* r; L2.堆和栈位置
3 F6 C4 [. G5 m/ T; s" T
8 ?' Z" [, z3 O0 D7 V通过MAP文件可知1 J# n. M/ I2 Q1 A

. [% u- g+ _! l% N/ u  QHEAP  0x200106f8  Section  512  startup_stm32f2xx.o(HEAP)
  T* X9 s2 L* `! H9 nSTACK  0x200108f8  Section  1024  startup_stm32f2xx.o(STACK); o% F, A3 [% W6 F
3 n6 }3 ?5 F- O: W' x: B
__heap_base  0x200106f8  Data  0  startup_stm32f2xx.o(HEAP) 6 ~$ Z( d' [; J' R; Y
__heap_limit  0x200108f8  Data  0  startup_stm32f2xx.o(HEAP) * {; _& ]+ i; @& A
__initial_sp  0x20010cf8  Data  0  startup_stm32f2xx.o(STACK)
0 V* I3 x2 m. s# p! }+ C' ]
8 C1 |/ p9 T! W( w显然 Cortex-m3资料可知:__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成)* s. r' P  ^# i1 s( C/ R
2 A3 A; S( {  }' @3 G
显然堆和栈是相邻的。
# G6 `2 o: ~( {, d( r
  v- c+ r( v, \: d( m& N6 O
aHR0cDovL2ltYWdlcy5jbml0YmxvZy5jb20vYmxvZy81MTk3MDQvMjAxMzExLzA2MTEzNzI5LTc4NTJi.png
3 a4 f& F0 `$ d6 o7 M
3.堆和栈空间分配
" @3 N8 u* ?" Q6 G  [" L- c" S. S7 I: P: x1 _% T
栈:向低地址扩展
- Y8 L& L9 P: M/ t$ r
/ `  ?: c4 G5 ?堆:向高地址扩展
7 K9 t8 ]- G' T' P+ j
2 O* v2 D) H. o$ \显然如果依次定义变量# F  B- m+ O' _: R" g

0 o# B1 f4 y/ E/ p7 d先定义的栈变量的内存地址比后定义的栈变量的内存地址要大- R" y; ~0 B* w: T! J$ f- f/ D; K
3 S) o2 \- e1 n6 y0 g% F
先定义的堆变量的内存地址比后定义的堆变量的内存地址要小
, P) |1 X$ V+ y7 ]/ z7 K: b* U+ }& S3 v
/ N) B: q: K9 I4.堆和栈变量/ ]" O% }1 Y$ [" ?

- l, c3 C) x% d/ w- K! S$ r栈:临时变量,退出该作用域就会自动释放
2 h9 w" {$ ]: f( S% X3 T2 n
0 v5 _2 @; J# V. K' c堆:malloc变量,通过free函数释放
3 Z5 H0 o$ u. R9 H) o4 E% G1 \! P) ~- d$ r9 d
另外:堆栈溢出,编译不会提示,需要注意+ K2 Z; v7 @/ e/ V" H' L( W3 a! {' Y
- q' e9 G$ }/ b# ^- J8 K5 q; {

; A8 G9 d3 t' `! c0 B
" T/ m/ X2 E# F  h$ t------------------------------------------------------------------------------------------------------7 C5 f  i# U6 E0 P/ b
, X; H% L& n5 e# g  R/ U
7 S& U/ D! y1 w' S' h% ~+ l
" M. U  e( a' w! D( Q
如果使用了HEAP,则必须设置HEAP大小。 0 r% b% N' k. L7 K
如果是STACK,可以设置为0,不影响程序运行。
! e& ^! Z3 P3 V* p$ C6 |# N: zIAR STM8定义STACK,是预先在RAM尾端分配一个字节的区域作为堆栈预留区域。 + i2 u7 P) D: K1 Y* \% Z
当程序静态变量,全局变量,或者堆与预留堆栈区域有冲突,编译器连接的时候就会报错。
4 U- I5 [  L; |$ O# a你可以吧STACK设置为0,并不影响运行。(会影响调试,调试会报堆栈溢出警告)。 $ y; p2 a' L; O; S& {  E" f# a; s% c
其实没必要这么做。 - b8 d  E3 S# J0 n9 |. o
一般程序,(在允许范围内)设置多少STACK,并不影响程序真实使用的RAM大小, , Q) o! O  p6 g# g8 A1 {( k# [
(可以试验,把STACK设置多少,编译出来的HEX文件都是一样),
# T+ a0 i8 i; T( X: {/ }' I3 ~程序还是按照它原本的状态使用RAM,把STACK设置为0,并不是真实地减少RAM使用。
& R* O, l+ C1 O% c) f% C仅仅是欺骗一下编译器,让程序表面上看起来少用了RAM。
0 J2 t8 q- t0 p8 U2 |而设置一定size的STACK,也并不是真的就多使用了RAM,只是让编译器帮你 2 V. y8 r& r" ?# X
检查一下,是否能够保证有size大小的RAM没有被占用,可以用来作为堆栈。
  ^2 C1 I- V$ |) c' O) b9 A以上仅针对IAR STM8./ A5 U- r: Q) p% e2 e6 ^

" r7 e4 M/ W. `( Z. K( D5 s; Y) A, ?' V5 [
) ?1 U2 `6 b  e3 A0 p# e
------------------------------------------------------------------------------------------------------" y# Q2 x3 f3 C& D

6 ?+ O9 t- Q1 ^# t7 A' A0 x, T
9 K0 w0 }3 W6 N- Y" {1 H5 O8 u4 ^4 @
从以上网摘来看单片机的堆和栈是分配在RAM里的,有可能是内部也有可能是外部,可以读写;5 _8 V/ _2 g. p4 }' f3 e
6 R$ k' u2 Z1 u" y" S8 s

' ~7 j2 L* q- d5 N2 U- f8 r: x$ T3 P1 f0 W# H) b! |2 x
栈:存函数的临时变量,即局部变量,函数返回时随时有可能被其他函数栈用。所以栈是一种分时轮流使用的存储区,. e# l( d! U. _: k) H

& }* W6 f5 {) y* ^7 N7 P0 Y      编译器里定义的Stack_Size,是为了限定函数的局部数据活动的范围,操过这么范围有可以跑飞,也就是栈溢出;
1 m  R9 ~0 h/ n, C$ D% r
* C6 I# D: W" s* {0 e, V$ U5 W     Stack_Size不影响Hex,更不影响Hex怎么运行的,只是在Debug调试时会提示错。栈溢出也有是超过了国界进行
. O: }& O% S9 y2 Z; g/ d2 l; ?
+ `4 W( l3 ~  ?; @7 \9 o2 P5 F, U     活动,只要老外没有意见,你可以接着玩,有老外不让你玩,你就的得死,或是大家都死(互相撕杀),有的人写) |+ u% ]5 x. F& X2 Q: w* q  a9 J

6 B- h( }$ ]; e% q, X$ p# P# \    单片机代码在函数里定义一个大数组 int buf[8192],栈要是小于8192是会死的很惨。6 \, J; _! C/ d1 ]

+ [1 Z0 G) K1 X# X! ?8 U' J/ ~& d
2 Y& I& y# r+ E7 I* f% e' A! Z
9 E. l$ j" ]0 l0 p( {$ P! g* Y3 N! J堆:存的是全局变量,这变量理论上是所有函数都可以访问的,全局变量有的有初始值,但这个值不是存在RAM里的,是
+ J& {/ E4 ~  U* i( H3 S$ J) W+ k& @# _$ ^) x- i& P1 \- n% }! w( b& r
     存在Hex里,下载到Flash里,上电由代码(编译器生成的汇编代码)搬过去的。有的人很“霸道”,上电就霸占已一块很
& Z" d7 E/ j" T" b, C' V3 C6 u0 d. j6 {, k
    大的RAM(Heap_Size),作为己有(malloc_init),别人用只能通过他们管家借(malloc),用完还得换(free)。所以  
0 K, Z# @8 `' z' g* L6 U+ \0 V* G+ S2 E# b0 K
    一旦有“霸道”的人出现是编译器里必须定义Heap_Size,否则和他管家借也没有用。* M* s1 _9 E4 s" i; p. s! n. |) J
% t& u- O2 z3 R/ K8 X# D
/ W" o0 S/ \  F% I" H$ {. V* D7 E

' _/ T0 A& e' w' x% o# F! P1 K总之:堆和栈有存在RAM里,他两各分多少看函数需求,但是他两的总值不能超过单片机硬件的实际RAM尺寸,否则只能* ?, Q( @1 ~' v" i8 H

9 T7 q2 t/ T( j8 P' ]     到海里玩(淹死了)或是自己打造船接着玩(外扩RAM)。
2 w$ a9 |' V4 h6 E  D, Q" T7 G
- m6 {6 u  m) `$ O7 d1 U
, O- m: W# C: Y2 E0 x: S5 i( S
收藏 评论0 发布时间:2021-12-4 19:03

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版