32位单片机中断深度理解

ID:933150

当前离线

积分289

电梯直达

楼主

ID:933150

发表于 2023-3-27 22:41

|

只看该作者

|倒序浏览

|阅读模式

## 中断

### 简介

- 中断(Interrupt)是一种事件响应机制,可以使单片机在处理其他任务的同时及时响应并处理紧急事件,提高系统的实时性能和可靠性。

- 中断是一种异步事件响应方式,当指定的事件发生时,中断处理器会立即暂停当前程序执行,转而执行中断服务程序,处理完中断事件后再返回原来的程序执行流程。

### 组成部分

- 在单片机中,中断由中断源、中断控制器和中断服务程序组成。

#### 中断源

- 产生中断事件的硬件设备或软件程序,如定时器溢出、外部输入信号、串口接收数据等。

#### 中断控制器

- 负责检测中断源产生的中断请求,并向CPU发送中断信号,在CPU完成当前指令后跳转到相应的中断服务程序。

在32位单片机中,中断控制器通常由NVIC(Nested Vector Interrupt Controller)实现。NVIC支持多达240个中断源,可以灵活配置优先级、屏蔽中断等设置。

下面是一个在STM32F4单片机上使用NVIC实现中断初始化的示例代码:

```c

// 初始化中断

void init_interrupt(void) {

// 使能IRQ中断

NVIC_SetPriorityGrouping(NVIC_PriorityGroup_4);

// 初始化中断优先级

NVIC_Init(&NVIC_InitStructure);

}

```

#### 中断服务程序

- 是一个用于处理特定中断事件的程序。

- 包括清除中断标志位、保存现场、执行特定操作、恢复现场等步骤,最后通过返回指令返回到原来的任务流程。

在32位单片机中,中断服务程序通常由ISR(Interrupt Service Routine)实现。ISR是一种特殊的函数,具有固定的格式和命名规则,以便编译器正确地生成中断向量表和中断服务程序入口地址。例如,对于外部中断EXTI1的中断服务程序,其函数定义应该如下所示:

```c

// EXTI1中断服务程序

void EXTI1_IRQHandler(void) {

// 处理中断事件

// ...

// 清除中断标志位

EXTI_ClearITPendingBit(EXTI_Line1);

}

```

### 响应过程

- 中断响应过程主要包括中断源产生中断请求、中断控制器检测到中断请求、CPU暂停当前任务跳转到中断服务程序、中断服务程序处理中断事件、CPU返回原任务继续执行等几个步骤。

以下是中断响应过程的详细说明:

1. 中断源产生中断请求

当某个硬件设备或软件程序产生了一个需要CPU立即处理的事件时,会向中断控制器发送中断请求信号。例如,当定时器溢出时,定时器会向中断控制器发送一个定时器中断请求。

2. 中断控制器检测到中断请求

中断控制器不断检测是否有中断请求发生,当检测到中断请求时,会向CPU发送中断信号,通知CPU有中断事件需要处理。

在32位单片机中,中断控制器通常由NVIC实现。NVIC会根据中断优先级和屏蔽设置等信息来判断是否响应中断请求,并向CPU发送相应的中断信号。

3. CPU暂停当前任务,跳转到中断服务程序

当CPU收到中断信号后,会暂停正在执行的任务,并将当前指令的下一条指令地址(PC)保存到堆栈中,以便在中断服务程序执行完后返回原来的任务流程。然后,CPU会从中断向量表中读取相应中断源对应的中断服务程序入口地址,并跳转到该地址开始执行中断服务程序。

4. 中断服务程序处理中断事件

中断服务程序是用于处理特定中断事件的程序,它包括清除中断标志位、保存现场、执行特定操作、恢复现场等步骤,最后通过返回指令返回到原来的任务流程。

在中断服务程序中,需要清除中断标志位以便下一次中断响应,例如,对于外部中断EXTI1的中断服务程序,可以使用以下代码清除中断标志位:

```c

// 清除中断标志位

EXTI_ClearITPendingBit(EXTI_Line1);

```

5. CPU返回原任务继续执行

当中断服务程序执行完毕后,CPU会从堆栈中读取之前保存的PC值,恢复执行原来的任务流程,即返回到之前暂停的任务处,继续执行原来的指令。

### 中断向量表

- 中断向量表(Interrupt Vector Table)是一种特殊的数据结构,用于存储所有中断服务程序的入口地址。

- 在单片机启动时,中断向量表会被加载到固定的内存位置,并在中断响应时被CPU使用。

- 它通常是一个连续的存储区域,每个中断源都占据一个固定的位置。

- 当中断控制器检测到中断请求时,会将相应的中断编号作为索引,从中断向量表中读取对应的中断服务程序入口地址,并跳转到该地址开始执行中断服务程序。

以下是在STM32F4单片机上定义中断向量表的示例代码:

```c

// 中断向量表

void (* const InterruptVectorTable[]) (void) __attribute__ ((section(".isr_vector"))) = {

(void (*)(void)) &_estack, // 栈指针

Reset_Handler, // 复位中断

NMI_Handler, // 非屏蔽中断

HardFault_Handler, // 硬件故障中断

MemManage_Handler, // 存储器管理中断

BusFault_Handler, // 总线错误中断

UsageFault_Handler, // 用法错误中断

0, // 保留

0, // 保留

0, // 保留

0, // 保留

SVC_Handler, // 系统调用中断

DebugMon_Handler, // 调试监视中断

0, // 保留

PendSV_Handler, // 挂起中断

SysTick_Handler, // 系统定时器中断

// 外部中断0~15的中断服务程序

EXTI0_IRQHandler,

EXTI1_IRQHandler,

EXTI2_IRQHandler,

EXTI3_IRQHandler,

EXTI4_IRQHandler,

EXTI9_5_IRQHandler,

EXTI15_10_IRQHandler,

// 更多的外部中断服务程序

};

```

