启动文件

启动文件

0. 它是谁、什么时候跑

  • 文件名:startup_stm32f407xx.s,汇编编写,放在 MDK-ARM 目录下。

  • 上电复位后第一个执行 的程序,在 main() 之前。

  • 干 5 件事:CPU 上电后从向量表第0项取栈指针、从第1项取 Reset_Handler 地址跳转 → 调 SystemInit() → 调 __main(C 库初始化)→ 跳进 main()。

1. 栈和堆

复制代码
 Stack_Size  EQU 0x00000400    ; 栈 1KB
 Heap_Size   EQU 0x00000200    ; 堆 512B
栈(Stack) 堆(Heap)
用途 局部变量、函数调用、形参 malloc() 动态分配
生长方向 高地址 → 低地址 低地址 → 高地址
大小默认值 1KB 512B
不够了会怎样 溢出 → HardFault malloc 返回 NULL

局部变量多了/递归深了,栈不够会莫名其妙进 HardFault。遇到这种事先把 Stack_Size 改大。

2. 向量表

向量表就是一个函数地址数组,存在 Flash 0 地址。

复制代码
 __Vectors  DCD __initial_sp       ; 第0个:栈顶地址(不是函数!)
            DCD Reset_Handler     ; 第1个:复位
            DCD NMI_Handler       ; 第2个:不可屏蔽中断
            DCD HardFault_Handler ; 第3个:硬错误
            ...
            DCD WWDG_IRQHandler   ; 外部中断从这里开始
            ...

CPU 响应中断的机制:中断号 × 4 → 到向量表里查对应地址 → 跳过去执行。

位置 内容 说明
0x00 __initial_sp 栈顶地址,复位后直接加载到 SP
0x04 Reset_Handler 复位后第一条要跑的代码
0x08~0x3C 系统异常 NMI / HardFault / SVC / PendSV / SysTick 等
0x40 起 外部中断 WWDG / PVD / 各种外设中断

3. Reset_Handler:复位后干了什么

复制代码
 Reset_Handler PROC
     LDR R0, =SystemInit    ; ① 调 SystemInit()
     BLX R0
     LDR R0, =__main        ; ② 调 __main(C 库初始化,最终调你的 main)
     BX  R0
 ENDP
  • SystemInit():在 system_stm32f4xx.c 里。HAL 工程里它不配时钟 ,只做 FPU 使能、向量表地址设置、外部 SRAM 配置。时钟靠你自己写的 SystemClock_Config()(见 4. 时钟.md 第6节)。

  • __main:C 库函数,初始化堆和栈,然后跳进你的 main()。

4. WEAK(弱定义)------最关键的概念

启动文件里所有中断服务函数都是空实现,标了 [WEAK]:

复制代码
 NMI_Handler PROC
     EXPORT NMI_Handler [WEAK]
     B .          ; 死循环
 ENDP

规则:

  • 你在 C 文件里写了同名函数(比如 void SysTick_Handler(void) {})→ 用你的。

  • 没写 → 用这个空的死循环。

后果:开了中断但忘了写中断服务函数 / 函数名拼错 → 中断来了直接跳进这个死循环,程序卡死。

你自己写中断函数时,名字必须和向量表里的完全一致(如 USART1_IRQHandler),错一个字母就等于没写。

5. 常用汇编指令速查

指令 作用
EQU 给常量起名字,相当于 C 的 #define
SPACE 分配内存(单位字节)
DCD 以字为单位分配并初始化内存(向量表用它存函数地址)
EXPORT 把本文件的标号导出给别的模块用,相当于 C 里非 static 的全局定义(对外可见)
IMPORT 声明标号来自外部文件,相当于 C 的 extern(引用)
B 跳转。B . = 跳到自己 = 死循环
BLX 跳转到函数并保存返回地址
WEAK 弱定义(不是 ARM 指令,是编译器伪指令)
ALIGN 地址对齐

6. MicroLIB

Keil 里 Target 选项卡勾的 "Use MicroLIB",对应的就是启动文件里的 __MICROLIB 宏:

复制代码
 IF :DEF:__MICROLIB
     EXPORT __initial_sp
     EXPORT __heap_base
     EXPORT __heap_limit
 ELSE
     ; 不勾 MicroLIB 时需要用户自己实现 __use_two_region_memory
 ENDIF
  • 勾了:Keil 自带精简 C 库,启动文件直接导出栈顶/堆起止地址,省事。

  • 不勾 :用标准 C 库,需要自己实现 __use_two_region_memory。

  • 嵌入式开发一般都勾 MicroLIB,代码小、启动快。

相关推荐
意法半导体STM3211 小时前
【官方原创】LAT6048 如何扩大MP2的A35核和M33核共享内存
stm32·单片机·嵌入式硬件·内存映射·stm32mp2
en.en..12 小时前
STM32(F429)启动模式与两种烧录方式
stm32·单片机·嵌入式硬件
Zw-awa12 小时前
从 printf 到曲线:把数据送上 VOFA+
stm32
单片机仿真设计12 小时前
基于 51 单片机的数字温度计(DS18B20+LCD1602+Proteus 仿真,支持阈值可调声光报警)
单片机·嵌入式硬件·proteus·课设
芝士爱沙拉13 小时前
原生内置agent智能开发能力的MCU IDE-MounRiver Studio
ide·单片机·嵌入式硬件
路上有只喵13 小时前
认识元器件 · 单片机(MCU/MPU/SOC) · 实战篇4
单片机·嵌入式硬件
YYRAN_ZZU13 小时前
FlameGraph 火焰图介绍和使用
linux·嵌入式硬件
【 STM32开发 】14 小时前
【CubeMX+STM32】SD卡 文件系统读写 FatFs+SDIO+DMA (F103版本)
stm32·单片机·嵌入式硬件·1024程序员节
动词ing14 小时前
【51单片机】独立按键控制LED灯亮灭
单片机·嵌入式硬件·51单片机
Industio_触觉智能14 小时前
瑞芯微工业ADC采集实战-上|AD7616&RK3506 FlexBus高速并行采集落地
嵌入式硬件·硬件架构·硬件工程·adc·瑞芯微·rk3506·flexbus