文章目录
文章基于适用于STM32F4系列,作者使用STM32F401CCU6开发板。
本文章基于此系列和开发板展开讨论。
中断
什么是中断
故名思意,中断就是打断某个程序的运行过程。转而运行其他规定的程序。
为什么要有中断
因为单片机的程序运行从本质上说是顺序执行程序(单线程),因此无法及时处理未知的突发事件。
突发情况包括但不限于某个按键的触发,达到某个时间,收到某个信号等。
所以硬件设计者设计出了一种可以在某个特定情况发生的时候及时响应的系统(中断系统)。
中断的运作过程
这里不解释底层的原理,详情请看微机原理
从编程的角度来看。可以把中断当作一个函数(中断服务函数),这个函数的调用和平常的函数不同,它可以在出现某个信号(中断信号)时被自动调用。
中断的调用过程和函数一样,在出现中断信号(函数被调用)时会存储现在执行到的位置,然后进入函数进行执行,中断服务函数(函数)被执行完毕后会回到原来保存下的位置继续执行。
就像这张图一样。(PS:函数的调用过程也类似)
中断优先级
既然中断是用来处理突发事件的,那必然不同的事件有不同的紧急程度。
反应在编程中便是中断优先级。
中断优先级就是表示在两个中断同时(虽然对单片机来说不存在同时,可以认为是在较短时间内出现两个)发送中断请求时决定优先处理哪个。
中断系统内部有一套程序决定不同中断的优先级(中断号)。当然编程者也可以自行设置,也就是后文要介绍的NVIC。
中断嵌套
中断是存在优先级的,高优先级的中断可以打断低优先级的中断。在中断函数中出现中断并被执行就叫做中断嵌套。
其实就像函数嵌套一样,是在中断函数中执行中断函数,只不过会不会产生中断嵌套是要取决于两个中断的优先级。只有在较低优先级的中断函数中才能运行较高优先级的中断函数。
就像个图一样
NVIC
NVIC是一套用来管理中断的系统。
初始化思路
- 设置NVIC分组
- 设置NVIC初始化结构体
- 初始化NVIC
NVIC分组
STM32中中断优先级有2个,一个是抢占优先级,一个是响应优先级。
官方起的名字容易使人产生误导,可以认为分为主优先级(抢占优先级),和副优先级(响应优先级)。
到这里可以将STM32的中断优先级系统介绍完全了。
首先比较主优先级(标号小的优先级高,0是最高),然后比较副优先级(标号小的优先级高,0是最高),如果主副优先级都相同,则比较中断号(系统确定好的,无法简单更改)(同样是小的优先级高)。
注意:没有两个中断源的优先级完全相同,总会存在先后次序。
注意:主优先级相同的两个中断无法产生中断嵌套,会先执行优先级高的再执行优先级低的
NVIC分组就是来设置主优先级和副优先级的数量。如下表
名称 | 主优先级(抢占优先级)数量/可取值 | 副优先级(响应优先级)数量/可取值 |
---|---|---|
NVIC_PriorityGroup_0 | 0(可取0) | 16(可取0-15) |
NVIC_PriorityGroup_1 | 2(可取0-1) | 8(可取0-7) |
NVIC_PriorityGroup_2 | 4(可取0-3) | 4(可取0-3) |
NVIC_PriorityGroup_3 | 8(可取0-7) | 2(可取0-1) |
NVIC_PriorityGroup_4 | 16(可取0-15) | 0(可取0) |
也就是一个4位的寄存器,根据上面的不同组分为主副优先级。
根据需要选取分组后使用这个函数进行设置
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
NVIC初始化结构体
这个结构体包含了配置NVIC一些参数
typedef struct
{
uint8_t NVIC_IRQChannel; //中断名称
uint8_t NVIC_IRQChannelPreemptionPriority; //主优先级
uint8_t NVIC_IRQChannelSubPriority; //副优先级
FunctionalState NVIC_IRQChannelCmd; //打开或关闭
} NVIC_InitTypeDef;
中断名称就是要设置的中断,只能传入1个
名字长的是主优先级
中断名称的取值请查阅标准库的stm32f4xx.h文件的189行左右。
初始化NVIC
使用这个函数初始化NVIC
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
传入的是之前定义的结构体的地址,请使用取址符(&)
例子
NVIC_InitTypeDef NVIC_Initstruct; //定义NVIC初始化结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选定NVIC分组,选择组2
NVIC_Initstruct.NVIC_IRQChannel=EXTI0_IRQn; //选择中断源(外部中断0)
NVIC_Initstruct.NVIC_IRQChannelCmd=ENABLE; //打开NVIC使能
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority=1; //设置主优先级
NVIC_Initstruct.NVIC_IRQChannelSubPriority=1; //设置副优先级
NVIC_Init(&NVIC_Initstruct); //初始化NVIC
中断初始化思路
- 配置NVIC(上文介绍的)
- 配置中断设置(不同中断不同,单独博客介绍)
- 编写中断服务函数
注意:中断服务函数的名字是固定的,不允许写错,不同中断不同,需要时介绍
与NVIC有关的常用的函数
NVIC_SetPriority
原型
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
名称 | 描述 |
---|---|
输入 1 | 要改变的中断号(可以是内部中断也可以是外部中断) |
输入 2 | 优先级 |
输出 | 无 |
功能描述:设置中断优先级,这个函数是直接设置中断优先级寄存器,0表示最高位,15表示最低位,具体主副优先级需要看NVIC组的划分
其实就是设置四位的中断优先级寄存器,具体是主副优先级需要看划分
例子:使用NVIC_PriorityGroup_2组,则
输入2 | 主优先级 | 副优先级 |
---|---|---|
0b0000 | 0b00 | 0b00 |
0x0001 | 0b00 | 0b01 |
… | … | … |
0x1001 | 0b10 | 0b01 |
… | … | … |
NVIC_GetPriority
原型
__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
名称 | 描述 |
---|---|
输入 1 | 要读取的中断号(可以是内部中断也可以是外部中断) |
输出 | 优先级(0-15) |
功能描述:读取中断优先级,这个函数是直接读取中断优先级寄存器,0表示最高,15表示最低,具体主副优先级需要看NVIC组的划分
基本同上,写入和读取
NVIC_SystemReset
原型
__STATIC_INLINE void NVIC_SystemReset(void)
名称 | 描述 |
---|---|
输入 1 | 无 |
输出 | 无 |
功能描述:软件复位
注意;使用此函数到复位成功有个延迟,可以响应中断,如果有精度需要在前面加上关闭中断的控制函数
__set_FAULTMASK(1); //关闭中断
NVIC_SystemReset(); //复位