STM32启动文件

如何获取STM32启动文件

接触过STM32单片机的都知道,使用STM32开发肯定是需要添加启动文件的,讲解STM32的教材或教材或多或少都会在建立工程文件的入门部分内容中讲解一些关于启动文件相关的知识,而不会像51单片机教材那样几乎啥都不会说明。部分原因就是STM32单片机内核比51复杂很多,开发过程中我们很有可能需要对启动文件或其他一些内核依赖文件做一些处理。并且如果是用keil建立工程时软件不会像建立51工程那样问你要不要添加启动文件进去了,需要自己根据所以用的芯片型号手动选择文件添加。

在建立工程时教程里面都会告你需要在哪些文件夹中去复制哪些文件到工程文件夹,其中就会提及启动文件。一般情况下如果我们使用ST官方标准库做开发的话标准库文件中都会带有启动文件。

STM32启动文件_第1张图片

标准库启动文件

在标准库对应目录下就可以有该库一系列芯片型号的启动文件。51单片机启动文件一样里面都是汇编程序,当然在上级目录我们也会看到官方还提供了其他一下主流开发工具对应的启动文件。

STM32启动文件_第2张图片

其他平台启动文件

keil因为已经被ARM收购,所以其启动文件会存放arm文件夹下,其他平台的可以自行查看。如果你使用的标准库比较古老,那可能该目录下没有arm文件夹,而对应的应该为mdk文件夹,因为之前arm还没收购keil。使用时最好找到自己芯片型号对应的文件进行复制,如何确定自己使用的芯片与哪个文件匹配,可以参考官方选项手册,可以查看芯片参考手册中对应数据手册。

STM32启动文件_第3张图片

STM32F1系列对应数据手册

同一系列的芯片分类是依据芯片flash存储空间容量来确定的,所以可以直接从芯片名称确定自己使用哪个文件。

STM32启动文件_第4张图片

关于使用库开发

既然提到了库开发就顺便介绍一下相关知识。如果你想用标准库进行开发,手头上没有标准库或没有最新版本的标准库,可以在st官网进行下载,F1系列芯片的最新版本为3.6,如果不是大版本号(比如2.x与3.x)不同库代码内容差异不会太大,所以你使用3.x都没可以。

STM32启动文件_第5张图片

STM32官网标准库资料

另外要注意的是尽量使用一个固定版本的库,这样更方便自己后续的项目移植,初学者当然是建议使用最新版本,进行开发,不过现在标准库都非常稳定了,官方也不会进行太多的更新,自从STM32Cube发布之后官方对标准库的维护更少了,所以官方是推荐使用新的HAL库的,这几年官方对部分新产型号芯片都不再推出标准库了,所以如果使用新款芯片找不到标准库文件就直接使用HAL库吧,习惯了都一样。使用STM32Cube建立工程还是非常方便的,可视化流程,一套设置之后就可以生成完整的工程项目,平时习惯使用哪个开发平台就生成哪个平台的工程,连复制粘贴过程都省了(包括库文件和启动文件以及其他依赖文件),何乐而不为呢?

STM32启动文件_第6张图片

HAL库工程文件下的启动文件

最后你只需直接打开工程再添加自己的项目代码即可进行开发。

STM32启动文件_第7张图片

HAL库项目树视图

当然官方提供的库都是只是一种工具而已,自己喜欢哪种风格就用哪种库,完全没必要在这个问题上纠结。如果你不想使用库开发也可以直接编写寄存器函数,当然自己编写寄存器函数也不要忘了添加一种现成的启动文件,以及相关依赖文件。在一般的开发过程中,我们不会频繁的新建工程,通常都是直接复制现有工程,然后再对工程文件进行一定的修改即可投入到下一个项目中使用。初学者在学习的时候可多操作几遍新建工程的完整过程以加强理解,熟悉之后也大可不必没吃都要新建一个工程来浪费时间了。

启动文件分析

