记录代码进入Default_Handler错误的解决办法
问题表述
在一次调试代码的时候,发现代码卡死在启动文件 startup_stm32f0xx_.s 的222行,即 B. 处
B.是汇编代码,B:跳转到一个标号,这里跳转到一个‘.’,即表示无限死循环
通过在Debug窗口可以定位到,程序是进入Default_Handler错误
根本原因分析:
底层原理
1. 中断向量表结构
STM32启动文件预先定义了完整的中断向量表,包含所有可能的异常和中断处理程序入口地址。其中的典型定义形式为:
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
...
.word DMA1_Channel1_IRQHandler
... // 共百余个中断向量
2. 弱符号定义规则
启动文件通过.weak指令将默认Handler设为弱符号(模板代码可见下图):
启动文件中的弱符号定义
这种设计允许开发者在外设驱动文件中重写同名中断服务函数,当链接器检测到重载时会优先选择用户定义版本。
3. 中断触发流程
[中断触发] → [NVIC查找向量表] → [执行对应ISR]
↑ ↓
└─若未注册有效ISR → 执行Default_Handler
一、底层原理打比方
假设你有一栋大楼(STM32芯片),楼里每个房间都装了应急按钮(外设中断)。你给每个按钮都写了贴纸标签(启动文件中的中断服务函数名)。但有个特殊情况:所有按钮都默认连接到同一间喇叭房(Default_Handler),只有当工人在你的总控系统(项目代码)里给具体房间接线(实现正确的中断函数)时,对应的按钮才会连接到真正的功能房间。
二、分步骤详细解释
2.1 为什么程序会"死循环"?
➊ 正常情景
当你正确配置一个外设(比如串口DMA)中断时:
真按钮 → 连接到功能房(用户实现的DMA1_Handler
)→ 正常工作
➋ 故障情景
配置了外设中断,却没有实现对应的处理函数:
↓
假按钮 → 默认连接到喇叭房(启动文件的Default_Handler
)→ B.死循环(持续报警)
2.2 两个关键设计特性
- "假功能房"设计(弱符号声明)
启动文件里预先写了各种DMA1_Handler
这样的空函数,例如:
// 这是启动文件的预先声明(赋予低优先级)
__weak void DMA1_Channel1_IRQHandler(void) {
while(1); // 危险设计:堵在这里
}
标注__weak
表示:这个函数可以被你的代码覆盖取代。
- "按钮标签强行对应"规则
中断向量表强制要求每个按钮必须对应一个处理函数。当出现以下情况都会被导向Default_Handler:
- 函数名称写错(如
DMA_Handler
漏写"Channel1") - 忘记实现函数
- 中断配置错误
三、快速自检口诀
当你遇到"卡死在B.死循环"时,三步口诀定位:
1、查外设——是否开启了没用到的中断?
2、对名称——中断函数名是否与启动文件完全一致?
3、看调用——通过CallStack回溯哪个中断被触发?
总结
在开启了某个中断,但是又忘记编写配套的中断服务程序或者函数名写错,代码会进入Default_Handler错误,即 B. 死循环
参考链接:
关于STM32程序卡在B .即Default_Handler处的解决方法
【玩转STM32】:Default_Handler问题