stm32启动文件

不管是51还是32,在编写程序的时候,都需要一个头文件,里面包含了大部分的程序内容,缩短了我们的开发周期,32的头文件中定义了器件、中断线、数据类型、结构体封装的寄存器、寄存器地址映射、寄存器位操作以及防C++编译的条件编译等信息。而在进行32编程的时候,无可避免的我们都会添加一个启动文件。它可以说是,程序的基石了。

1.启动文件简介

启动文件是由汇编写的(我也不会汇编,就大致认识一下启动文件的流程),它是系统上电复位后第一个执行的程序。主要做了以下工作:

1.初始化堆栈指针 SP = ------initial_sp

2.初始化PC指针=Rest_Handler

3.初始化中断向量表

4.配置系统时钟

5.调用C库函数_main初始化用户堆栈,从而最终调用main函数去C的世界。

2.查找ARM汇编指令

由于启动文件中都是用汇编写的,涉及ARM和Cortex内核的指令,有关cortex内核的指令可以参考《CM3权威指南CnR2》第四章:指令集。剩下的ARM指令可以在MDK->Help->Uvision Help中搜索到,感兴趣可以了解一下

3.启动文件代码讲解

(所有代码均startup_stm32f10x_hd.s源代码,可以看那个代码的顺序)

3.1Stack------栈

开辟栈的大小为1KB(0x00000400),名字为STACK,NOINIT(不初始化),可读可写,8(2^3)字节对齐(EQU类似于宏定义,AREA告诉汇编器汇编一个新的代码段或数据段,SPACE用于开辟一定大小的内存空间,单位是字节)

栈的作用是用于局部变量,函数调用,函数形参等的开销,大小不能超过内部SRAM的大小。若编写的程序较大,局部变量多,则需修改栈的大小。

标号__initial_sp 紧挨着 SPACE 语句放置,表示栈的结束地址,即栈顶地址,栈是由

高向低生长的

3.2 Heap------堆

与前面类似开辟堆的大小为512字节,名字为HEAP,NOINIT(不初始化),可读可写,8(2^3)字节对齐

标号__heap_base 表示堆的起始地址, __heap_limit 表示堆的结束地址。堆是由低向高生长的,跟栈的生长方向相反。

堆主要是分配动态内存的分配,malloc()函数申请的内存就在堆上,这个在32里用的少

PRESERVE8: 指定当前文件的堆栈按照 8 字节对齐。

THUMB: 表示后面指令兼容 THUMB 指令。THUBM 是 ARM 以前的指令集, 16bit,

现在 Cortex-M 系列的都使用 THUMB-2 指令集, THUMB-2 是 32 位的,兼容 16 位和 32 位

的指令,是 THUMB 的超集。

3.3 中断向量表

定义一个可读的数据段RESET,并声明具有全局属性的三个标号,可供外部文件使用

当内核响应了一个发送的异常后,对应的异常服务例程就会执行。为了决定 ESR

