摘要
STM32中外部中断普遍有20个以上,其中有16个中断线对应着16个GPIO口,其余的中断线连接在比如RTC闹钟,PVD输出等事件上,这些外部中断通过EXTI寄存器管理,这些中断事件可以通过外部IO触发,内部事件触发,还可以通过软件触发,通过软件在EXTI_SWIER寄存器中对应的位写1
触发对应的中断线。在程序中主动触发某个中断,可以及时处理一些不可预测的任务,比如串口接收事件等。这篇文章主要记录如何触发软件中断。
外部中断的配置与使用通过STM32CubeMX配置请转STM32CubeMX系列教程2:外部中断EXIT查看,这里主要讲解软件中断的配置方式。
这里以软件触发中断,改变LED灯状态为例进行说明。
中断控制器
通过查阅STM32参考手册可知。STM32的中断触发方式有两种,
- 第一种是上图中用红线描出的路径,也是最常用的一种方式,通过外部IO口的输入信号,经过1表示的边缘检测电路,如果配置了上升或下降沿触发中断,则对应输出信号进入2表示的或门,或门输出的信号与事件屏蔽寄存做与运算,如果配置了事件寄存器则发出事件脉冲,同时2号或门发出的信号进入4号与门,与中断屏蔽寄存器做与运算,如果配置了中断屏蔽寄存器,则在挂起寄存器挂起一个触发位,向CPU发起中断。CPU进入中断处理程序处理中断。
- 第二种中断触发方式是图中蓝色描出的路径,通过软件发起中断,比如,程序中需要CPU立刻立刻去处理某件任务,那么可以在软件中断事件寄存器中相应的位置1,信号通过2号或门输出给3号与门,如果配置中断的同时配置了事件,那么软件中断还可发出事件信号,2号发出的信号与中断屏蔽寄存器中的信号进行与运算,如果运算结果正确,则通过挂起寄存器向CPU发起中断。
以上就是STM32单片机的外部中断触发过程。通过结构图可知,
如果想要配置一个通过GPIO外部中断,则需要至少配置一个边缘触发寄存器EXTI_RTSR or EXTI_FTSR
,配置中断屏蔽寄存器EXTI_IMR
,需要事件的话,还需要配置事件屏蔽寄存器EXTI_EMR
。
如果想要配置一个软件中断,则只需要配置软件中断事件寄存器EXTI_SWIER
,中断屏蔽寄存器EXTI_IMR
,如果需要事件,则需要配置事件屏蔽寄存器EXTI_EMR
。
寄存器
查阅STM32F4参考手册 10.2章节《外部中断/事件控制器 (EXTI)》,可知STM32F4系列单片机有多达 23 个用于产生事件/中断请求的边沿检测器。每根输入线都可单独进行配置,以选择类型(中断或事件)和相应的触发事件(上升沿触发、下降沿触发或边沿触发)。每根输入线还可单独屏蔽。挂起寄存器用于保持中断请求的状态线。
STM32F4参考手册10.2.4中有说明。
要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置 2 个触发寄存器,同时在中断屏蔽寄存器的相应位写“1”使能中断请求。当外部中断线上出现选定信号沿时,便会产生中断请求,对应的挂起位也会置 1。在挂起寄存器的对应位写“1”,将清除该中断请求。
要产生事件,必须先配置好并使能事件线。根据需要的边沿检测设置 2 个触发寄存器,同时在事件屏蔽寄存器的相应位写“1”允许事件请求。当事件线上出现选定信号沿时,便会产生事件脉冲,对应的挂起位不会置 1。
通过在软件中对软件中断/事件寄存器写“1”,也可以产生中断/事件请求。
- 硬件中断选择
要配置 23 根线作为中断源,请执行以下步骤:
* 配置 23 根中断线的屏蔽位 (EXTI_IMR)
* 配置中断线的触发选择位(EXTI_RTSR 和 EXTI_FTSR)
* 配置对应到外部中断控制器 (EXTI) 的 NVIC 中断通道的使能和屏蔽位,使得 23 个中断线中的请求可以被正确地响应。
- 硬件事件选择
要配置 23 根线作为事件源,请执行以下步骤:
* 配置 23 根事件线的屏蔽位 (EXTI_EMR)
* 配置事件线的触发选择位(EXTI_RTSR 和 EXTI_FTSR)
- 软件中断/事件选择
可将这 23 根线配置为软件中断/事件线。以下为产生软件中断的步骤。
* 配置 23 根中断/事件线的屏蔽位(EXTI_IMR、EXTI_EMR)
* 在软件中断寄存器设置相应的请求位 (EXTI_SWIER)
中断屏蔽寄存器
事件屏蔽寄存器
软件中断事件寄存器
挂起寄存器
外部中断配置
外部中断的配置与使用通过STM32CubeMX配置请转STM32CubeMX系列教程2:外部中断EXIT查看,这里主要讲解软件中断的配置方式。
软件中断配置
配置过程
通过阅读参考手册可知,配置软件中断只需要配置中断屏蔽寄存器
,在程序中需要发起软件中断的地方置位相应的软件中断事件寄存器
。即可向CPU发起中断。
创建工程
打开STM32CubeMX,选择一个单片机,生成一个工程。
开启软件中断
从单片机的23个外部中断线中选择一个中断线作为软件中断线使用,被使用的中断线不可在作为外部中断使用。这里我选择使用EXTI0做为软件中断线使用。
打开创建的工程,打开启动文件,查看中断函数入口名称。
由启动文件可知,外部中断0的中断入口名称为EXTI0_IRQHandler
。
在main()
函数中的while(1)
前/* USER CODE BEGIN 2 */
与/* USER CODE END 2 */
之间添加中断配置代码。
EXTI->IMR |= 1<<0; //配置开放中断线0中断
HAL_NVIC_SetPriority(EXTI0_IRQn, 15, 0); //设置中断线0的中断优先级
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线0
EXTI->IMR
中断屏蔽寄存器的第0位写入1,可开放中断线0。
通过中断入口名称EXTI0_IRQHandler
可推测外部中断0的中断号名称为EXTI0_IRQn
。
通过调用HAL_NVIC_SetPriority(EXTI0_IRQn, 15, 0);
函数可设置外部中断0的抢占优先级为15;这里注意:单片机的中断优先级位数,如STM32F4的中断优先级为4位可编程优先级,也就是16个优先级,0为最高有限,15为最低优先级。设置中断优先级为15是为防止打断其他中断,使软中断的任务优先级仅高于主循环的优先级
中断优先级详解转 STM32CubeMX系列教程2:外部中断EXIT 中断优先级小节查阅。
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
中断使能函数,使能外部中断0,调用此函数后,CPU才会对外部中断0作出反应。
创建中断回调函数
已知外部中断0的中断回调函数名为EXTI0_IRQHandler
,中断回调函数名称必须与启动文件中相同。
在main.c
文件的下方/* USER CODE BEGIN 4 */
与/* USER CODE END 4 */
之间实现终端回调函数。
void EXTI0_IRQHandler()
{
if(EXTI->PR &= 1<<0){
EXTI->PR |= 1<<0;
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
}
中断回调函数中以翻转LED灯的状态为例。首先读取EXTI->PR
挂起寄存器中的第0
位是否为1,如果为1
,则说明确实触发了外部中断线0。向对应位写1
,清除本次中断标志。
启动软中断
这里以在主循环中每隔500毫秒,发起一次软件中断为例。在while(1)
与/* USER CODE END WHILE */
之间写入软中断触发语句。
HAL_Delay(500);
EXTI->SWIER |= 1<<0;
主循环中每隔500ms在EXTI->SWIER
软件中断事件寄存器中的第0位写入1
。向CPU发起中断。
编译下载
将程序编译下载进单片机中,就可以看到LED灯每隔500ms,状态翻转一次。