(上述图片来自正点原子)
本次实验内容为利用按键触发外部中断,使得灯泡实现亮灭,并且观察不同优先级下中断的现象。
exti.c文件里,①初始化中断
void exti_init(void)
{
GPIO_InitTypeDef gpio_init_struct; /* 定义结构体 */
__HAL_RCC_GPIOB_CLK_ENABLE(); /* 使能时钟 */
__HAL_RCC_GPIOA_CLK_ENABLE(); /* 使能时钟 */
gpio_init_struct.Pin = GPIO_PIN_0; /* 引脚配置 */
gpio_init_struct.Mode = GPIO_MODE_IT_RISING; /* 上升沿模式 */
gpio_init_struct.Pull = GPIO_PULLDOWN; /* 引脚下拉 */
HAL_GPIO_Init(GPIOB, &gpio_init_struct);
gpio_init_struct.Pin = GPIO_PIN_10; /* 引脚配置 */
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; /* 下降沿模式 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 引脚上拉 */
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 1); /* 设置优先级,抢占优先级为0,响应优先级为1,先比较抢占再比较响应,数字越小级别越高,响应优先级高 */
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); /* 使能中断 */
HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 2); /* 设置优先级,抢占优先级为1,响应优先级为2 */
HAL_NVIC_EnableIRQ(EXTI0_IRQn); /* 使能中断 */
}
注意事项:
(1)设定优先级时,HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority),32f103中IRQn只有七个,分别是EXTI0_IRQn,EXTI1_IRQn,EXTI2_IRQn,EXTI3_IRQn,EXTI4_IRQn,EXTI9_5_IRQn,EXTI15_10_IRQn,即0~4线是分开的,5~9与10~15是合并的,总共有7条中断线。
(2)?中断优先级比较规则:先比较抢占再比较响应,数字越小级别越高,响应优先级高。一次只能执行一个中断进程。
(3)设置上升沿有一个注意事项,JTAG是有默认几个引脚为上拉的,此时软件置为下拉将不起作用。SWD对应I/O引脚也有某些复用规则。如下图:
②中断回调处理机制:
当触发中断时,将跳转到下面函数
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10); /* 调用中断处理公用函数GPIO_PIN_10清除所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_10); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}
调用中断处理公用函数 清除GPIO_PIN_10所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(20);
switch(GPIO_Pin)
{
case GPIO_PIN_10:
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_10) == 1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
delay_ms(5000);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
}
break;
case GPIO_PIN_0:
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6);
}
break;
}
}
执行完callback函数,回到?EXTI0_IRQHandler执行__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0); 对中断标志位进行清零。