的入口地址, 内核使用了―向量表查表机制。(详细可以看《STM32中文参考手册》第九章-中断和事件向量表部分。

(太长了截图不完整贴代码了)

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler            ; TIM2
                DCD     TIM3_IRQHandler            ; TIM3
                DCD     TIM4_IRQHandler            ; TIM4
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                DCD     SPI1_IRQHandler            ; SPI1
                DCD     SPI2_IRQHandler            ; SPI2
                DCD     USART1_IRQHandler          ; USART1
                DCD     USART2_IRQHandler          ; USART2
                DCD     USART3_IRQHandler          ; USART3
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
                DCD     TIM8_UP_IRQHandler         ; TIM8 Update
                DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
                DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
                DCD     ADC3_IRQHandler            ; ADC3
                DCD     FSMC_IRQHandler            ; FSMC
                DCD     SDIO_IRQHandler            ; SDIO
                DCD     TIM5_IRQHandler            ; TIM5
                DCD     SPI3_IRQHandler            ; SPI3
                DCD     UART4_IRQHandler           ; UART4
                DCD     UART5_IRQHandler           ; UART5
                DCD     TIM6_IRQHandler            ; TIM6
                DCD     TIM7_IRQHandler            ; TIM7
                DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors

__Vectors 为向量表起始地址, __Vectors_End 为向量表结束地址,两个相减即可算出向量

表大小。

向量表从 FLASH 的 0 地址开始放置,以 4 个字节为一个单位,地址 0 存放的是栈

顶地址, 0X04 存放的是复位程序的地址,以此类推。从代码上看,向量表中存放的都

是中断服务函数的函数名。(DCD:分配一个或者多个以字为单位的内存,以四字节对齐,并要求初始化这些内存。在向量表中, DCD 分配了一堆内存,并且以 ESR 的入口地址初始化它们。

3.4.复位程序

定义一个可读代码段

复位子程序是系统上电后第一个执行的程序,调用 SystemInit 函数初始化系统时钟,

然后调用 C 库函数_mian,最终调用 main 函数去到 C 的世界(LDR、 BLX、 BX 是 CM4 内核的指令)

WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部

文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并

不是唯一的。

IMPORT:表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。这里表

示 SystemInit 和__main 这两个函数均来自外部的文件。

SystemInit()是一个标准的库函数,在 system_stm32f10x.c 这个库文件中定义。主要作

用是配置系统时钟,这里调用这个函数之后, 单片机的系统时钟配被配置为 72M。(前面那个介绍库函数的文章中定义了一个这个函数就是这个道理。必须要有这个函数)

__main 是一个标准的 C 库函数,主要作用是初始化用户堆栈,并在函数的最后调用

main 函数去到 C 的世界。这就是为什么我们写的程序都有一个 main 函数的原因。

3.5中断服务函数

在启动文件里面已经帮我们写好所有中断的中断服务函数,跟我们平时写的中断服务

函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的 C 文件里

面重新实现,这里只是提前占了一个位置而已。

如果我们在使用某个外设的时候,开启了某个中断,但是又忘记编写配套的中断服务

程序或者函数名写错,那当中断来临的时,程序就会跳转到启动文件预先写好的空的中断

服务程序中,并且在这个空函数中无线循环,即程序就死在这里(大多数中断有固定参数名称和函数名)

代码大致在启动文件的159到326行

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
MemManage_Handler\
                PROC
                EXPORT  MemManage_Handler          [WEAK]
                B       .
                ENDP
BusFault_Handler\
                PROC
                EXPORT  BusFault_Handler           [WEAK]
                B       .
                ENDP
UsageFault_Handler\
                PROC
                EXPORT  UsageFault_Handler         [WEAK]
                B       .
                ENDP
//代码较长省略一部分
SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP

Default_Handler PROC

                EXPORT  WWDG_IRQHandler            [WEAK]
                EXPORT  PVD_IRQHandler             [WEAK]
                EXPORT  TAMPER_IRQHandler          [WEAK]
                EXPORT  RTC_IRQHandler             [WEAK]
//代码较长省略一部分
                EXPORT  DMA2_Channel1_IRQHandler   [WEAK]
                EXPORT  DMA2_Channel2_IRQHandler   [WEAK]
                EXPORT  DMA2_Channel3_IRQHandler   [WEAK]
                EXPORT  DMA2_Channel4_5_IRQHandler [WEAK]

WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
//代码较长省略一部分

SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_IRQHandler
TIM7_IRQHandler
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
                B       .

                ENDP

B:跳转到一个标号。这里跳转到一个'.',即表示无线循环。

3.6用户堆栈初始化

首先判断是否定义了__MICROLIB ,如果定义了这个宏则赋予标号__initial_sp(栈顶

地址)、 __heap_base(堆起始地址)、 __heap_limit(堆结束地址)全局属性,可供外部文

件调用。有关这个宏我们在 KEIL 里面配置,具体见图。 然后堆栈的初始化就由 C 库

函数_main 来完成

如果没有定义__MICROLIB,则插入标号__use_two_region_memory,这个函数需要

自己实现, 具体要实现成什么样,可在 KEIL 的帮助文档里面查询到

然后声明标号__user_initial_stackheap 具有全局属性, 可供外部文件调用,并实现这个

标号的内容。

IF,ELSE,ENDIF:汇编的条件分支语句,跟 C 语言的 if ,else 类似

END:文件结束

相关推荐
LN花开富贵1 小时前
stm32g431rbt6芯片中VREF+是什么?在电路中怎么设计?
笔记·stm32·单片机·嵌入式硬件·学习
qq21084629531 小时前
【stm32笔记】使用rtt-studio与stm32CubeMx联合创建项目
笔记·stm32·嵌入式硬件
CV金科1 小时前
蓝桥杯—STM32G431RBT6按键的多方式使用(包含软件消抖方法精讲)从原理层面到实际应用(一)
stm32·单片机·嵌入式硬件·蓝桥杯
2021.091 小时前
五、CAN总线
嵌入式硬件
luckyluckypolar1 小时前
STM32——输入捕获
stm32·单片机·嵌入式硬件·物联网
hong1616881 小时前
嵌入式硬件基础知识
嵌入式硬件
hai405871 小时前
单片机(Microcontroller)原理及应用
单片机·嵌入式硬件
jun7788952 小时前
嵌入式硬件基础知识
嵌入式硬件
Projectsauron3 小时前
STM32 芯片启动过程
stm32·单片机·芯片启动过程
CDialog3 小时前
arduino ide开发esp32-wroom-32E
单片机·嵌入式硬件