中断与GPIO一样是STM32中非常常用的东西,以我一个写上位机的人的理解,它相当于上位机程序中多线程的地位,因为多线程和中断都是为了提高某些响应的实时性。悄悄说一句,我觉得中断在一定程度上比多线程还好用。哈哈哈哈哈哈哈~
大部分图片来源:正点原子HAL库课程
目录
1 作用
2 意义
3 NVIC
3.1 优先级
3.2 NVIC的使用
3.3 相关的HAL库文件(可以去这里找用到的函数和宏定义)
4 EXTI
4.1 中断和事件
4.2 工作原理
4.3 外部中断配置
4.4 EXTI配置步骤
4.5 相关的HAL库文件(可以去这里找用到的函数和宏定义)
5 中断中几个重要概念的本质
5.1 __HAL_PPP_ENABLE_IT
5.2 HAL_NVIC_EnableIRQ
5.3 HAL_PPP_XXX_Start_IT
1 作用
2 意义
高效处理紧急程序,不会一直占用CPU资源。
3 NVIC
中断的总管家。
中断服务函数:位于启动文件中。
3.1 优先级
数字越小优先级越高!
优先级的分组:
设置优先级分组大概意思就是在同样只有IPRx寄存器高四位时,使得项目有一定数量的抢占优先级和一定数量的响应优先级。而因为只有四位的空间,不同优先级分组之间就是把4位分别分给抢占和响应而已。具体怎么分就需要结合项目需要了,因为中断是抢占优先级和响应优先级共同作用的。
但在一个工程中,一般只设置一次中断优先级的分组,避免程序的优先级混乱,多次设置时以最后一次为准。
3.2 NVIC的使用
注意⚠️:
在例程中stm32f1xx_hal.c已经在HAL_init()函数中设置过中断分组为2,就不需要额外设置了。分组为2中中间间,比较好用。
3.3 相关的HAL库文件(可以去这里找用到的函数和宏定义)
stm32f1xx_hal_cortex.c(找NVIC函数)
startup_stm32103xe.s(找中断服务函数名)
4 EXTI
外部中断事件控制器。
F1包含20(互联型)/19(非互联型)个产生事件/中断请求的边沿检测器,即总共20条EXTI线。
4.1 中断和事件
中断:要进入NVIC,有相应的中断服务函数,需要CPU处理
事件:不进入NVIC,仅用于内部硬件自动控制的,如:TIM、DMA、ADC
4.2 工作原理
最常用的寄存器:上升沿触发寄存器、下降沿触发寄存器、请求挂起寄存器、中断屏蔽寄存器。而一般不采用软件触发中断,也很少使用事件,都是使用中断。
4.3 外部中断配置
使用AFIO的AFIO_EXTICR1~4寄存器对EXTI中断线0-15对应哪个IO口进行配置。
配置前需要先使能AFIO时钟:__HAL_RCC_AFIO_CLK_ENABLE()
同一时间段内,一条EXTI线只能与一路IO相映射如下图时只能选PA0-PG0中的一个和EXTI0映射。
4.4 EXTI配置步骤
- 理论上的全流程
- 实际上的全流程(其中示例程序中第二步已经完成了第三步内容)
【其中6包含重写中断服务函数和重写数据处理回调函数两步】
其中根据四步法的逻辑,可以分为:
1. 初始化
(1) 时钟设置:使能串口时钟
(2) 外设参数设置:HAL_GPIO_Init();
(3) IO设置:HAL_GPIO_Init();
(4) 中断设置:使能中断,设置中断优先级;
2. 定义读函数:无
3. 定义写函数:无
4. 编写中断服务函数:
重写EXTIx_IRQHandler及其内部的HAL_GPIO_EXTI_Callback函数;
- 中断的回调机制为
- 注意事项⚠️
(1) 在使用GPIO作为中断输入时,GPIO的模式就应该配置为GPIO_MODE_IT_RISING(上升沿触发中断)、GPIO_MODE_IT_FALLING(下降沿触发中断)、GPIO_MODE_IT_RISING_FALLING(双边沿触发中断)中之一;
(2) 设置中断优先级就是按照第三步(也就是第二步内部的第三步)设置的中断分组来设置抢占优先级和响应优先级;
(3) 设置PINx的中断就是设置EXTIx的中断,x = 0~4时是这样,5及以后的可能就和剩下的两个EXTI线相关了,具体要查资料;
(4) 第六步所谓的设置中断服务函数,就是在启动文件的中断向量中找到EXTIx对应的中断服务函数名,来重写。例如,EXTI4就是重写一个void EXTI4_IRQHandler(void)函数;而中断回调函数中说到的调用HAL库中断处理公用函数,就是在EXTI4_IRQHandler函数的具体实现上,调用GPIO的中断处理公用函数HAL_GPIO_EXTI_IRQHandler。
(正点原子的视频中其实还讲到了调用公共处理函数后还要接一句清除中断标志位的函数,如GPIO中为__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_X),但实际上我看公共处理函数内部中本来就有这一句,因此大概率是不需要的,因为像串口之类的外设课程中正点原子也没提到需要进行手动清除,反而说了公共处理函数已经清除了)
拓展地来讲:对于非GPIO使用EXTIx的的情况,即x >= 16的情况,就要根据EXTIx对应的外设,去对应外设的HAL库文件中找其中断处理公用函数;
(5) 中断回调函数中说到的HAL库数据处理回调函数,在HAL库中断处理公用函数可以看到它被调用,而去查其定义,可以看到这个函数(如使用GPIO中断时是HAL_GPIO_EXTI_Callback)是被__weak修饰的,且其内容为空,这意味这个函数可以并需要被用户文件重写,手动实现在中断发生时执行的回调函数;
(6) 注意:中断处理公用函数和HAL库数据处理回调函数在自己的BSP源文件内定义后,不需要再在对应的头文件中声明了,因为他们两个都已经声明过了,一个是在启动文件中,一个是在外设对应的HAL库文件中;
4.5 相关的HAL库文件(可以去这里找用到的函数和宏定义)
stm32f1xx_hal_cortex.c(找NVIC相关函数)
stm32f103xe.h(找基地址)
startup-stm32f103xe.s(找中断服务函数名)
stm32f1xx_hal_gpio.h(为了找清除中断标志位的函数)
stm32f1xx_hal_gpio.c(为了找HAL库中断处理公用函数、数据处理回调函数)
其他外设的hal库.h(为了找清除中断标志位的函数)
其他外设的hal库.c(为了找HAL库中断处理公用函数、数据处理回调函数)
5 中断中几个重要概念的本质
5.1 __HAL_PPP_ENABLE_IT
启用外设PPP的某个中断,但并不意味着中断处理函数和回调就会执行。但是!!!哪怕不执行这个函数,中断标志位也会发生改变,别的外设我不知道,但是输入捕获中断的话,哪怕不用HAL_TIM_Base_Start_IT而直接用HAL_TIM_Base_Start(相当于没有启用IC的中断),其中断标志状态寄存器SR也会随着输入捕获的出现而置位。
5.2 HAL_NVIC_EnableIRQ
真正启用中断的函数,就是告诉芯片我启用了这个中断的服务函数和回调函数了,后面发生这个中断后你必须给我执行它的服务函数和回调函数。
这个函数要先执行__HAL_PPP_ENABLE_IT,再执行。
5.3 HAL_PPP_XXX_Start_IT
(注意:这里的XXX指的是功能,有可能没有。)
这个函数就是启用某个硬件,并且调用其__HAL_PPP_ENABLE_IT函数启用其中断。相当于HAL_PPP_XXX_Start_IT + __HAL_PPP_ENABLE_IT。