你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F2外部按键触发中断问题

[复制链接]
lsimoniu 提问时间:2019-11-12 16:29 /
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:
  1. NVIC_InitTypeDef NVIC_InitStructure;
  2.         
  3.         /*Configure NVIC  as prioritygroup 2*/
  4.         /*PreemptionPriority 2 bit for 4 Priorities
  5.          *SubPriority 2 bits for 4 Priorities*/
  6.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

  7.         NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  8.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
  9.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  10.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  11.         NVIC_Init(&NVIC_InitStructure);
  12.         
  13.         /*Configure the interrupt source for EXTI1*/
  14.         NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //
  15.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  16.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  17.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  18.         NVIC_Init(&NVIC_InitStructure);
  19.         
  20.         NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //  
  21.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  22.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  23.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  24.         NVIC_Init(&NVIC_InitStructure);
  25.         
  26.         NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //  
  27.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  28.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  29.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  30.         NVIC_Init(&NVIC_InitStructure);
复制代码


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


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

  13. void EXTI1_IRQHandler(void)
  14. {
  15.           /*Ensure the EXTI line interrupt occur*/
  16.       if (EXTI_GetITStatus(EXTI_Line1) != RESET)
  17.          {
  18.             printf("\r\nEXTI1 IRQHandler enter.\r\n");
  19.             EXTI_GenerateSWInterrupt(EXTI_Line2);         //软件触发EXTI2中断
  20.             printf("\r\nEXTI1 IRQHandler return.\r\n");
  21.             GPIOB -> ODR ^= GPIO_Pin_1;
  22.             EXTI_ClearITPendingBit(EXTI_Line1);
  23.           }
  24. }

  25. void EXTI2_IRQHandler(void)
  26. {
  27.         /*Ensure the EXTI line interrupt occur*/
  28.         if (EXTI_GetITStatus(EXTI_Line2) != RESET)
  29.         {
  30.                 printf("\r\nEXTI2 IRQHandler enter.\r\n");
  31.                 EXTI_GenerateSWInterrupt(EXTI_Line3);          //软件触发EXTI3中断
  32.                 printf("\r\nEXTI2 IRQHandler return.\r\n");
  33.                 GPIOB -> ODR ^= GPIO_Pin_2;
  34.                 EXTI_ClearITPendingBit(EXTI_Line2);
  35.         }
  36. }

  37. void EXTI3_IRQHandler(void)
  38. {
  39.         /*Ensure the EXTI line interrupt occur*/
  40.      if (EXTI_GetITStatus(EXTI_Line3) != RESET)
  41.         {
  42.            printf("\r\nEXTI3 IRQHandler enter.\r\n");
  43.            printf("\r\nEXTI3 IRQHandler return.\r\n");
  44.            GPIOB -> ODR ^= GPIO_Pin_3;
  45.            EXTI_ClearITPendingBit(EXTI_Line3);
  46.          }
  47. }
复制代码


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


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

原本以为是硬件干扰的问题,但是我试了试 不初始化EXTI1(EXTI 0,2,3均初始化),即:
  1. EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line2 | EXTI_Line3;         
  2.         EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  3.         EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  4.         EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  5.         EXTI_Init(&EXTI_InitStructure);
复制代码

此时按下KEY_USER2,就只能得到下面的串口输出,这是很正常的,因为EXTI1没有被初始化,后面嵌套的EXTI 2,3 自然也无法执行:
EXTI0 IRQHandler enter.

EXTI0 IRQHandler return.


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

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


按键电路图

按键电路图
收藏 1 评论7 发布时间:2019-11-12 16:29

举报

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

评分

参与人数 1蝴蝶豆 +2 收起 理由
STMCU + 2

查看全部评分

lsimoniu 回答时间:2019-11-12 17:05:45
唉,更搞笑了
我把下面注释完了,居然还能按键触发中断,问题还是存在
  1.         /*select the pin of KEY_USER2 */
  2.         //KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  3.         //KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  4.         //KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//The status of pin is depended on the external circuits completely  
  5.         //GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);
  6.        
  7.         /*Link the EXTI source to the pin of KEY_USER2
  8.          *Config the GPIOA as the SOURCE of EXTI0 */
  9.         //SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
复制代码
lsimoniu 回答时间:2019-11-12 20:10:23
mylovemcu 发表于 2019-11-12 19:07
看这么长挺费脑啊  好累  终于看懂了  问题也很简单
因为你选的是PA口  那个寄存器的值默认就是连接的PA口 ...

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

  5.      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
复制代码


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


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

以此类推,我由于也使能了EXTI 1,2,3,所以EXTI1[3:0],EXTI2[3:0],EXTI3[3:0]的位全部默认为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口,是来源于这些代码吧:
  1. KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  2.         KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  3.         KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//The status of pin is depended on the external circuits completely  
  4.         GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);

  5.      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
复制代码


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


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

以此类推,我由于也使能了EXTI 1,2,3,所以EXTI1[3:0],EXTI2[3:0],EXTI3[3:0]的位全部默认为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口,是来源于这些代码吧:
  1. KEY_GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  2.         KEY_GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  3.         KEY_GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//The status of pin is depended on the external circuits completely  
  4.         GPIO_Init(GPIOA,&KEY_GPIO_InitStructure);

  5.      SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
复制代码


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


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

以此类推,我由于也使能了EXTI 1,2,3,所以EXTI1[3:0],EXTI2[3:0],EXTI3[3:0]的位全部默认为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口  
不用客气  互相学习  共同进步
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版