从零实现GPIO中断代码运行异常,附相关代码求错误排查
GPIO中断实现代码错误排查
以下是你代码中存在的几处问题:
- SYSCFG外设名拼写错误
代码中配置EXTI路由时全部用了SYSFG->EXTICR,正确的外设寄存器名应为SYSCFG->EXTICR,拼写错误会导致EXTI和GPIO端口的路由配置完全失效,中断无法正常触发。 - NVIC中断使能/失能的偏移计算错误
在GPIO_IT_Config函数中,处理IRQ号在63~95区间的代码里,你使用了IRQNumber % 64计算位偏移,但是每个NVIC_ISER/NVIC_ICER寄存器都是32位宽,正确的偏移计算应为IRQNumber % 32,错误的偏移会导致你实际操作的是寄存器的无效位,对应中断根本没有被启用。 - NVIC优先级配置逻辑错误
GPIO_IT_Priority函数中你直接用|=操作写入优先级,没有先清空对应优先级位段。如果该位段此前有残留值,会导致实际写入的优先级和预期不符,若优先级低于系统当前阈值,中断会被直接屏蔽。同时你需要确认已经提前配置好SCB->AIRCR寄存器的中断优先级分组,否则优先级移位的计算也会失效。 - 额外需要确认的点
- 你未贴出GPIO模式配置的非中断相关代码,需要确认对应中断引脚已经被配置为输入模式,上下拉配置符合硬件电路要求,否则引脚电平异常也无法触发预期的边沿中断。
- 确认你已经实现了对应EXTI线的中断服务函数,函数名必须和启动文件内中断向量表的定义完全一致,且在服务函数中及时清除
EXTI->PR1寄存器对应位的挂起标志,否则会出现中断无法进入、或者一直重复触发的问题。
你提供的原始代码参考:
1. GPIO中断初始化代码
void GPIO_Init(GPIO_handle_t *pGPIOHandle){ .... //Other non interrupt related code .... //Interrupt mode if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_IT_RT){ //Set EXTI to generate an interrupt if rising edge occur and clear of the falling edge EXTI->RTSR1 |= (1 << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber)); EXTI->FTSR1 &= ~(1 << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber)); }else if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode ==GPIO_MODE_IT_FT){ //Set EXTI to generate an interrupt if falling edge occur and clear of the rising edge EXTI->FTSR1 |= (1 << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber)); EXTI->RTSR1 &= ~(1 << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber)); }else if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode ==GPIO_MODE_IT_RFT){ //Set EXTI to generate an interrupt if rising edge occur and set of the falling edge EXTI->RTSR1 |= (1 << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber)); EXTI->FTSR1 |= (1 << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber)); } //Configure the SYSCFG register for the mux selector uint8_t EXTICRx_Index; //EXTICRx index; 0, 1, 2, 3 uint8_t EXTICRx_Position; //Position inside the EXTICRx __RCC_SYSCFG_ENABLE_CLK(); //Clock enable for SYSCFGs EXTICRx_Index = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber / 4; EXTICRx_Position = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber % 4; if (pGPIOHandle->pGPIOx == GPIOA){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x0 << (4 * EXTICRx_Position)); }else if(pGPIOHandle->pGPIOx == GPIOB){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x1 << (4 * EXTICRx_Position)); }else if(pGPIOHandle->pGPIOx == GPIOC){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x2 << (4 * EXTICRx_Position)); }else if(pGPIOHandle->pGPIOx == GPIOD){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x3 << (4 * EXTICRx_Position)); }else if(pGPIOHandle->pGPIOx == GPIOE){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x4 << (4 * EXTICRx_Position)); }else if(pGPIOHandle->pGPIOx == GPIOF){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x5 << (4 * EXTICRx_Position)); }else if(pGPIOHandle->pGPIOx == GPIOG){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x6 << (4 * EXTICRx_Position)); }else if(pGPIOHandle->pGPIOx == GPIOH){ //Clear and set SYSFG->EXTICR[EXTICRx_Index] &= ~(0xf << (4 * EXTICRx_Position)); SYSFG->EXTICR[EXTICRx_Index] |= (0x7 << (4 * EXTICRx_Position)); } //Enable the interrupt for that pin EXTI->IMR1 |= (1 << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber)); } .... //Other no interrupt related code ....
2. NVIC中断配置代码
void GPIO_IT_Config(uint8_t IRQNumber, uint8_t EnOrDi){ if(EnOrDi == ENABLE){ if(IRQNumber <= 31){ *(NVIC_ISER0) |= (1 << IRQNumber); }else if(IRQNumber > 31 && IRQNumber < 64){ *(NVIC_ISER1) |= (1 << (IRQNumber % 32)); }else if(IRQNumber > 63 && IRQNumber < 96){ *(NVIC_ISER2) |= (1 << (IRQNumber % 64)); } }else if(EnOrDi == DISABLE){ if(IRQNumber <= 31){ *(NVIC_ICER0) |= (1 << IRQNumber); }else if(IRQNumber > 31 && IRQNumber < 64){ *(NVIC_ICER1) |= (1 << (IRQNumber % 32)); }else if(IRQNumber > 63 && IRQNumber < 96){ *(NVIC_ICER2) |= (1 << (IRQNumber % 64)); } } }
3. 中断优先级配置代码
void GPIO_IT_Priority(uint8_t IRQNumber, uint32_t IRQPriority){ //1. first lets find out the ipr register uint8_t iprx = IRQNumber / 4; uint8_t iprx_section = IRQNumber % 4 ; uint8_t shift_amount = ( 8 * iprx_section) + ( 8 - 4) ; *( NVIC_PR_BASE_ADDR + iprx ) |= ( IRQPriority << shift_amount ); }
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

