lsimoniu 发表于 2019-11-12 16:29:17

STM32F2外部按键触发中断问题

STM32F2上手期,写了个多级嵌套中断试试。板子上有两个按键,KEY_USER1 和 KEY_USER2。
用其中的KEY_USER2(PA0)触发中断,GPIOA作为EXTI0的中断源。
然后在EXTI0中断里面嵌套软件中断EXTI0,EXTI0里又嵌套EXTI1的软件中断,以此类推。
整个流程就是【按键KEY_USER2(PA1)触发EXTI0 → 触发EXTI1→ 触发EXTI2→ 触发EXTI3】
后面三个都是嵌在前一个中断里的软件触发中断。
优先级是 EXTI3 > EXTI2 > EXTI1 > EXTI0 。
试验很顺利,按了板子上的USER2之后,从串口调试助手可以看到确实是按照上面的优先级来执行中断的,如下:
EXTI0 IRQHandler enter.

EXTI1 IRQHandler enter.

EXTI2 IRQHandler enter.

EXTI3 IRQHandler enter.

EXTI3 IRQHandler return.

EXTI2 IRQHandler return.

EXTI1 IRQHandler return.

EXTI0 IRQHandler return.


但令我不解的是,我不小心按了KEY_USER1按键后,中断也被触发了,并且直接从EXTI1这个中断开始执行(关键在于我并没有配置EXTI1的硬件输入中断,更别提配置KEY_USER1作为EXTI1的中断源了),如下:
EXTI1 IRQHandler enter.

EXTI2 IRQHandler enter.

EXTI3 IRQHandler enter.

EXTI3 IRQHandler return.

EXTI2 IRQHandler return.

EXTI1 IRQHandler return.


这是为什么呢?我一度怀疑是硬件出了问题,但又觉得多半是代码不妥,无奈水平很低,调了半天也没个所以然。
关键代码在下边,求各位指教!

这是配置的NVIC:
NVIC_InitTypeDef NVIC_InitStructure;
      
      /*Configure NVICas prioritygroup 2*/
      /*PreemptionPriority 2 bit for 4 Priorities
         *SubPriority 2 bits for 4 Priorities*/
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

      NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      
      /*Configure the interrupt source for EXTI1*/
      NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      
      NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      
      NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);

这是配置的按键中断
/*select the pin of KEY_USER2 */
      KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;               //PA0是KEY_USER2的引脚
      KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
      KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //The status of pin is depended on the external circuits completely
      GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);
      
      /*Link the EXTI source to the pin of KEY_USER2
         *Config the GPIOA as the SOURCE of EXTI0 */
      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);   //在这里配置了GPIOA作为EXTI0的中断输入源。并没有涉及EXTI1.
      
      /*select the IT soure*/
      EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1 | EXTI_Line2 | EXTI_Line3;      // EXTI1 -> PX1 (x = A,B,C...I)...
      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;
      EXTI_Init(&EXTI_InitStructure);

这是写的EXTI0~EXTI3的中断函数:
void EXTI0_IRQHandler(void)
{
          /*Ensure the EXTI line interrupt occur*/
   if (EXTI_GetITStatus(EXTI_Line0) != RESET)
       {
            printf("\r\nEXTI0 IRQHandler enter.\r\n");
            EXTI_GenerateSWInterrupt(EXTI_Line1);      //软件触发EXTI1中断
            printf("\r\nEXTI0 IRQHandler return.\r\n");
            GPIOB -> ODR ^= GPIO_Pin_0;
            EXTI_ClearITPendingBit(EXTI_Line0);
      }
}

void EXTI1_IRQHandler(void)
{
          /*Ensure the EXTI line interrupt occur*/
      if (EXTI_GetITStatus(EXTI_Line1) != RESET)
         {
            printf("\r\nEXTI1 IRQHandler enter.\r\n");
            EXTI_GenerateSWInterrupt(EXTI_Line2);         //软件触发EXTI2中断
            printf("\r\nEXTI1 IRQHandler return.\r\n");
            GPIOB -> ODR ^= GPIO_Pin_1;
            EXTI_ClearITPendingBit(EXTI_Line1);
          }
}

