在嵌入式系统中,中断是一种重要的机制,用于处理来自外部设备的异步事件。STM32系列微控制器提供了强大的中断控制器,可以方便地处理各种外部中断和内部中断。本文将详细介绍STM32中断的结构和使用方法。
文章目录
- 1. 什么叫中断
- 2. 中断优先级
- 2.1 有抢占优先级为什么还要子优先级?
- 3. 中断嵌套
- 4. 中断结构
- 5. 中断使用方法
- 总结
1. 什么叫中断
中断是计算机系统中的一种机制,用于处理突发事件或异步事件。在计算机运行过程中,CPU通常是按照指令的顺序依次执行的,但是当发生某些特殊事件时,如外部设备的输入、定时器的溢出等,CPU需要立即中断当前的任务,转而处理这些事件。这样可以提高系统的响应速度和效率。
中断可以看作是一种突然的打断,类似于我们在做一件事情的时候突然收到了一个电话,需要立即停下手头的工作去接听电话。中断可以分为硬件中断和软件中断两种类型。
硬件中断是由外部设备触发的,如键盘输入、鼠标点击等。当外部设备触发了中断信号时,CPU会立即停止当前的任务,转而执行与中断相关的处理程序。处理完中断后,CPU会返回到之前被中断的地方继续执行。
软件中断是由程序中的特殊指令触发的。程序可以通过软件中断指令,主动请求CPU中断当前任务,执行与中断相关的处理程序。软件中断可以用来实现特定的功能,如操作系统的系统调用。
2. 中断优先级
在STM32微控制器中,中断优先级是用来确定**中断服务程序(ISR)**执行的顺序的。STM32系列微控制器支持多个中断源,并且每个中断源都有一个对应的中断优先级。
中断优先级可以分为两个级别:抢占优先级和子优先级。
- 抢占优先级(Preemption Priority):抢占优先级决定了当多个中断同时发生时,哪个中断可以中断当前正在执行的中断。具有较高抢占优先级的中断可以打断正在执行的较低优先级中断,并立即执行自己的中断服务程序。
- 子优先级(Subpriority):子优先级用于决定在同一抢占优先级的多个中断中,哪个中断将首先得到执行。具有较高子优先级的中断将在同一抢占优先级的其他中断之前得到执行。
2.1 有抢占优先级为什么还要子优先级?
抢占优先级和子优先级的组合可以提供更灵活的中断控制和调度。抢占优先级主要用于处理多个中断同时发生时的中断抢占关系,而子优先级则用于处理同一抢占优先级的多个中断的执行顺序。
使用抢占优先级可以确保关键的中断能够及时中断正在执行的低优先级中断,并立即执行自己的中断服务程序。这对于实时性要求较高的应用非常重要。
然而,当多个中断具有相同的抢占优先级时,如果没有子优先级的支持,它们将按照先后顺序依次执行,无法进行更细粒度的调度。一般情况下,抢占优先级的位数比子优先级的位数多,因此抢占优先级的范围更广,可以提供更细粒度的中断控制。通过使用子优先级,可以在同一抢占优先级的多个中断中确定首先执行的中断。这对于需要优先处理某些特定中断的应用非常有用。
3. 中断嵌套
中断嵌套是指在一个中断服务程序(ISR)执行期间,另一个中断发生并触发了相应的中断服务程序的执行。当一个中断正在处理时,如果有更高优先级的中断发生,系统将暂停当前中断的处理,转而去处理更高优先级的中断,这就是中断嵌套。
中断嵌套在实时系统中非常常见,它允许系统在处理一个中断时能够及时响应更高优先级的中断请求。通过中断嵌套,可以实现对多个中断请求的优先级排序和处理,确保关键中断能够及时中断正在执行的较低优先级中断,并立即执行自己的中断服务程序。
在STM32微控制器中,中断嵌套是通过抢占优先级和子优先级来实现的。当一个中断正在执行时,如果有更高抢占优先级的中断请求发生,系统会立即中断当前中断的执行,并开始处理更高优先级的中断。如果多个中断具有相同的抢占优先级,那么子优先级将决定它们的执行顺序。
中断嵌套可能会引入一些问题,如中断嵌套深度过大可能导致系统性能下降,同时需要合理地处理中断优先级和中断服务程序的互斥和同步问题,以确保系统的正确性和可靠性。
4. 中断结构
4.1 中断向量表(Interrupt Vector Table):中断向量表是一个存储中断向量地址的数据结构,用于存储中断服务函数的入口地址。当一个中断发生时,微控制器会根据中断号从中断向量表中读取相应的ISR地址,并跳转到该地址执行中断服务程序。在STM32中,中断向量表存储在内部闪存的起始地址处。
中断向量表的大小取决于微控制器支持的中断数量。对于STM32系列微控制器,通常采用的是基于向量表的中断处理方式,其中中断向量表的大小是固定的,每个中断向量的大小是4个字节。因此,中断向量表的大小等于中断数量乘以4个字节。
在编程中,我们可以通过修改中断向量表中的中断向量来指定每个中断的ISR地址。通常,我们会使用编译器提供的特定语法来定义中断向量表和中断服务程序,并将它们放置在正确的地址位置。
需要注意的是,中断向量表是只读的,它存储了系统在编译时确定的中断服务程序的地址。因此,在运行时无法修改中断向量表。如果需要动态地改变中断服务程序的执行地址,可以使用中断向量重定向技术,即通过修改中断向量表中的中断向量,将中断重定向到其他地址。但这种技术需要小心使用,以避免引入不可预测的错误。
4.2 中断控制器(Nested Vectored Interrupt Controller,NVIC):NVIC是STM32中断控制器的核心组件,用于管理和控制中断。它支持多级中断优先级,可以配置中断优先级、使能或禁用中断,并提供中断向量表的地址。
NVIC有以下几个主要的功能:
-
中断优先级管理:NVIC允许为每个中断分配一个抢占优先级和一个子优先级。抢占优先级用于确定中断的抢占关系,而子优先级用于确定同一抢占优先级的多个中断的执行顺序。NVIC提供了寄存器来配置和管理中断的优先级。
-
中断使能/禁止控制:NVIC提供了寄存器来使能或禁止特定的中断。通过设置相应的位,可以选择性地使能或禁止中断。这对于灵活地控制中断的触发和执行非常有用。
-
中断状态管理:NVIC提供了寄存器来管理中断的状态。例如,可以通过读取和写入中断挂起寄存器来判断中断是否处于挂起状态,以及通过写入中断清除寄存器来清除中断标志。
-
中断向量表偏移:NVIC允许通过设置偏移量来修改中断向量表的起始地址。这对于实现中断向量重定向非常有用,可以将中断重定向到其他地址。
4.3 中断服务函数(Interrupt Service Routine,ISR):中断服务函数是中断发生时执行的代码块。在STM32中,中断服务函数需要使用特定的函数声明和命名规则,并通过中断向量表进行注册。
5. 中断使用方法
-
配置中断优先级:首先,需要使用
NVIC_SetPriority()
函数设置中断的抢占优先级和子优先级。该函数的参数包括中断通道号和优先级值。 -
初始化中断向量表:在启动代码中,需要初始化中断向量表的起始地址。可以使用
NVIC_SetVectorTable()
函数来设置中断向量表的偏移地址。 -
注册中断处理函数:使用
NVIC_Init()
函数注册中断处理函数。该函数的参数包括中断通道号、中断优先级和中断处理函数的地址。 -
使能中断:使用
NVIC_EnableIRQ()
函数使能中断。该函数的参数为中断通道号。 -
编写中断处理函数:编写中断处理函数,处理中断事件发生时的逻辑。中断处理函数的命名和参数取决于所使用的中断通道和编程语言。
以下是一个示例代码,演示了如何使用标准外设库函数实现中断:
#include "stm32f10x.h"
// 中断处理函数
void EXTI0_IRQHandler(void)
{
// 处理中断事件逻辑
// ...
// 清除中断标志
EXTI_ClearITPendingBit(EXTI_Line0);
}
int main(void)
{
// 初始化中断向量表
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
// 配置中断优先级
NVIC_SetPriority(EXTI0_IRQn, 0);
// 注册中断处理函数
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能中断
NVIC_EnableIRQ(EXTI0_IRQn);
while (1)
{
// 主循环逻辑
// ...
}
}
总结
STM32中断提供了强大的功能,可以方便地处理各种外部中断和内部中断。通过合理配置中断优先级和中断服务函数,可以实现对异步事件的及时响应。在实际应用中,需要根据具体需求和硬件设备,合理使用中断功能,提高系统的可靠性和性能。