You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从零实现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寄存器的中断优先级分组,否则优先级移位的计算也会失效。
  • 额外需要确认的点
    1. 你未贴出GPIO模式配置的非中断相关代码,需要确认对应中断引脚已经被配置为输入模式,上下拉配置符合硬件电路要求,否则引脚电平异常也无法触发预期的边沿中断。
    2. 确认你已经实现了对应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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 02:45:06