### 注意事项

- 在使用中断时,需要注意一些问题,如中断的优先级、中断嵌套、中断延迟等,以确保系统的稳定性和可靠性。

#### 中断优先级

- 中断优先级可以决定哪个中断优先处理。

- 在NVIC中,中断优先级分为4位或3位,越高的值表示越低的优先级。

- 在设计中,需要根据具体应用场景来设置合理的中断优先级,以避免因低优先级中断被屏蔽而导致紧急事件无法及时处理的情况。

以下是在STM32F4单片机上设置中断优先级的示例代码:

```c

// 设置某个中断的优先级

NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级为1

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 子优先级为1

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

```

#### 中断嵌套

- 中断响应时,如果又有新的中断请求产生,就会发生中断嵌套。

- 在处理中断嵌套时,需要注意保存现场和恢复现场的顺序,以免出现逆序恢复导致系统错误的情况。

以下是在STM32F4单片机上处理中断嵌套的示例代码:

```c

// 外部中断0服务程序

void EXTI0_IRQHandler(void) {

// 保存现场

NVIC_SystemHandlerPendingBitConfig(SYS_TICK, DISABLE); // 禁用SysTick中断

__disable_irq(); // 禁用所有中断

// 处理中断

if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {

EXTI_ClearITPendingBit(EXTI_Line0);

// 触发外部中断1

EXTI_GenerateSWInterrupt(EXTI_Line1);

}

// 恢复现场

__enable_irq(); // 使能所有中断

NVIC_SystemHandlerPendingBitConfig(SYS_TICK, ENABLE); // 使能SysTick中断

}

```

#### 中断延迟

- 当中断服务程序执行时间过长或存在阻塞操作时,会导致其他中断响应受到影响,甚至出现错误。

- 在设计中,需要尽量避免中断延迟,并采取一些手段优化中断服务程序的执行效率,以确保系统实时性。

以下是降低一些常见中断延迟的方法:

- 将中断服务程序的执行时间尽量缩短;

- 禁止在中断服务程序中使用延时函数、锁存器等方式;

- 对于需要较长时间处理的中断事件,可以通过将其放在主循环中异步处理的方式来避免中断延迟。

#### 响应优先级和先占优先级

在中断处理中,常常涉及到两个概念:响应优先级和先占优先级。

响应优先级是指中断请求发生时,CPU按照一定的优先级顺序来处理多个中断请求。具有更高响应优先级的中断会在低优先级中断之前得到处理。

先占优先级是指在某个中断服务程序执行期间,不允许其他优先级低于其自身的中断干扰它的执行。如果此时发生了优先级更高的中断请求,则需要等待当前中断服务程序执行完成后再进行处理,这就是优先级抢占。

在STM32F4单片机中,中断响应优先级分为抢占优先级和响应优先级,其中抢占优先级用于决定同优先级中断之间的抢占关系,而响应优先级则用于决定不同优先级中断之间的响应顺序。

以下是在STM32F4单片机中设置中断优先级的示例代码:

```c

// 设置中断优先级

NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级为1

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 响应优先级为1

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

```

在该示例中,抢占优先级为1,响应优先级为1,表示该中断服务程序的优先级比所有响应优先级为2及以下的中断都要高。

总之,在设计中断处理过程时,需要合理设置中断响应和抢占优先级,以满足系统实时性和稳定性的要求。

### 注意事项:

#### 中断开关

在使用中断前,需要先打开中断总开关,使得单片机可以响应中断请求。在STM32F4单片机中,可以通过以下代码打开中断总开关:

```c

// 打开中断总开关

__enable_irq();

```

在使用完中断后,需要关闭中断总开关,以避免产生其他不必要的中断响应。在STM32F4单片机中,可以通过以下代码关闭中断总开关:

```c

// 关闭中断总开关

__disable_irq();

```

#### 中断优先级

在使用中断时,需要根据实际需求设置中断优先级,以确保不同优先级中断的响应顺序和抢占关系符合设计要求。如果中断优先级设置不当,可能会导致系统性能下降或出现严重错误。

#### 中断嵌套

当多个中断同时发生时,可能会出现中断嵌套的情况,这会影响中断处理效率和正确性。因此,在编写中断服务程序时,需要考虑中断嵌套的情况,并采取相应的措施避免嵌套带来的问题。

#### 中断延迟

当中断服务程序执行时间过长或存在阻塞操作时,会导致其他中断响应受到影响,甚至出现错误。因此,在设计中,需要尽量避免中断延迟,并采取一些手段优化中断服务程序的执行效率,以确保系统实时性。

#### 中断与优先级反转

中断与优先级反转是一种由于中断优先级问题导致的系统问题,这可能会使得高优先级的任务被低优先级的中断事件阻塞。在设计中需要避免出现中断与优先级反转的情况,并采取一些手段解决该问题。

总之,在使用中断时,需要全面考虑系统的实时性、可靠性和稳定性,以确保中断处理能够达到预期的效果。

分享到:

QQ好友和群

QQ空间

腾讯微博

腾讯朋友

收藏1

淘帖0

顶0

踩0

回复

使用道具

举报