嵌入式系统之初:STM32启动文件详解——中断向量表篇
本文最后更新于149 天前,其中的信息可能已经过时,如有错误请发送邮件到527388734@qq.com

当芯片接收到中断信号时,是如何精准找到对应的处理函数?问题的答案同样也藏在经常被我们忽略掉的启动文件当中。在上一篇内存篇中,我们探索了堆栈的分配与RAM的布局。今天,我们来继续深入启动文件当中另一个核心部分——中断向量表

在我们的启动文件当中,肯定会存在以下一部分的内容。

__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
                ;....其余中断函数
__Vectors_End

这段看似简单的代码,实际上构建了整个中断系统的核心。在深入分析之前,我们首先要掌握一个关键的汇编指令:DCD——它是构建整个中断向量表的基石。

DCD(Data Constant Double-word)是ARM汇编器中的一个伪指令,用于在当前位置分配一个或多个32位(4字节)的字,并用指定的值初始化这些字。可以这样理解:使用DCD的过程,类似于在C语言中定义并初始化一个全局数组

DCD的基本语法:
标号 DCD 表达式1, 表达式2, …, 表达式N

  • 标号:代表这段内存区域的起始地址,相当于给这个位置起了个名字。
  • 表达式:要存储的具体数值,可以是地址、常数或符号

现在让我们用DCD的知识,重新审视启动文件中的向量表定义。
第一行建立栈环境:

__Vectors DCD __initial_sp

这行代码的含义是:‘

  • __Vectors标识的地址处,分配4字节空间
  • 在这个空间中存储__initial_sp的值(栈顶地址)

那么这个__Vectors的地址在哪里?答案在编译后生成的Map文件中:

可以看到,__Vectors对应地址就是0x08000000——而这个正是flash的起始地址!同样也是stm32第一次取指的地方。
假设栈顶地址__initial_sp = 0x20000400,那么这行代码的实际效果就是:
在Flash的0x08000000地址处,存储数值0x20000400

第二行设定程序起点:

                DCD     Reset_Handler

这行代码有两个关键点:

  • 0x08000004地址处(前一个DCD + 4字节)
  • 存储Reset_Handler函数的地址

同样Reset_Handler的地址也可以到.map文件里找得到。

按照这个规律,整个向量表在Flash中的布局如下:

地址        数据(32位,小端格式)
0x08000000: 0x20000400   ; __initial_sp的值
0x08000004: 0x08000101   ; Reset_Handler函数的地址  
0x08000008: 0x0800018D   ; NMI_Handler函数的地址
0x0800000C: 0x08000191   ; HardFault_Handler函数的地址
;注意:由于STM32采用小端字节序,实际存储时低位字节在前。

既然把这些地址都记录下来了,那么硬件是如何使用这张表,来找到对应的中断处理函数呢?

上电启动过程
当芯片上电复位时,Cortex-M内核硬件自动执行以下操作:

  1. 从0x08000000读取值 → 存入MSP(主栈指针寄存器)
    • 建立C语言的栈环境
  2. 从0x08000004读取值 → 存入PC(PC指向哪,程序就执行哪)
    • 跳转到Reset_Handler函数开始执行
  3. 执行Reset_Handler → 初始化系统,最终调用main()

按照这么取指赋值的方式,处理器就明白了每个处理函数的具体地址。

中断响应过程
当中断发生时(比如按键触发EXTI0中断)

  1. 硬件自动暂停当前程序
  2. 根据中断号计算向量表位置
    • EXTI0的中断号是6
    • 向量表位置 = 0x08000000 + (6 + 16) × 4 = 0x08000058
  3. 从0x08000058读取值 → 存入PC
    • 跳转到EXTI0_IRQHandler函数
  4. 执行中断处理程序
  5. 返回原程序继续执行

理解了硬件如何查找中断函数后,我们自然会想到一个问题:如果某个中断我暂时不需要处理,该怎么办?答案就是WEAK——弱符号机制。我们可以看如下的一段代码:

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .      ;默认实现,死循环
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .      ;默认实现,死循环
                ENDP
                ;.....其他中断处理程序也采用相同方式定义

这个机制同c语言的__weak关键字是同样一个道理,他允许被开发者重新定义。当存在新的定义之后,原本的带有weak修饰的部分就会被覆盖掉。

假设我们需要处理按键中断,但不需要处理窗口看门狗中断:

// 在C文件中重写需要的中断函数
void EXTI0_IRQHandler(void) {
    EXTI->PR = EXTI_PR_PR0;  // 清除中断标志
    handle_button_press();   // 实际业务逻辑
}

// 不需要重写WWDG_IRQHandler,使用默认实现

在这种情况下:

  • EXTI0中断:由于我们提供了自定义实现,系统会调用我们编写的 EXTI0_IRQHandler 函数
  • 看门狗中断:由于没有自定义实现,系统使用启动文件中默认的死循环处理

这样的设计架构也避免未使用的中断不会导致程序跑飞,而是进入可控的死循环。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