STM32中断机制剖析:揭开中断向量表、优先级与处理的秘密
发布时间: 2024-07-01 18:47:33 阅读量: 855 订阅数: 77
![stm32单片机学习](https://wiki.st.com/stm32mpu/nsfr_img_auth.php/2/25/STM32MP1IPsOverview.png)
# 1. STM32中断概述**
中断是一种硬件机制,允许外设或事件在处理器执行当前指令时请求处理。在STM32微控制器中,中断系统是一个复杂的体系结构,提供对各种中断源的灵活控制。
中断系统由中断向量表、中断优先级机制和中断处理程序组成。中断向量表存储中断服务程序的地址,中断优先级机制决定中断处理的顺序,而中断处理程序负责处理特定中断。
中断在嵌入式系统中至关重要,因为它允许系统对外部事件或内部状态变化快速响应。通过使用中断,系统可以高效地管理任务,并在需要时立即处理关键事件。
# 2. 中断向量表
中断向量表是存储中断服务程序入口地址的表,当发生中断时,CPU会根据中断号从中断向量表中获取中断服务程序的入口地址,然后跳转到该地址执行中断服务程序。
### 2.1 中断向量表结构
STM32的中断向量表是一个固定大小的数组,其大小为1024字节,位于内存地址0x0000 0000。中断向量表的每一项都对应一个中断号,其中前256项用于处理外部中断,后768项用于处理内部中断。
| 中断号 | 中断源 | 内存地址 |
|---|---|---|
| 0 | 复位 | 0x0000 0000 |
| 1 | NMI中断 | 0x0000 0004 |
| 2 | 硬故障 | 0x0000 0008 |
| ... | ... | ... |
| 255 | 外部中断0 | 0x0000 0100 |
| ... | ... | ... |
| 768 | DMA1流0中断 | 0x0000 0300 |
| ... | ... | ... |
| 1023 | SysTick定时器中断 | 0x0000 03FC |
### 2.2 中断向量表配置
中断向量表的配置可以通过以下步骤进行:
1. 在链接脚本文件中定义中断向量表的起始地址。
2. 在程序中定义中断服务程序。
3. 将中断服务程序的入口地址写入中断向量表。
**代码块 2.1:中断向量表配置示例**
```c
/* 链接脚本文件 */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (rw) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.text :
{
*(.text*)
} >FLASH
.data :
{
*(.data*)
} >RAM
.bss :
{
*(.bss*)
} >RAM
.vectors :
{
. = ALIGN(4);
_estack = .;
*(.vectors*)
} >FLASH
}
```
```c
/* 程序代码 */
void HardFault_Handler(void)
{
// 硬故障处理代码
}
void SysTick_Handler(void)
{
// SysTick定时器中断处理代码
}
```
```c
/* 中断向量表 */
__attribute__((section(".vectors"))) const uint32_t vectors[] =
{
(uint32_t)&_estack,
(uint32_t)&Reset_Handler,
(uint32_t)&NMI_Handler,
(uint32_t)&HardFault_Handler,
// ...
(uint32_t)&SysTick_Handler
};
```
### 2.3 中断向量表重定位
在某些情况下,需要将中断向量表重定位到其他内存地址。这可以通过修改链接脚本文件中的中断向量表起始地址来实现。
**代码块 2.2:中断向量表重定位示例**
```c
/* 链接脚本文件 */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (rw) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.text :
{
*(.text*)
} >FLASH
.data :
{
*(.data*)
} >RAM
.bss :
{
*(.bss*)
} >RAM
.vectors :
{
. = ALIGN(4);
_estack = .;
*(.vectors*)
} >FLASH AT> 0x08010000
}
```
通过修改链接脚本文件中的`.vectors`段的`AT`属性,可以将中断向量表重定位到0x0801 0000地址。
# 3.1 中断优先级机制
STM32 中断优先级机制基于嵌套向量中断控制器(NVIC),它为每个中断源分配一个优先级。优先级范围从 0 到 255,其中 0 为最高优先级,255 为最低优先级。
中断优先级机制确保高优先级中断在发生时可以抢占低优先级中断。当两个或多个中断同时发生时,NVIC 会根据它们的优先级决定哪个中断应该被服务。高优先级中断将立即得到服务,而低优先级中断将被延迟,直到高优先级中断处理完成。
### 3.2 中断优先级设置
中断优先级可以通过修改 NVIC 中的寄存器来设置。每个中断源都有一个对应的寄存器,用于设置其优先级。寄存器名称为 `NVIC_IPR<n>`,其中 `<n>` 是中断源的编号。
```c
// 设置中断源 0 的优先级为 3
NVIC_IPR0 = 3;
```
### 3.3 中断优先级冲突处理
当两个或多个中断具有相同的优先级时,将发生中断优先级冲突。在这种情况下,NVIC 会使用以下规则来确定哪个中断应该被服务:
- 如果中断源位于不同的嵌套向量中断控制器(NVIC)外设,则具有较低编号的中断源将具有更高的优先级。
- 如果中断源位于同一 NVIC 外设,则具有较低编号的中断源将具有更高的优先级。
```
// 假设中断源 0 和 1 具有相同的优先级
if (NVIC_IPR0 == NVIC_IPR1) {
// 如果中断源 0 位于较低的 NVIC 外设,则它具有更高的优先级
if (NVIC_ISER0 & (1 << 0)) {
// 服务中断源 0
} else {
// 服务中断源 1
}
}
```
# 4.1 中断处理流程
STM32 中断处理流程主要分为以下几个步骤:
1. **中断请求产生:**当发生中断事件时,相应的外部设备或内部外设会向 CPU 产生中断请求信号。
2. **中断向量定位:**CPU 根据中断请求信号,在中断向量表中查找与该中断事件对应的中断服务程序入口地址。
3. **程序计数器压栈:**CPU 将当前正在执行的指令的地址压入堆栈,以便中断处理完成后返回原程序继续执行。
4. **中断服务程序执行:**CPU 跳至中断服务程序入口地址,开始执行中断服务程序。中断服务程序负责处理中断事件,通常包括读取中断状态寄存器、清除中断标志位、执行必要的处理逻辑等。
5. **中断返回:**中断服务程序执行完成后,CPU 从堆栈中弹出之前压入的程序计数器地址,返回到中断发生前正在执行的指令处,继续执行原程序。
### 中断处理流程图
以下流程图展示了 STM32 中断处理流程:
```mermaid
sequenceDiagram
participant CPU
participant Interrupt Source
CPU->Interrupt Source: Interrupt Request
Interrupt Source->CPU: Interrupt Request Signal
CPU->CPU: Find Interrupt Vector Address
CPU->CPU: Push Program Counter to Stack
CPU->CPU: Jump to Interrupt Service Routine
CPU->CPU: Execute Interrupt Service Routine
CPU->CPU: Pop Program Counter from Stack
CPU->CPU: Return to Original Program
```
### 中断处理流程示例
以下代码示例展示了 STM32 中断处理流程:
```c
// 中断服务程序
void EXTI0_IRQHandler(void) {
// 读取中断状态寄存器
if (EXTI->PR & EXTI_PR_PR0) {
// 清除中断标志位
EXTI->PR |= EXTI_PR_PR0;
// 执行中断处理逻辑
// ...
}
}
// 主程序
int main(void) {
// 配置中断向量表
// ...
// 使能中断
__enable_irq();
// 进入死循环,等待中断发生
while (1) {
// ...
}
}
```
# 5.1 外部中断应用
外部中断是 STM32 中断系统的重要组成部分,它允许外部设备或事件触发中断。外部中断可以用于各种应用,例如按钮按下检测、传感器数据采集和故障检测。
### 外部中断配置
STM32 的外部中断通过 EXTI(外部中断/事件控制器)模块进行管理。EXTI 模块提供 16 个外部中断线,可以连接到各种外部设备或事件源。
要配置外部中断,需要执行以下步骤:
1. **选择中断线:**确定要使用的外部中断线。
2. **配置中断源:**将外部中断线连接到要检测的事件源。
3. **配置中断触发方式:**选择中断触发方式(上升沿、下降沿、电平触发)。
4. **使能中断:**在 NVIC(嵌套向量中断控制器)中使能外部中断。
### 外部中断服务程序
当外部中断触发时,STM32 会调用相应的外部中断服务程序(ISR)。ISR 是一个函数,用于处理中断事件。
编写 ISR 时,需要考虑以下事项:
* **中断处理逻辑:**ISR 应包含处理中断事件的逻辑。
* **数据保护:**ISR 应保护关键数据,以防止并发访问导致数据损坏。
* **中断返回:**ISR 应以 `__return_from_interrupt()` 指令返回,以安全地退出中断处理。
### 外部中断应用示例
外部中断在各种应用中都有广泛的应用,以下是一些示例:
* **按钮按下检测:**使用外部中断检测按钮按下事件,并执行相应的操作。
* **传感器数据采集:**使用外部中断触发传感器数据采集,并将其存储在缓冲区中。
* **故障检测:**使用外部中断检测系统故障,并触发警报或采取纠正措施。
### 代码示例
以下代码示例展示了如何配置外部中断和编写 ISR:
```c
// 1. 选择中断线
#define EXTI_LINE_0 0
// 2. 配置中断源
EXTI->IMR |= EXTI_IMR_MR0;
EXTI->RTSR |= EXTI_RTSR_TR0;
// 3. 配置中断触发方式
EXTI->FTSR |= EXTI_FTSR_TR0;
// 4. 使能中断
NVIC_EnableIRQ(EXTI0_IRQn);
// 外部中断服务程序
void EXTI0_IRQHandler(void) {
// 处理中断事件
if (EXTI->PR & EXTI_PR_PR0) {
// 清除中断标志位
EXTI->PR |= EXTI_PR_PR0;
// 执行中断处理逻辑
// ...
}
}
```
# 6.1 中断嵌套
中断嵌套是指在当前中断服务程序执行期间,又发生了新的中断请求。STM32支持中断嵌套,允许高优先级中断打断低优先级中断的执行。
### 中断嵌套机制
STM32的中断嵌套机制由嵌套向量表实现。嵌套向量表是一个额外的中断向量表,用于处理嵌套中断。当发生嵌套中断时,当前中断服务程序的返回地址将被压入嵌套向量表,然后跳转到嵌套中断服务程序。
### 中断嵌套使能
要启用中断嵌套,需要在NVIC的ISER寄存器中设置对应的位。ISER寄存器包含32个位,每个位对应一个中断源。要启用中断源i的嵌套,需要设置ISER寄存器的第i位。
```c
// 启用中断源i的嵌套
NVIC_ISER |= (1 << i);
```
### 中断嵌套优先级
嵌套中断的优先级由NVIC的IPR寄存器决定。IPR寄存器包含32个位,每个位对应一个中断源。IPR寄存器的值决定了中断源的优先级,值越大,优先级越高。
当发生嵌套中断时,高优先级中断将打断低优先级中断的执行。如果两个中断的优先级相同,则先发生的嵌套中断将被先执行。
### 中断嵌套示例
以下代码示例演示了中断嵌套:
```c
void EXTI0_IRQHandler(void) {
// 处理外部中断0
// ...
// 触发嵌套中断
NVIC_SetPendingIRQ(TIM2_IRQn);
}
void TIM2_IRQHandler(void) {
// 处理定时器2中断
// ...
}
```
在这个示例中,外部中断0的中断服务程序触发了定时器2的中断。由于定时器2的中断优先级高于外部中断0,因此定时器2的中断将打断外部中断0的中断服务程序的执行。
0
0