中断,顾名思义就是停止现在正在干的活,去干其他更紧急的事情。在通常的信息系统中,中断发生时,会先保留现场,即当前的运行情况和状态。在去做其他紧急事情。事情做完还要恢复原先中断前的状态继续干原来的活。在STM32中,例如指令出错,定时器结束,串口接收到数据,GPIO电平变化等都会产生中断。
一、外部中断示例
注:使用STM32F103CT6芯片,KEYSKING教程的开发板套件。开发板接口图如下
(1)示例:红灯正常闪烁,按下KEY1按钮,翻转绿灯亮灭。
在芯片设置界面中设置PA7,PB0口为GPIO_OUTPUT标签命名分别为greenLED,redLED.把PB12口设置为GPIO_EXIT12,命名为key1.
在属性设置面板中,System Core ->GPIO->PB12 进行详细设置,GPIO MODE 设置为下降沿(Falling Edge)触发.
而后属性设置面板中,点击中断向量控制NVIC 设置中断优先级,如图
关键代码如下:在main.c中编写红灯闪烁代码
cpp
...
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
int status =0 ;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
status++ ;
status%=5;
if(status < 1){
HAL_GPIO_WritePin(redLED_GPIO_Port, redLED_Pin, GPIO_PIN_RESET);
}else{
HAL_GPIO_WritePin(redLED_GPIO_Port, redLED_Pin, GPIO_PIN_SET);
}
HAL_Delay(300);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
.....
在stm32f1xx_it.c 中编写中断处理函数。(注:it为"中断"英文缩写)
cpp
......
void EXTI15_10_IRQHandler(void)
{
/* USER CODE BEGIN EXTI15_10_IRQn 0 */
HAL_Delay(10);
if(HAL_GPIO_ReadPin(key1_GPIO_Port,key1_Pin) == GPIO_PIN_RESET){
//反转pin位,即按下key翻转绿灯亮灭
HAL_GPIO_TogglePin(greenLED_GPIO_Port, greenLED_Pin);
}
/* USER CODE END EXTI15_10_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(key1_Pin);
/* USER CODE BEGIN EXTI15_10_IRQn 1 */
/* USER CODE END EXTI15_10_IRQn 1 */
}
......
编译,生成结果。
二、外部中断原理
上图是GPIO的输入驱动器模块,电流从I/O引脚进入,到达上拉/下拉电阻,而后到达施密特触发器,而后流入输入数据寄存器或者片上外设。
(1).中断/事件控制器
再接下来,电平信号便会进入外部中断/事件控制器的输入线中。其框图如下所示。
在STM32中,这样的控制器在STM32F1系列芯片中由19个。这19个外部中断控制器公用一套寄存器,但是各个部件的连线都是独立的。每个部件之间的连线都有19组,每个外部中断都对应着其中1组线路。该线路也称为外部中断线。
这19个外部中断线的前16组(EXIT0 ~ EXIT15)分别对应着编号相同的GPIO口。也就是说PA0/PB0/PC0/PD0对应着EXIT0,PA1/PB1/PC1/PD1对应着EXIT1一直到PA15/PB15/PC15/PD15对应着EXIT15...
边沿检测电路可以检测输入的电平信号是否发生高低电平转换。如果出现电平转换后续就会发出一个高电平信号。
例如在上述示例中,我们把key1对应的PB12设置成了下降沿触发中断。那么当按下按钮时,下降沿触发选择寄存器就会置成1。而后发出高电平信号。经过一个或门到达请求挂起寄存器。请求挂起寄存器收到高电平信号后把满线路编号对应的bit位置为1。并向后续发出高电平信号。 到达了与门。而中断屏蔽器对应的bit位是否发出高电平信号,取决于STM32的端口是否设置为GPIO_EXIT,是则到达嵌套向量中断控制器NVIC.
(2).嵌套向量中断控制器NVIC
NVIC会根据中断信号,选择对应的处理函数。中断向量前5号对应着各自的中断处理函数。而5号到9号公用同一个处理函数EXIT9_5_IRQHandler。10号到15号公用同一个处理函数EXIT15_10_IRQHandler。在上述示例中,PB12对应的中断向量为EXIT12,对应的处理函数则为EXIT15_10_IRQHandler。
在中断函数中,有系统自动生成的代码HAL_GPIO_EXTI_IRQHandler();进入到其实现中发现有__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);函数,该函数就是用来重置中断寄存器中的bit位。
(3).中断优先级
当中断发生时如何确定哪个中断先执行呢?例如上述示例中,中断函数中调用了HAL_DELAY函数。该函数也会触发一个时钟滴答(Tick Timer)中断,如果设置的时钟滴答优先级比中断函数处理优先级低。当代码执行到HAL_DELAY时,由于有比HAL_DELAY优先级高的中断处理函数未完成那么系统就会进入"死锁"状态。
当两中断同时发生时,先比较抢占优先级,如果一样则比较响应优先级。如果还一样则取决于在中断向量表中的顺序。
当一个中断正在处理,而另一个中断信号发生。那么就只比较抢占优先级。
在STM32为每个中断向量准备了4个二进制位来存储优先级信息。在Cube中可以根据优先级组下拉框设置哪几个bit位用来确定抢占优先级(主优先级),剩下的bit位确定为响应优先级(子优先级)。