其实STM32的启动文件中的代码进行的操作和51单片机的启动文件基本内容差不多,只是因为STM32功能更多了所以内容会更多,另外,二者指令集不一样,所以表面上看起来没有任何相同的语句,但真实用途都是为了引导芯片执行进入到用户代码区域。

芯片型号众多,文件内容就不贴出了,这里F1系列中的一款为例做介绍,其他型号大同小异。

当然在这之前大家需要对以下知识点有一定的了解,几乎都是和内核以及指令集相关的知识,所以在学习STM32的过程中还要多看看与内核相关的书籍比如《Cortex-M3权威指南》,学其他芯片一是一样,至于你使用的芯片是什么内核,就参考该内核的资料。51内核只是比较简单所以教材里都不会单独列一本书进行讲解,但涉及到复杂的芯片时光内核都可以写几本书了。

1. 栈(Stack):
- 栈是MCU中的一块内存空间,用栈指针管理,具有LIFO(后进先出)的特点。
- 主要用于存储函数调用时的返回地址、参数、局部变量等信息。
- 在启动代码中我们定义Stack_Mem作为栈空间,__initial_sp作为栈指针初值。

2. 堆(Heap):
- 堆也是MCU内存空间,我们通过malloc/free在程序运行时动态分配和释放。
- 在启动代码中,我们定义了Heap_Mem作为堆空间,__heap_base和__heap_limit表示开始和结束。

3. 中断向量表(__Vectors):
- 这是一块非常重要的数据结构,存放各种中断和异常的处理函数入口。
- 首个入口是复位后需要执行的Reset_Handler函数。
- 向量表让CPU可以快速响应各种异步事件。

4. 复位处理(Reset_Handler):
- 上电或重置后首先执行的函数,完成基本的初始化工作。
- 它会调用SystemInit做底层初始化,然后跳转到C语言main函数。

5. 相关寄存器和汇编指令:
- 启动代码中大量用到寄存器和汇编指令,这需要时间逐步学习。
- 可以先理解代码主要逻辑,不必刨根问底汇编细节。

现在再分析一下这个启动代码主要完成的操作:

1. 设置代码段为启动代码,使用Thumb指令集

2. 定义栈段STACK,分配1024字节栈空间,并定义栈指针初值符号__initial_sp

3. 定义堆段HEAP,分配512字节堆空间,并定义堆开始和结束符号__heap_base和__heap_limit

4. 定义中断向量表__Vectors,里面包含栈指针初值设置,复位处理函数Reset_Handler入口等

5. 复位处理函数Reset_Handler:
  - 调用SystemInit系统初始化函数
  - 跳转执行C库入口__main

6. 定义各个外设中断处理函数入口,初始化为空操作

7. __user_initial_stackheap函数:
  - 初始化栈指针为栈底地址
  - 初始化堆起始和结束地址

再总结一下启动代码主要工作内容:

第一部分是定义栈空间Stack_Mem,大小是1024字节,后面又定义了堆空间Heap_Mem,大小是512字节。栈和堆都是MCU中的重要内存区域,我们的C程序都需要依赖它们正常运行。

第二部分是中断向量表__Vectors,这是核心的数据结构,它定义了各种异常发生时,CPU需要跳转执行的函数入口。比如第一个入口就是复位后需要执行的Reset_Handler函数。

第三部分首先是Reset_Handler复位处理函数,它会依次调用SystemInit做系统初始化,然后跳转到C语言入口__main。

后面还定义了空的中断处理函数,这些我们之后会逐步补充代码实现各种中断服务。

最后一部分是__user_initial_stackheap函数,它会正式设置栈指针和堆空间的地址,完成内存区域的初始化。

简单概括整个过程既为:
  - 设置代码段和指令集
  - 配置栈和堆空间
  - 定义向量表和中断函数
  - 系统初始化和跳转到C库入口
  - 栈和堆地址初始化
  - 程序结束循环

通过这些代码操作完成了STM32处理器启动前的基本设置,之后CPU会跳入C语言main函数中执行我们的代码,这些特定内核的启

转载微信公众号:落木青云 

你可能感兴趣的:(stm32,单片机)