您好,欢迎访问三七文档
一基础知识字节8位半字16位字32位二解惑Code,RO-data,RW-data,ZI-dataCode为程序代码部分RO-data表示程序定义的常量consttemp;RW-data表示已初始化的全局变量ZI-data表示未初始化的全局变量ProgramSize:Code=18248RO-data=320RW-data=260ZI-data=3952Code,RO-data,RW-data............flashRW-data,ZIdata...................RAM三详细分析初始化时RW-data从flash拷贝到RAM生成的map文件位于list文件夹下(KEIL)TotalROSize(Code+ROData)18568(18.13kB)TotalRWSize(RWData+ZIData)4212(4.11kB)TotalROMSize(Code+ROData+RWData)18828(18.39kB)ARM指令的长度刚好是1个字(分配为占用4个字节),Thumb指令的长度刚好是半字(占用2个字节)R0-R15(R15-PC,R14-LR,R13-SP)32位每个异常模式还带有一个程序状态保存寄存器(SPSR),它用于保存在异常事件发生之前的CPSRLDMIAR1!,{R2-R7,R12};将R1单兀中的数据读出到R2-R7,R12,R1自动加1STMIARO!,{R3-R6,R10};将R3-R6,R10中的数据保存到RO指向的地址,RO自动加1在数据传送之前,将偏移量加到Rn中,其结果作为传送数据的存储地址.若使用后缀“!”,则结果写回到Rn中,且Rn值不允许为R15.指令举例如下:LDRRd,[Rn,#Ox4]!LDMFDSP!,{R0-R3,PC}^;中断返回“^”符号表示这是一条特殊形式的指令。这条指令在从存储器中装载PC的同时(PC是最后恢复的),CPSR也得到恢复大端格式(Big-endian)小端格式(Little-endian)数据0x12345678存储格式大端格式低地址----0x12|0x34|0x56|0x78----高地址小端格式低地址----0x78|0x56|0x34|0x12----高地址ARM微处理器支持7种运行模式,分别为:CPSRM[4:0]1.用户模式(usr):ARM处理器正常的程序执行状态。100002.快速中断模式(fiq):用于高速数据传输或通道处理。100013.外部中断模式(irq):用于通用的中断处理。100104.管理模式(svc):操作系统使用的保护模式。100115.数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护。101116.系统模式(sys):运行具有特权的操作系统任务。111117.定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。11011ARM正常工作一般工作在用户模式和系统模式,复位的时候进入管理模式。对于ARM指令集来说,PC指向当前指令的下两条指令的地址,注意pc,在调试的时候显示的是当前指令地址,而用movlr,pc的时候lr保存的是此指令向后数两条指令的地址假设反汇编代码:0x000001:movlrpc(此时查看PC寄存器的值是0x000001,但实际PC值是0x000003,lr里面保存的就是0x000003)fields指定传送的区域(psrCPSR或SPSR)c控制域屏蔽字节(psr[7..0])x扩展域屏蔽字节(psr[15..8])s状态域屏蔽字节(psr[23..16])f标志域屏蔽字节(psr[31..24])例如:MSRcpsr_c,#0xD3;CPSR[7...0]=0xD3关于堆和栈已经是程序员的一个月经话题,大部分有是基于os层来聊的。那么,在赤裸裸的单片机下的堆和栈是什么样的分布呢?以下是网摘:刚接手STM32时,你只编写一个intmain(){while(1);}BUILD://ProgramSize:Code=340RO-data=252RW-data=0ZI-data=1632编译后,就会发现这么个程序已用了1600多的RAM,要是在51单片机上,会心疼死了,这1600多的RAM跑哪儿去了,分析map,你会发现是堆和栈占用的,在startup_stm32f10x_md.s文件中,它的前面几行就有以上定义,这下该明白了吧。Stack_SizeEQU0x00000400Heap_SizeEQU0x00000200以下引用网上资料理解堆和栈的区别(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表。(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统自动释放。(4)文字常量区:常量字符串就是存放在这里的。(5)程序代码区:存放函数体的二进制代码。例如:inta=0;//全局初始化区char*p1;//全局未初始化区main(){intb;//栈chars[]=abc;//栈char*p3=1234567;//在文字常量区Flashstaticintc=0;//静态初始化区p1=(char*)malloc(10);//堆区strcpy(p1,123456);//123456放在常量区}所以堆和栈的区别:stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。stack的空间有限,heap是很大的自由存储区。程序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。------------------------------------------------------------------------------------------------------1.堆和栈大小定义大小在startup_stm32f2xx.sStack_SizeEQU0x00000400AREASTACK,NOINIT,READWRITE,ALIGN=3Stack_MemSPACEStack_Size__initial_sp;HeapConfiguration;HeapSize(inBytes)0x0-0xFFFFFFFF:8;Heap_SizeEQU0x00000200AREAHEAP,NOINIT,READWRITE,ALIGN=3__heap_base2.堆和栈位置通过MAP文件可知HEAP0x200106f8Section512startup_stm32f2xx.o(HEAP)STACK0x200108f8Section1024startup_stm32f2xx.o(STACK)__heap_base0x200106f8Data0startup_stm32f2xx.o(HEAP)__heap_limit0x200108f8Data0startup_stm32f2xx.o(HEAP)__initial_sp0x20010cf8Data0startup_stm32f2xx.o(STACK)显然Cortex-m3资料可知:__initial_sp是堆栈指针,它就是FLASH的0x8000000地址前面4个字节(它根据堆栈大小,由编译器自动生成)显然堆和栈是相邻的。3.堆和栈空间分配栈:向低地址扩展堆:向高地址扩展显然如果依次定义变量先定义的栈变量的内存地址比后定义的栈变量的内存地址要大先定义的堆变量的内存地址比后定义的堆变量的内存地址要小4.堆和栈变量栈:临时变量,退出该作用域就会自动释放堆:malloc变量,通过free函数释放另外:堆栈溢出,编译不会提示,需要注意------------------------------------------------------------------------------------------------------如果使用了HEAP,则必须设置HEAP大小。如果是STACK,可以设置为0,不影响程序运行。IARSTM8定义STACK,是预先在RAM尾端分配一个字节的区域作为堆栈预留区域。当程序静态变量,全局变量,或者堆与预留堆栈区域有冲突,编译器连接的时候就会报错。你可以吧STACK设置为0,并不影响运行。(会影响调试,调试会报堆栈溢出警告)。其实没必要这么做。一般程序,(在允许范围内)设置多少STACK,并不影响程序真实使用的RAM大小,(可以试验,把STACK设置多少,编译出来的HEX文件都是一样),程序还是按照它原本的状态使用RAM,把STACK设置为0,并不是真实地减少RAM使用。仅仅是欺骗一下编译器,让程序表面上看起来少用了RAM。而设置一定size的STACK,也并不是真的就多使用了RAM,只是让编译器帮你检查一下,是否能够保证有size大小的RAM没有被占用,可以用来作为堆栈。以上仅针对IARSTM8.------------------------------------------------------------------------------------------------------从以上网摘来看单片机的堆和栈是分配在RAM里的,有可能是内部也有可能是外部,可以读写;栈:存函数的临时变量,即局部变量,函数返回时随时有可能被其他函数栈用。所以栈是一种分时轮流使用的存储区,编译器里定义的Stack_Size,是为了限定函数的局部数据活动的范围,操过这么范围有可以跑飞,也就是栈溢出;Stack_Size不影响Hex,更不影响Hex怎么运行的,只是在Debug调试时会提示错。栈溢出也有是超过了国界进行活动,只要老外没有意见,你可以接着玩,有老外不让你玩,你就的得死,或是大家都死(互相撕杀),有的人写单片机代码在函数里定义一个大数组intbuf[8192],栈要是小于8192是会死的很惨。堆:存的是全局变量,这变量理论上是所有函数都可以访问的,全局变量有的有初始值,但这个值不是存在RAM里的,是存在Hex里,下载到Flash里,上电由代码(编译器生成的汇编代码)搬过去的。有的人很“霸道”,上电就霸占已一块很大的RAM(Heap_Size),作为己有(malloc_init),别人用只能通过他们管家借(malloc),用完还得换(free)。所以一旦有“霸道”的人出现是编译器里必须定义Heap_Size,否则和他管家借也没有用。总之:堆和栈有存在RAM里,他两各分多少看函数需求,但是他两的总值不能超过单片机硬件的实际RAM尺寸,否则只能到海里玩(淹死了)或是自己打造船接着玩(外扩RAM)。
本文标题:STM32堆栈学习
链接地址:https://www.777doc.com/doc-2860956 .html