HAL 库的 stm32f4xx_hal_exti.h 和 stm32f4xx_hal_exti.c 文件中。
STM32F407 的中断控制器支持 23个外部中断/事件请求。
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB OTG FS 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
EXTI 线 20:连接到 USB OTG HS(在 FS 中配置)唤醒事件。
EXTI 线 21:连接到 RTC 入侵和时间戳事件。
EXTI 线 22:连接到 RTC 唤醒事件。
STM32F4 供 IO 口使用的中断线只有 16 个,但是 STM32F4 的 IO 口却远远不止 16 个,
GPIO 的管脚 GPIOx.0~GPIOx.15(x=A,B,C,D,E, F,G,H,I)分别对应中断线 0到15。
每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、 GPIOB.0、 GPIOC.0、
GPIOD.0、 GPIOE.0、 GPIOF.0、 GPIOG.0,GPIOH.0,GPIOI.0。
++++++++++++++++++++++++++++++++++++++++++
使用库函数配置外部中断的步骤。
- 使能 IO 口时钟,初始化 IO 口为输入
- 设置 IO 口模式,触发条件, 开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系。
使用 HAL 库的时候,都是在函数 HAL_GPIO_Init 中一次性完成的。函数内部会通过判断
Mode 的值来开启 SYSCFG 时钟,并且设置 IO 口和中断线的映射关系。
GPIO_InitTypeDef GPIO_Initure;
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //外部中断,上升沿触发
GPIO_Initure.Pull=GPIO_PULLDOWN; //默认下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
- 配置中断优先级(NVIC),并使能中断。
设置中断线 0 的中断优先级并使能外部中断 0 的方法为:
HAL_NVIC_SetPriority(EXTI0_IRQn,2,1); //抢占优先级为 2,子优先级为 1
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线 2
- 编写中断服务函数。
中断服务函数的名字是在 HAL 库中事先有定义的。
void EXTI0_IRQHandler();
void EXTI1_IRQHandler();
void EXTI2_IRQHandler();
void EXTI3_IRQHandler();
void EXTI4_IRQHandler();
void EXTI9_5_IRQHandler();
void EXTI15_10_IRQHandler();
HAL 库把中断处理过程进行了简单封装,
HAL 库 为 了 用 户 使 用 方 便 , 它 提 供 了 一 个 中 断 通 用 入 口 函 数
HAL_GPIO_EXTI_IRQHandler,在该函数内部直接调用回调函数 HAL_GPIO_EXTI_Callback。
在中断服务函数中直接调用外部中断共用处理函数 HAL_GPIO_EXTI_IRQHandler,然后在回调函
数 HAL_GPIO_EXTI_Callback 中通过判断中断是来自哪个 IO 口编写相应的中断服务控制逻辑。
该函数有一个入口参数就是 IO 口序号。在该函数内部,一般通过判断 IO 口序号值来确定中断是来自哪个 IO 口,也就是哪个中断线,然后编写相应的控制逻辑。
通过 switch 语句判断 IO 口来源,做出相应的处理。
++++++++++++++++++++++++++++++++++++
对于前后台架构的程序,
callback是运行在ISR的上下文中的,通常要求尽量少的占用CPU。通常完成一些打标的工作。
在main中,检查需要的标志,再做出后续的处理。
+++++++++++++++++++++++++++++++++++
实例,
在callback中打标。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin){
case wk_up_Pin:
wk_up_push = 1;
break;
case key2_Pin:
key2_push = 1;
break;
case key1_Pin:
key1_push = 1;
break;
case key0_Pin:
key0_push = 1;
break;
default:
break;
}
}
在main中检查标志,处理,然后清标。
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
while(!wk_up_push && !key2_push && !key1_push && !key0_push);
Delay(0x7fffff);
if(wk_up_push){
pin_value = HAL_GPIO_ReadPin(led1_GPIO_Port, led1_Pin);
HAL_GPIO_WritePin(led1_GPIO_Port ,led1_Pin ,!pin_value);
pin_value = HAL_GPIO_ReadPin(led2_GPIO_Port, led2_Pin);
HAL_GPIO_WritePin(led2_GPIO_Port ,led2_Pin ,!pin_value);
wk_up_push = 0;
}
if(key2_push){
pin_value = HAL_GPIO_ReadPin(led1_GPIO_Port, led1_Pin);
HAL_GPIO_WritePin(led1_GPIO_Port ,led1_Pin ,!pin_value);
key2_push = 0;
}
if(key1_push){
pin_value = HAL_GPIO_ReadPin(led2_GPIO_Port, led2_Pin);
HAL_GPIO_WritePin(led2_GPIO_Port ,led2_Pin ,!pin_value);
key1_push = 0;
}
if(key0_push){
HAL_GPIO_WritePin(beep_GPIO_Port ,beep_Pin ,1);
Delay(0x7fffff);
HAL_GPIO_WritePin(beep_GPIO_Port ,beep_Pin ,0);
key0_push = 0;
}
}