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

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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版