目录
1、中断优先级
STM32 中的中断优先级可以分为:抢占式优先级和响应优先级,响应优先级也称子优先级,每个中断源都需要被指定这两种优先级。抢占式优先级和响应优先级的区别:
抢占优先级:抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。
响应优先级:抢占优先级相同,响应优先级高的中断不能打断响应优先级低的中断。
还有一种情况就是当两个或者多个中断的抢占式优先级和响应优先级相同时,那么就遵循自然优先级,看中断向量表的中断排序,数值越小,优先级越高。
2、中断分类
(1)STM32F103中断
STM32F103 的 EXTI 支持 19 个外部中断/事件请求,这些都是信息输入端,具体如下:
EXTI 线 0~15:对应外部 IO 口的输入中断
EXTI 线 16:连接到 PVD 输出
EXTI 线 17:连接到 RTC 闹钟事件
EXTI 线 18:连接到 USB 唤醒事件
EXTI 线 19:连接到以太网唤醒事件
(2)STM32F407中断
STM32F407 的 EXTI 支持 23 个外部中断/事件请求,这些都是信息输入端,具体如下:
EXTI 线 0~15:对应外部 IO 口的输入中断
EXTI 线 16:连接到 PVD 输出
EXTI 线 17:连接到 RTC 闹钟事件
EXTI 线 18:连接到 USB 唤醒事件
EXTI 线 19:连接到以太网唤醒事件
EXTI 线 20:连接到 USB OTG HS(在 FS 中配置)唤醒事件
EXTI 线 21:连接到 RTC 入侵和时间戳事件
EXTI 线 22:连接到 RTC 唤醒事件
(3)GPIO中断
STM32 把 GPIO 管脚 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线 0~15。这样子每个中断线对应了最多 7 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0 和 GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置决定对应的中断线配置到哪个 GPIO 上了。
3、引脚中断
初始化:
/**
* @brief 外部中断初始化程序
* @param 无
* @retval 无
*/
void extix_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
gpio_init_struct.Pin = GPIO_PIN_4; /* KEY0 引脚 */
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; /* 下升沿触发 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
HAL_GPIO_Init(GPIOE, &gpio_init_struct); /* KEY0 引脚初始化 */
gpio_init_struct.Pin= GPIO_PIN_3; /* KEY1 引脚 */
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; /* 下升沿触发 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
HAL_GPIO_Init(GPIOE, &gpio_init_struct); /* KEY1 引脚初始化 */
gpio_init_struct.Pin = GPIO_PIN_0; /* WKUP 引脚 */
gpio_init_struct.Mode = GPIO_MODE_IT_RISING; /* 上升沿触发 */
gpio_init_struct.Pull = GPIO_PULLDOWN; /* 下拉 */
HAL_GPIO_Init(GPIOA, &gpio_init_struct); /* WKUP 引脚初始化 */
HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 2); /* 抢占 0,子优先级 2 */
HAL_NVIC_EnableIRQ(EXTI4_IRQn); /* 使能中断线 4 */
HAL_NVIC_SetPriority(EXTI3_IRQn, 1, 2); /* 抢占 1,子优先级 2 */
HAL_NVIC_EnableIRQ(EXTI3_IRQn); /* 使能中断线 3 */
HAL_NVIC_SetPriority(EXTI0_IRQn, 3, 2); /* 抢占 2,子优先级 2 */
HAL_NVIC_EnableIRQ(EXTI0_IRQn); /* 使能中断线 0 */
}
中断函数:
/**
* @brief KEY0 外部中断服务程序
* @param 无
* @retval 无
*/
void KEY0_INT_IRQHandler(void)
{
/* 调用中断处理公用函数 清除 KEY0 所在中断线 的中断标志位 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
/* HAL 库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
}
/**
* @brief KEY1 外部中断服务程序
* @param 无
* @retval 无
*/
void KEY1_INT_IRQHandler(void)
{
/* 调用中断处理公用函数 清除 KEY1 所在中断线 的中断标志位 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
/* HAL 库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3);
}
/**
* @brief WK_UP 外部中断服务程序
* @param 无
* @retval 无
*/
void WKUP_INT_IRQHandler(void)
{
/* 调用中断处理公用函数 清除 KEY_UP 所在中断线 的中断标志位 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* HAL 库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
}
中断回调函数:
/**
* @brief 中断服务程序中需要做的事情
在 HAL 库中所有的外部中断服务函数都会调用此函数
* @param GPIO_Pin:中断引脚号
* @retval 无
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(20); /* 消抖 */
switch(GPIO_Pin)
{
case GPIO_PIN_4:
if (KEY0 == 0)
{
LED0_TOGGLE(); /* LED0 状态取反 */
LED1_TOGGLE(); /* LED1 状态取反 */
}
break;
case GPIO_PIN_3:
if (KEY1 == 0)
{
LED0_TOGGLE(); /* LED0 状态取反 */
}
break;
case GPIO_PIN_0:
if (WK_UP == 1)
{
LED1_TOGGLE(); /* LED1 状态取反 */
}
break;
}
}
按下对应按键,执行对应回调函数,主函数只需要初始化 “extix_init(); ”,不需要调用。