STM32-中断
需求:红灯每两秒进行闪烁,按键key1控制绿灯亮灭
简单的程序代码无法满足要求
如何让STM32既能执行HAL_DELAY这种耗时的任务,同时又能快速响应按键按下这种突发情况呢
设置中断步骤
1.接入中断
将KEY1输入模式由原先的GPIO_Input设置为GPIO_EXTI12(第12号外部中断线)
- 修改后需要重新设置用户标签。
根据GPIO口的特性,按键按下时,电平由高电平变为低电平,因此选择下降沿触发中断
2.开启中断向量
保存并生成代码
3.编写中断发生时的代码
在生成的Core->Src->stm32f1xx_it.c文件中 其为缀it代表interrupt中断相关的文件,在文件的最下方
该函数就是我们按下按键触发中断后STM32会调用执行的中断处理函数
其执行时间十分短。
因此在此处对小灯进行控制,但值得注意的是
每当按键按下时都有下降沿,会一直触发中断,所以对小灯触发的效果不是很好
处理:延迟10ms检测是否为低电平,此if判断还可以防止第二个10ms的下降沿所触发的中断
4.设置中断优先级
HAL_DELAY依赖于Time base : System tick timer 1ms 的优先级,而系统默认优先级最高15,若中断的优先级低于15则无法执行,因此解决方法:让Svstem tick timer的优先级数字小于咱们的EXTI15_10即可
- 处理过后能满足需求,但程序对于中断的处理中不会使用HAL_DALAY,希望中断任务能尽快结束,往往还会有一些更加巧妙的方法来实现。
深入中断
EXTI
GPIO口内部:在输入控制模块
在信号到达复用功能输入后,进入 外部中断/事件控制器 ,如下图
像这样的外部中断共有19组,这19个外部中断线的前16个,也就是EXTI0~EXTI15分别对应着与其编号相同的GPIO口
每个引脚上PA0,PB0,PC0,PD0 对应EXTI0这条线 PA1,PB1,PC1,PD1 对应EXTI1这条线,以此类推
- 左下角的脉冲发生器,以及事件屏蔽寄存器与事件(Event)相关,事件型号会送达相应的外设,由外设自行处理。
配置这两个寄存器,如果给KEY1配置了下降沿触发中断,那么上升沿触发选择寄存器的第12位关闭为0,下降沿的触发选择寄存器的第12位开启为1
此时,如果边沿检测电路检测到下降沿就会向后发出高电平信号
经过或门后,将请求挂起寄存器对应的位置为1,如果是接受到来自第十二根外部中断线来的高电平后,将第12位0 置为 1 ,将此为输出 到与门,与门的特性是两个1才为1,中断屏蔽寄存器中只有其对应位上为1才能输出为1进入到NVIC,将KEY1设为GPIO_EXTI12时,就已经将中断屏蔽寄存器12位置为了1,接着送往最高层NVIC,其主要作用便是掌管着一张中断向量表,指向中断处理函数。
在中断向量表中。只有1-4号中断线有自己的中断向量,5-9 共享中断向量 EXTI9_5,10 - 15 共享中断向量 EXTI15_10
在信号抵达NVIC后,NVIC会找到中断向量EXTI15_10,然后按照指向去寻找EXTI5_10_IRQHandler并执行
执行完成后,HAL_GPIO_EXTI_IRQHandler(KEY1_Pin)会将请求挂起寄存器中的对应位置为0,此时EXTI5_10_IRQHandler()函数结束执行,否则会一直执行下去。
HAL_GPIO_EXTI_IRQHandler(KEY1_Pin)调用了名为__HAL_GPIO_EXIT_CLEAR_IT的函数
其功能是清除请求挂起寄存器,也就是将请求寄存器的第12位清为0,就不会误导NVIC再次执行EXTI5_10_IRQHandler()
其次回到NVIC中断向量表中,还有中断优先级的信息
上面设置了系统滴答的抢占优先级由于我们的EXTI15_10,是为了让系统滴答可以在EXTI15_10执行过程中抢占执行,从而为HAL_Delay提供时间基准,HAL_Delay就可以被打断,不然HAL_Delay没有时间基准,无法被打断 无法 实现在HAL_Delay时运行EXTI5_10_IRQHandler()