void EXTI2_IRQHandler(void)
{
      /*Ensure the EXTI line interrupt occur*/
      if (EXTI_GetITStatus(EXTI_Line2) != RESET)
      {
                printf("\r\nEXTI2 IRQHandler enter.\r\n");
                EXTI_GenerateSWInterrupt(EXTI_Line3);          //软件触发EXTI3中断
                printf("\r\nEXTI2 IRQHandler return.\r\n");
                GPIOB -> ODR ^= GPIO_Pin_2;
                EXTI_ClearITPendingBit(EXTI_Line2);
      }
}

void EXTI3_IRQHandler(void)
{
      /*Ensure the EXTI line interrupt occur*/
   if (EXTI_GetITStatus(EXTI_Line3) != RESET)
      {
         printf("\r\nEXTI3 IRQHandler enter.\r\n");
         printf("\r\nEXTI3 IRQHandler return.\r\n");
         GPIOB -> ODR ^= GPIO_Pin_3;
         EXTI_ClearITPendingBit(EXTI_Line3);
         }
}

补充一点,我把下面配置按键的代码注释掉后,把程序下载到板子里,发现依然可以跑,中断照常进行,并且串口也有输出,上面的问题也依然存在。。。。我更迷惑了:funk:
/*select the pin of KEY_USER2 */
      KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;               //PA0是KEY_USER2的引脚
      KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
      KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //The status of pin is depended on the external circuits completely
      GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);

因为两个按键 分别对应 PA0 和 PA1 , 问题焦点也在他们可以作为中断源的EXTI0 和 EXTI1 上,我在想,是不是和按键的PA0PA1 与 EXTI0 EXTI1 有关系的原因。

原本以为是硬件干扰的问题,但是我试了试 不初始化EXTI1(EXTI 0,2,3均初始化),即:
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line2 | EXTI_Line3;         
      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
      EXTI_InitStructure.EXTI_LineCmd = ENABLE;
      EXTI_Init(&EXTI_InitStructure);
此时按下KEY_USER2,就只能得到下面的串口输出,这是很正常的,因为EXTI1没有被初始化,后面嵌套的EXTI 2,3 自然也无法执行:
EXTI0 IRQHandler enter.

EXTI0 IRQHandler return.


并且此时再按KEY_USER1 按键,也没有任何反应了。

显然问题就在EXTI 1上,我没有配置它的外部硬件中断,却可以通过KEY_USER1(PA1)实现它的中断。


mylovemcu 发表于 2019-11-12 19:07:00

看这么长挺费脑啊好累终于看懂了问题也很简单
因为你选的是PA口那个寄存器的值默认就是连接的PA口所以只要是默认状态就是PA口PA0那个也是一样的
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
这个指令就是把口线中断指向的寄存器写入0所以这个寄存器如果是在默认值这个语句写与不写是一样的最后寄存器都是0

lsimoniu 发表于 2019-11-12 17:05:45

唉,更搞笑了:)
我把下面注释完了,居然还能按键触发中断,问题还是存在
        /*select the pin of KEY_USER2 */
        //KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        //KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        //KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//The status of pin is depended on the external circuits completely
        //GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);
       
        /*Link the EXTI source to the pin of KEY_USER2
       *Config the GPIOA as the SOURCE of EXTI0 */
        //SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);

lsimoniu 发表于 2019-11-12 20:10:23

mylovemcu 发表于 2019-11-12 19:07
看这么长挺费脑啊好累终于看懂了问题也很简单
因为你选的是PA口那个寄存器的值默认就是连接的PA口 ...

谢谢您的热心回复,不过很抱歉,我仍然不是很懂。您说我选的PA口,是来源于这些代码吧:
        KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//The status of pin is depended on the external circuits completely
        GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);

   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);

