本帖最后由 星辰大海不退缩 于 2025-5-26 15:58 编辑
手写一个最简 Reset_Handler
与其对着 MCU官方启动文件(一堆汇编,头大)研究,不如咱们自己动手写一个简单清晰的 Reset_Handler!目标是完成变量初始化,然后跳到 main()。代码如下:
#include "MCUxx.h"
externuint32_t _etext; // 数据段初始值在 Flash 的地址
externuint32_t _sdata; // 数据段起始地址(RAM)
externuint32_t _edata; // 数据段结束地址(RAM)
externuint32_t _sbss; // BSS 段起始地址
externuint32_t _ebss; // BSS 段结束地址
void Reset_Handler(void) {
// 1. 拷贝数据段初始值(从 Flash 到 RAM)
uint32_t *init_values_ptr = &_etext;
uint32_t *data_ptr = &_sdata;
if (init_values_ptr != data_ptr) {
while (data_ptr < &_edata) {
*data_ptr++ = *init_values_ptr++;
}
}
// 2. 清零 BSS 段
for (uint32_t *bss_ptr = &_sbss; bss_ptr < &_ebss;) {
*bss_ptr++ = 0;
}
// 3. 跳转到 main()
main();
// 4. 如果 main() 返回,进入死循环(防止跑飞)
while (1);
}
解释一下:
数据段拷贝:把初始值从 _etext(Flash)拷贝到 _sdata 到 _edata(RAM),确保有初始值的变量值正确。
BSS 段清零:把 _sbss 到 _ebss 的内存清零,确保没初始值的变量是 0。
调用 main() :环境准备好后,直接跳到 main()。
死循环:如果 main() 意外返回,死循环防止程序跑飞。
为了让代码更健壮,我们还可以加点 STM32F411 专属的初始化。比如,ST的需要确保系统时钟配置正确(否则默认用内部 HSI 16 MHz 运行,可能不满足某些场景需求)。我们可以在 Reset_Handler 中调用 SystemInit(ST 官方提供的函数)来搞定这些。改后的代码如下:
#include "MCUxx.h"
externuint32_t _etext; // 数据段初始值在 Flash 的地址
externuint32_t _sdata; // 数据段起始地址(RAM)
externuint32_t _edata; // 数据段结束地址(RAM)
externuint32_t _sbss; // BSS 段起始地址
externuint32_t _ebss; // BSS 段结束地址
extern void SystemInit(void); // STM32 官方提供的系统初始化函数
void Reset_Handler(void) {
// 1. 拷贝数据段初始值
uint32_t *init_values_ptr = &_etext;
uint32_t *data_ptr = &_sdata;
if (init_values_ptr != data_ptr) {
while (data_ptr < &_edata) {
*data_ptr++ = *init_values_ptr++;
}
}
// 2. 清零 BSS 段
for (uint32_t *bss_ptr = &_sbss; bss_ptr < &_ebss;) {
*bss_ptr++ = 0;
}
// 3. 调用系统初始化(设置时钟等)
SystemInit();
// 4. 跳转到 main()
main();
// 5. 死循环
while (1);
}
注意:这里的 SystemInit 是MCU 官方固件库(或 HAL 库)提供的,负责初始化时钟、FPU(浮点单元,Cortex-M4 特有)等。如果不用官方库,也可以自己写时钟配置,比如手动设置 HSE 或 PLL。
|