目录
基本知识框架
课堂笔记
中断
什么是中断
中断是一种计算机处理突发情况的工作机制
中断的基本工作机制
中断工作机制并不是凭空出现的,而是借鉴了生活中的经验。例如,你今天想完成两件事情:看电视和收快递,你会这样去完成,躺在沙发上专心看电视,并等待快递员通知你去收取快递,如果快递员不通知,那你就会专心的看你的电视;这和中断的使用场景非常相似,计算机在处理主任务的同时,还会面对一些突发情况(内存溢出,硬件宕机,定时器溢出。。。),通过中断这种硬件层面的功能,当异常情况发生时,中断控制器主动通知CPU保存主任务进度,优先执行突发情况处理的程序,执行完后再恢复主任务现场,并继续先前的工作
功能框图
中断的优点
相比轮询,中断机制有以下优点
- 提高了计算机的工作效率:中断不像轮询一样,需要CPU时时刻刻去监测突发情况是否发生,而是主动去通知CPU来处理突发情况,当不发生突发情况时,CPU可以专心的完成主任务
- 满足实时性的需求:当有实时性要求很高的任务时,通过配置中断,可以使此任务得到优先处理,
- 提供了故障处理的手段当发生故障,尤其是硬件故障时,通过中断,可以实现故障处理,设备复位等操作
中断类型和中断优先级
中断类型
STM32中,根据发起中断请求的外设在内核中还是内核以外,可以分为系统中断和外部中断
系统中断
系统中断是由内核中的外设发出的中断请求,由嵌套向量控制器NVIC直接响应
外部中断
外部中断是由内核外的外设,即APB总线上的外设发出的中断请求,由外部中断/事件控制器相应,如果发出的是中断信号,最终还会传到NVIC嵌套向量控制器
中断优先级
如果STM32同一时间收到多个中断信号,那么信号之间就有可能出现冲突。所以NVIC中还定义了中断的优先级,优先级高的中断,会被优先处理
优先级分为主优先级和子优先级,主优先级中断信号高于子优先级中断信号,会被优先响应,同级中断信号,根据优先级编号判断,编号越小,优先级越高,如果主优先级和子优先级都相同,则比较它们的硬件编号,硬件编号越小的,优先级越高
STM32中中断信号的优先级不是完全固定的,有部分中断信号的优先级是可以编程的,由开发者去设定中断信号的优先级
STM32中有8个系统中断(算上Reset和HardFault的话,有10个),60个外部中断,其中大部分优先级是可编程的,少部分中断信号优先级是固定的
NVIC嵌套向量控制器
NVIC嵌套向量控制器 ,这个控制器控制着整个芯片中断相关的功能,是内核中的一个外设,和内核紧密耦合。但由于STM32需要的中断功能没有那么高,所以实际上STM32中的NVIC是经过裁剪的,是属于CorteX NVIC的一个子集
为什么NVIC叫嵌套向量控制器
个人理解
嵌套:中断是可以嵌套的,这就意味着在执行优先级较低的中断服务时,是会被优先级较高的中断服务打断,等待高优先级的中断服务完成后,再恢复低优先级中断服务的现场,继续执行低优先级的中断服务
向量:向量指的是有方向有数值的量,在这里的向量指的是中断向量表,中断向量表之前已经讨论过,向量表中存储的是中断服务函数的地址,当有中断信号产生时,会从中断向量表中找到相应的中断函数的地址,然后跳转到该函数执行,流程如下图
NVIC寄存器结构体
NVIC寄存器结构体定义在固件库core_m3.h中,内容如下
typedef struct
{
__IO uint32_t ISER[8]; // 中断使能寄存器
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; // 中断清除寄存器
uint32_t RESERVED1[24];
__IO uint32_t ISPR[8]; // 中断使能悬起寄存器
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; // 中断清除悬起寄存器
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; // 中断有效位寄存器
uint32_t RESERVED4[56];
__IO uint32_t IP[240]; // 中断优先级寄存器(8bit)
uint32_t RESERVED5[644];
__IO uint32_t STIR; // 软件触发中断寄存器
}NVIC_Type;
实际中断的配置流程中,一般只用到ISER、ICER和IP三个寄存器,ISER寄存器用来使能中断,ICER寄存器用来失能中断,IP用来设置中断的优先级
NVIC寄存器相关库函数
在库函数头文件core_m3.h中除了提供NVIC寄存器结构体的定义,还提供了用来操作寄存器的库函数,这些函数遵循CMSIS的规则,这意味着只要是Cortex-M3处理器,这些函数都可用
但这些库函数一般都很少用到,因为还有更简洁的方法去配置寄存器
中断优先级寄存器和中断优先级设置库函数
NVIC有一个专门用于配置中断优先级的寄存器NVIC_IPRx,IPR寄存器的位数为8位,理论上可配置的中断优先级可以是0~255,但大多数的单片机系统,都会将中断优先级简化,STM32 F103中只是用到了IPR的高4位
通过内核外设SCB程序中断及复位控制寄存器AIRCR,其中的PRIGROUP[10:8]设置位,可以将中断根据优先级进行分组,虽然IPR寄存器仅有4位,但通过与PRIGROUP的前3位配合,可以将这4位分别设置成主优先级和子优先级 ,共5组,详细可见下表
和中断相关的库函数全部都在misc.c和misc.h里面,以下是优先级分组的解析和设置优先级库函数NVIC_PriorityGroupConfig()详细内容
// 设置中断优先级
// NVIC_PriorityGroup_0: 0bit for Main Interupt
// 4bit for Sub Interupt
// NVIC_PriorityGroup_1: 1bit for Main Interupt
// 3bit for Sub Interupt
// NVIC_PriorityGroup_2: 2bit for Main Interupt
// 2bit for Sub Interupt
// NVIC_PriorityGroup_3: 3bit for Main Interupt
// 1bit for Sub Interupt
// NVIC_PriorityGroup_4: 4bit for Main Interupt
// 0bit for Sub Interupt
//
// If Enabled NVIC_PriorityGroup_0,All bit will Work As Sub Interupt
void PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup
}
中断编程
将中断的思想通过库函数体现到函数中,一般要经过一下的过程:
- 想使能某个中断,首先要明确其寄存器的使能中断位。再需要根据需求是开启外设的中断
- 初始化NVIC_InitType结构体,设定中断源,设定中断优先级(包括主优先级和子优先级),最后使能中断
以下是NVIC_InitType结构体的详细内容
typedef struct
{
uint8_t NVIC_IRQChannel; // 中断源
uint8_t NVIC_IRQChannelPreemptionPriorty; // 中断主优先级
uint8_t NVIC_IRQChannelSubPriorty; // 中断子优先级
FunctionableState NVIC_IRQChannelCmd // 中断使能/失能
;}
NVIC_InitType结构体中有4个成员,它们分别代表了:
- NVIC_IRQChannel:用来设置中断源。中断源如果写错,并不会报错,而是会导致原本要相应的中断不工作,而其他意料之外的中断会工作的后果。NVIC_IRQChannel可设置的内容可以在头文件stm3210x.h定义的中断源结构体IRQn_Type中查询到
- uint8_t NVIC_IRQChannelPreemptionPriorty:用来设置中断主优先级,具体可以查看上表
- uint8_t NVIC_IRQChannelSubPriorty:用来设置中断子优先级,具体可以查看上表
- FunctionableState NVIC_IRQChannelCmd:用来设置中断使能/失能,主要是通过设置NVIC_ISER和NVIC_ICER寄存器来实现
- 最后编写中断服务函数,当系统响应中断时,会通过中断向量表找到并执行这个函数。原先在启动文件startup_stm3210x_hd.s中设置的空函数,为的是去初始化中断向量表,如果中断向量表中的函数指向错误,那么很可能会使系统陷入死循环
基本知识框架Xmind文件下载
链接:资源下载