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 NVIC as 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);
- }
- }
复制代码
补充一点,我把下面配置按键的代码注释掉后,把程序下载到板子里,发现依然可以跑,中断照常进行,并且串口也有输出,上面的问题也依然存在。。。。我更迷惑了
- /*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 上,我在想,是不是和按键的PA0 PA1 与 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)实现它的中断。
|
因为你选的是PA口 那个寄存器的值默认就是连接的PA口 所以只要是默认状态就是PA口 PA0那个也是一样的
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
这个指令就是把口线中断指向的寄存器写入0 所以这个寄存器如果是在默认值 这个语句写与不写是一样的 最后寄存器都是0
评分
查看全部评分
我把下面注释完了,居然还能按键触发中断,问题还是存在
谢谢您的热心回复,不过很抱歉,我仍然不是很懂。您说我选的PA口,是来源于这些代码吧:
但是我已将它们注释掉,程序仍能运行。
还是说,您的意思是,在使能了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,我这样理解对吗?
谢谢您的热心回复,不过很抱歉,我仍然不是很懂。您说我选的PA口,是来源于这些代码吧:
但是我已将它们注释掉,程序仍能运行。
还是说,您的意思是,在使能了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,我这样理解对吗?
谢谢您的热心回复,不过很抱歉,我仍然不是很懂。您说我选的PA口,是来源于这些代码吧:
但是我已将它们注释掉,程序仍能运行。
还是说,您的意思是,在使能了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,我这样理解对吗?
谢谢您,我明白了,参考手册里的寄存器写明了Reset Value 是0x0000,也就是缺省为选择了PA0~PA3为中断输入源,而恰好两个按键的PA0和PA1都在其中,因此有没有SYSCFG_EXTILine和前面对GPIOA的配置,效果都是一样的。谢谢您!
是的 口线的默认配置都是连接的PA口
不用客气 互相学习 共同进步