但是我已将它们注释掉,程序仍能运行。


还是说,您的意思是,在使能了EXTI0的情况下,假如没有写上述语句,外部中断配置寄存器SYSCFG_EXTICR1中的EXTI0位会默认为0000,即选择了PA0为EXTI0的输入源?

以此类推,我由于也使能了EXTI 1,2,3,所以EXTI1,EXTI2,EXTI3的位全部默认为0000,即PA1,PA2,PA3都被默认为相应EXTI的输入源,所以在我的原程序中,即便没有配置EXTI1的外部中断,我按下KEY_USER1也能触发EXTI1中断,因为KEY_USER1的pin就是PA1,我这样理解对吗?

lsimoniu 发表于 2019-11-12 20:13:03

mylovemcu 发表于 2019-11-12 19:07
看这么长挺费脑啊好累终于看懂了问题也很简单
因为你选的是PA口那个寄存器的值默认就是连接的PA口 ...

谢谢您的热心回复,不过很抱歉,我仍然不是很懂。您说我选的PA口,是来源于这些代码吧:
KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//The status of pin is depended on the external circuits completely
        GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);

   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);

但是我已将它们注释掉,程序仍能运行。


还是说,您的意思是,在使能了EXTI0的情况下,假如没有写上述语句,外部中断配置寄存器SYSCFG_EXTICR1中的EXTI0位会默认为0000,即选择了PA0为EXTI0的输入源?

以此类推,我由于也使能了EXTI 1,2,3,所以EXTI1,EXTI2,EXTI3的位全部默认为0000,即PA1,PA2,PA3都被默认为相应EXTI的输入源,所以在我的原程序中,即便没有配置EXTI1的外部中断,我按下KEY_USER1也能触发EXTI1中断,因为KEY_USER1的pin就是PA1,我这样理解对吗?

lsimoniu 发表于 2019-11-12 20:23:21

mylovemcu 发表于 2019-11-12 19:07
看这么长挺费脑啊好累终于看懂了问题也很简单
因为你选的是PA口那个寄存器的值默认就是连接的PA口 ...

谢谢您的热心回复,不过很抱歉,我仍然不是很懂。您说我选的PA口,是来源于这些代码吧:
KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//The status of pin is depended on the external circuits completely
        GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);

   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);

但是我已将它们注释掉,程序仍能运行。


还是说,您的意思是,在使能了EXTI0的情况下,假如没有写上述语句,外部中断配置寄存器SYSCFG_EXTICR1中的EXTI0位会默认为0000,即选择了PA0为EXTI0的输入源?

以此类推,我由于也使能了EXTI 1,2,3,所以EXTI1,EXTI2,EXTI3的位全部默认为0000,即PA1,PA2,PA3都被默认为相应EXTI的输入源,所以在我的原程序中,即便没有配置EXTI1的外部中断,我按下KEY_USER1也能触发EXTI1中断,因为KEY_USER1的pin就是PA1,我这样理解对吗?

lsimoniu 发表于 2019-11-12 21:46:39

mylovemcu 发表于 2019-11-12 19:07
看这么长挺费脑啊好累终于看懂了问题也很简单
因为你选的是PA口那个寄存器的值默认就是连接的PA口 ...

谢谢您,我明白了,参考手册里的寄存器写明了Reset Value 是0x0000,也就是缺省为选择了PA0~PA3为中断输入源,而恰好两个按键的PA0和PA1都在其中,因此有没有SYSCFG_EXTILine和前面对GPIOA的配置,效果都是一样的。谢谢您!

mylovemcu 发表于 2019-11-13 14:54:23

lsimoniu 发表于 2019-11-12 21:46
谢谢您,我明白了,参考手册里的寄存器写明了Reset Value 是0x0000,也就是缺省为选择了PA0~PA3为中断输入 ...

是的口线的默认配置都是连接的PA口
不用客气互相学习共同进步
页: [1]
查看完整版本: STM32F2外部按键触发中断问题