最近在做一个关于USB PD快充的项目,在使用外部中断的时候遇到了一个奇怪的问题,一使能中断就直接触发了外部中断,进去了中断服务函数。
引脚配置是高电平,上拉;也量了引脚的电平,是一个持续的高电平,并没有出现任何的沿(我设置的触发方式是下降沿触发,单片机是STM32F103ZE)。
通过查看手册发现,要使用外部中断功能涉及到的寄存器主要有以下4个寄存器:
- 中断屏蔽寄存器(EXTI_IMR)
- 上升沿触发选择寄存器(EXTI_RTSR)
- 下降沿触发选择寄存器(EXTI_FTSR)
- 挂起寄存器(EXTI_PR)
由图中的红线可知:
第一个红箭头处为逻辑或,当边沿检测电路检测到下降沿或上升沿的时候,不管软件中断事件寄存器的值是多少,挂起寄存器都会被置为1;
蓝色箭头处为逻辑与,由于在配置外部中断的时候,中断屏蔽寄存器已经被置1,所以当挂起寄存器置为1的时候就会进到中断服务函数里即触发了中断。
由上面的分析可知,要同时满足EXTI_PR和EXTI_IMR两个寄存器才会进到中断服务函数。
但是我一进中断就会清掉挂起寄存器,而且我还用void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)函数将引脚恢复为了初始状态,为什么还会一开启中断就进中断函数了呢?
通过仿真发现,在清完挂起寄存器后,由于下降沿来的速度很快,基本上在3us左右,所以在我还没关掉中断使能的时候,挂起寄存器就又被值1了,虽然这时候我关掉了中断使能,但是挂起寄存器和中断屏蔽寄存器都是1,所以当我再开中断使能的时候,由于EXTI_PR和EXTI_IMR逻辑与成立,所以马上就进了中断。
所以我们在使用外部中断的时候,要注意EXTI_PR和EXTI_IMR这两个寄存器,在开启中断使能前,要保证挂起寄存器的值一定是被清零的,可用EXTI->PR = __EXTI_LINE__来进行挂起寄存器清零,如我配置为外部中断的引脚是GPIO_PIN_1,所以__EXTI_LINE__的值就是GPIO_PIN_1。
GPIO_InitTypeDef GPIO_InitStruct;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
/* PA1配为外部中断,下降沿触发 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 清挂起寄存器,写1清零 */
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
/* 设置中断优先级 */
HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0);
/* 开启中断使能 */
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
以上为本人亲测可行,实际情况不同实际的效果可能也会不一样。
如果上面的方法不行,可以看看RCC->APB2ENR的AFIO有没有使能,没有使能的话就把它使能。