目录
1. 中断系统
2. 中断向量表
3. NVIC基本结构
4. NVIC优先级分组
5. NVIC程序编写
5.1 中断分组
5.2 中断结构体变量
5.3 中断通道选择
5.4 抢占优先级和响应优先级配置
6. 中断程序执行
1. 中断系统
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
在此时的断点部分,若是此时主程序还在进行例如加减乘除运算,但是突然有个更加紧急的的事情需要处理,可以在此时进行中断,优先处理更加紧急的事情,等事情处理完后,在返回主程序继续处理。
在中断这里,我们在断点处离开,编译器会自动帮我们保护现场(当前程序),等我们回来(中断完成后),继续工作。
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
例如:两个人同时就医,急诊和门诊。
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
STM32F1系列包含最多:68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设。
使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级
2. 中断向量表
灰色部分为内核中断,了解即可,一般用不上,初学者可以不用那么深入。
这里仅做了解,编译器已经帮我们做好了。
中断函数的地址由编译器来进行分配的,是不固定的,但是终端的跳转因为硬件的限制,只能调到固定的地址进行程序的执行,为了让硬件跳转到不固定的一个中断函数里,这里需要在中断函数里定义一个地址的列表,列表地址是固定的,中断发生后跳到这个位置,在这个固定位置由编译器,再加上一条跳转到中断函数的代码,这样就可以调到任意位置。
3. NVIC基本结构
NVIC:嵌套中断向量控制器
统一分配中断优先级,和管理中断
NVIC内核外设,CPU的小助手
米色圈住部分,意思是:一个外设可能会占用多个中断通道,所以这里有“n”条线,NVIC只有一个输出口,NVIC根据每个中断的优先级进行分配中断的先后顺序。
例如:医院叫号,CPU为医生,NVIC进行排号,中断是病人,NVIC根据病人的紧急程度进行排号,找医生。
4. NVIC优先级分组
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级
抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
对于响应优先级,相当于“插队”,此时“1”在看病(程序在进行中),“4”要是比较严重,“4”可以进行插队到“2”前面,但是要等“1”看完(进程走完)
对于抢占优先级(中断嵌套),相当于“1”在看病(程序在进行中),“4”不等“1”看完直接冲到屋内,把“1”推到一边,“4”先看病(进行),“4”先看完,在进行“1”,再依次进行后续的操作。
5. NVIC程序编写
了解:
中断分组:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
初始化NVIC:
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
设置中断向量表:
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
系统低功耗配置:
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
5.1 中断分组
/**
* @brief Configures the priority grouping: pre-emption priority and subpriority.
* @param NVIC_PriorityGroup: specifies the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
* 4 bits for subpriority
* @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
* 3 bits for subpriority
* @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
* 2 bits for subpriority
* @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
* 1 bits for subpriority
* @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
* 0 bits for subpriority
* @retval None
*/
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
根据需求,配置所需要的分组,几个抢占,几个响应。
这里我们选择分组2,两个抢占,两个响应
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组
注意:分组方式整个芯片只能用一种
5.2 中断结构体变量
NVIC_InitTypeDef NVIC_InitStructure;
5.3 中断通道选择
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.h file) */
要是我们配置PC13引脚,则:
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
5.4 抢占优先级和响应优先级配置
根据如图分组进行配置,我们配置为分组“2”,则抢占优先级和响应优先级的取值都为“0~3”,由于我们只配置一个引脚所以这里全给“1”。
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
完整初始化:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组,
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
6. 中断程序执行
void EXTI15_10_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line14) == SET)
{
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
学习笔记,仅供参考。