stm32中断堆栈_STM32入门系列-启动文件介绍

在启动文件内部使用的都是汇编语言,这个文件的作用是负责执行微控制器从“复位”到“开始执行 main 函数”中间这段启动时间所必须进行的工作。它完成的具体工作有:

  • 初始化堆栈指针SP=_initial_sp
  • 初始化PC指针=Reset_Handler
  • 初始化中断向量表
  • 配置系统时钟
  • 调用C库函数_main初始化用户堆栈,从而转向我们用户应用程序的main。

汇编指令

打开STM32的启动文件会发现,里面全部都是汇编语句,对于汇编指令不了解的朋友来说可能一头雾水。下面我们按照启动文件内指令出现的顺序来介绍,相信可以了解到大概情况。

EQU:给数字常量取一个符号名, 相当于C语言中的预处理命令define。其常用格式如下:


Stack_Size EQU 0x00000400


表示将0x00000400这个数值,用Stack_Size名代替。

AREA:汇编一个新的代码段或者数据段。常用格式如下:


AREA STACK, NOINIT, READWRITE, ALIGN=3


表示汇编一个数据段,名字是STACK,NOINIT表示不初始化,READWRITE表示可读可写,ALIGN表示字节对齐,通常后面会赋一个立即数,比如ALIGN=3表示的就是2^3字节对齐,即8字节对齐。

SPACE:分配一定大小的内存空间,单位为字节。常用格式如下:


Stack_Mem SPACE Stack_Size


表示给Stack_Mem分配一个Stack_Size大小的内存空间。通常它后面还会跟随一个__initial_sp语句,表示栈的结束地址,即栈顶地址,因为栈是由高向低生长的。

PRESERVE8:当前文件堆栈需按照8字节对齐。格式:直接写此指令即可。

THUMB:表示后面指令兼容THUMB指令。在ARM以前的指令集中有16位的THUMBM指令,现在Cortex-M系列使用的都是THUMB-2指令集,THUMB-2是32位的,兼容16位和32位的指令,是THUMB的超级版。格式:直接写此指令即可。

EXPORT:声明一个具有全局属性的标号,可被外部文件使用。常用格式如下:


EXPORT __Vectors


表示__Vectors标号具有全局属性,外部文件可以调用它。

DCD:以字为单位分配内存, 要求4字节对齐, 并要求初始化这些内存。常用格式如下:


DCD Reset_Handler ; Reset Handler


表示给Reset_Handler名称的地址分配内存并初始化, 这个名称地址可以在“STM32F4xx中文参考手册”-“中断和事件”-“中断和异常向量”章节中找到。在那个函数名后面还有一个“;”, 在汇编程序中“;”即注释,和C语言中的//类似效果。在后面的学习中会接触很多的中断函数,这些中断函数名都可在DCD这部分找到。

PROC:定义子程序。常用格式:


; Reset handler

Reset_Handler PROC

EXPORT Reset_Handler [WEAK]

IMPORT SystemInit

IMPORT __main

LDR R0, =SystemInit

BLX R0

LDR R0, =__main

BX R0

ENDP


表示定义一个全局的子程序Reset_Handler,需与ENDP成对使用,表示子程序结束。在


EXPORT Reset_Handler [WEAK]


后面有一个[WEAK],这个是弱定义,如果外部文件声明了一个标号,则优先使用外部文件定义的标号,如果外部文件没有定义也不出错。要注意的是:这个并不是ARM的指令,是编译器的。

LDR:从存储器中加载字到一个寄存器中。常用格式:


LDR R0, =SystemInit


BLX:跳转到由寄存器给出的地址,并根据寄存器的LSE确定处理器的状态,还要把跳转前的下条指令地址保存到LR。常用格式:


BLX R0


BX:跳转到由寄存器/标号给出的地址,不用返回。常用格式:


BX R0


IMPORT:声明标号来自外部文件,和C语言中的extern关键字类似。


IMPORT SystemInit

IMPORT __main


上述代码中表示声明SystemInit和main为外部文件,所以 在创建寄存器模板的时候写一个SystemInit()空函数。如果想修改main.c文件中的main函数名,在这个地方就可以改动,然后后面


LDR R0, =__main


中的main也需要改动,对汇编不了解的不建议改动。

B:跳转到一个标号。常用格式如下:


B .


在B后面有一个“.”,在汇编语言中表示循环。这句话的意思就是说跳进了循环。

IF,ELSE,ENDIF:汇编条件分支语句,与C语言的if else类似。其常用格式:


IF :DEF:__MICROLIB

EXPORT __initial_sp

EXPORT __heap_base

EXPORT __heap_limit

ELSE

IMPORT __use_two_region_memory

EXPORT __user_initial_stackheap

ENDIF


END:到达文件的末尾,文件结束。

到这里启动文件指令就介绍完了, 有的朋友在学习过程中还会遇到其他的汇编指令,那么怎么查找它们的功能和用法呢?其实很简单,KEIL5软件内已经给我们提供了帮组文档,打开Help选项就会弹出帮助文档,如下图所示。

4989d93ab06df3c114f74a0ac7d9ead2.png

帮助文档的界面如下图所示,如果要查找AREA指令,只需要选择搜索,输入要搜索的指令,选择列出主题即可。选择对应的指令,右侧就会显示指令的具体介绍和格式说明。

587c8f94793e7c65934359432ba26390.png

堆栈

学习过C语言的朋友对堆栈这一词很熟悉。在启动文件开始处就定义了一堆栈的大小,代码如下:


;栈空间的开辟

Stack_Size EQU 0x00000400

AREA STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem SPACE Stack_Size

__initial_sp ;栈的结束地址

;堆空间的开辟

Heap_Size EQU 0x00000200

AREA HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem SPACE Heap_Size

__heap_limit ;堆的结束地址


在程序开头开辟了一个0x00000400即1KB的Stack_Size栈空间。 栈主要用于存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。栈的大小不能超过内部RAM的大小。假如开发的程序占用的RAM比较大,局部变量使用的比较多,那么可以在启动文件内修改这个Stack_Size值。

如果程序出现了莫名其妙的错误,并进入了硬fault的时候,你就要考虑下是不是栈不够大,溢出了的问题。通常我们修改最多的还是栈值。

程序紧接着又开辟了一个0x00000200即512字节的Heap_Size堆空间。堆中的内存一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表。堆和栈生长方式是相反的,堆是由低向高生长的,而栈是由高向低生长的。

e6982916c4c129725a6de89993877a3b.png
嵌入式开发直播课 - 轻松掌握STM32电机驱动 - 创客学院直播室​www.makeru.com.cn
23f8ffa485b7d5eabddfc2cba445ee96.png
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值