
⚡ 一、硬件阶段(由 CPU 硬件自动完成)
当 STM32 上电或复位 时,Cortex-M 内核自动执行以下步骤:
注意:STM32上电复位以后,代码区都是从0x00000000开始的,三种启动模式将各自存储空间的地址映射到0x00000000中。
| 启动方式 |
启动地址映射到 0x00000000 |
启动内容 |
典型用途 |
| 主Flash启动(Main Flash boot) |
主Flash(0x0800_0000) |
用户应用程序 |
正常运行 |
| 系统存储器启动(System Memory boot) |
系统存储器(0x1FFF_0000 或类似) |
内置 Bootloader |
串口 / USB / DFU 下载 |
| SRAM启动(RAM boot) |
SRAM(0x2000_0000) |
调试用 |
调试或特殊引导 |
| 步骤 |
动作 |
说明 |
| ① |
取地址 0x00000000 的值 → 写入 MSP(主栈指针) |
栈顶指针初始化 |
| ② |
取地址 0x00000004 的值 → 写入 PC(程序计数器) |
这就是 Reset_Handler 的入口地址 |
| ③ |
CPU 从 Reset_Handler 开始执行 |
程序正式启动 |
👉 这两步对应中断向量表的前两项:
0x00000000 __initial_sp ; 初始栈顶
0x00000004 Reset_Handler ; 复位入口
🧠 二、软件阶段(由启动文件与运行时库完成)
从 Reset_Handler 开始,一切都是软件控制。
以 STM32 官方启动文件为例,主要有以下过程:
| 阶段 |
执行函数 |
主要工作 |
| ① |
Reset_Handler |
初始化 SRAM、调用 SystemInit、再跳转到 __main |
| ② |
SystemInit() |
配置时钟(HSE/HSI/PLL)、Flash、总线分频等硬件系统设置 |
| ③ |
__main(编译器库函数) |
初始化 C 运行环境(复制 .data、清零 .bss、准备堆栈) |
| ④ |
main() |
进入用户编写的主函数 |
🔍 更细的展开(典型 ARMCC / Keil 流程)
上电或复位
↓
硬件加载 MSP、PC
↓
执行 Reset_Handler
↓
├─ 清空 SRAM (部分芯片)
├─ 调用 SystemInit() ← 时钟初始化
└─ 跳转到 __main
↓
├─ 拷贝 .data 段(Flash → RAM)
├─ 清零 .bss 段
├─ 初始化 C/C++ 运行环境
└─ 调用 main()
↓
用户程序开始运行
🧩 三、内存空间的状态变化
| 内存区域 |
内容 |
来源 |
| Flash(程序存储器) |
代码、常量、初始化数据 |
编译后固化 |
| SRAM(数据存储器) |
栈区、堆区、全局变量、静态变量 |
由 Reset_Handler / __main 初始化 |
| 寄存器 |
MSP、PC、PSP、CONTROL、PRIMASK... |
由 CPU 自动或系统代码设置 |
🧱 四、Reset_Handler 中的重要三步(再次总结)
- 初始化 SRAM(可选)
清零 RAM 或建立默认值;
- 调用 SystemInit()
配置系统时钟、外设基础环境;
- 跳转到
__main
由编译器运行时库初始化 C 语言环境,最后进入 main()。
💡 五、通俗比喻
| 阶段 |
类比 |
| 上电/复位 |
打开电脑电源 |
| 硬件取向量表 |
BIOS 启动,知道去哪执行 |
| Reset_Handler |
BIOS 初始化硬件 |
| SystemInit |
设置 CPU 频率、时钟源 |
| __main |
操作系统加载应用环境 |
| main |
程序员写的应用程序开始运行 |
✅ 最简总结(记住这 6 步即可)
上电复位 →
取向量表 →
MSP ← __initial_sp
PC ← Reset_Handler
→ SystemInit()
→ __main()
→ main()