STM32的外部按键中断问题

mercury70 2015-07-27 11:49:00
各位大虾好,在我的工程里需要串口通信和按键中断。具体是这样,有两个按键,每个按键被按下时进入中断服务子程序,再按一下退出,相当于模式切换。但是最近几天遇到了问题:当按键第一次被按下时,此时可以进入中断服务子程序;当按键再次被按下时,有时却不能回到主程序,主程序里只有一个主函数。望各位大虾能够指点指点,不胜感激。
优先级设置是:
抢占 响应
串口 2 0
定时器 1 0
按键1 0 0
按键2 0 1

代码如下:

主函数中是:
main()
{
。。。。。初始化
while(1)
{
function1();
}
}
以下是两个中断服务子程序。
void EXTI9_5_IRQHandler(void) //function1和function2模式切换
{
// int flag1=1;
int flag1=0;
if(EXTI_GetITStatus(EXTI_Line5) != RESET) //确保是否产生了EXTI Line中断
{
delayms(200); //延时消抖
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_5) == 0)
{

while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_5) == 0); //等待按键释放
//GPIO_WriteBit(GPIOB, GPIO_Pin_0, 0);
GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_RESET);
flag1=1;
}
}
while(flag1)
{
//if(!GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0)) function2();
function2();
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_5) == 0 ) //检测一下按键是否按下
{

delayms(200);// 防止是脉冲干扰的影响
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_5) == 0 )
{
while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_5) == 0); //等待按键释放
flag1=0;
}

}

}

// }
GPIO_WriteBit(GPIOB, GPIO_Pin_0,Bit_SET);
EXTI_ClearITPendingBit(EXTI_Line5); //清除中断标志位
}

void EXTI15_10_IRQHandler(void) //function1和function3模式切换
{
int flag2=1;
angle=After_filter[0];//记录当前要保持的角度
if(EXTI_GetITStatus(EXTI_Line11) != RESET) //确保是否产生了EXTI Line中断
{
delayms(200); //延时消抖
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == 0)
{
// GPIO_WriteBit(GPIOB, GPIO_Pin_1, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1))));//LED1反转
while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == 0); //等待按键释放
GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_RESET);
}

while(flag2)
{
if(!GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1)) function3();

if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == 0 ) //检测一下按键是否按下
{

delayms(200);// 防止是脉冲干扰的影响
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == 0 )
{
while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == 0); //等待按键释放
flag2=0;
}

}

}

}
GPIO_WriteBit(GPIOB, GPIO_Pin_1,Bit_SET);
EXTI_ClearITPendingBit(EXTI_Line11); //清除中断标志位
}
...全文
566 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
mercury70 2015-07-28
  • 打赏
  • 举报
回复
引用 9 楼 pppppp11 的回复:
[quote=引用 5 楼 mercury70 的回复:] [quote=引用 3 楼 pppppp11 的回复:] [quote=引用 2 楼 mercury70 的回复:] [quote=引用 1 楼 pppppp11 的回复:] 描述有问题吧,按键按一下进入中断程序,再按一下退出,难道如果不按的话就一直死在中断里面?不可能吧。。。而且在中断里面用delay延时。。。这个程序结构不太好吧
谢谢您的解答,我的程序思路是这样的:当不按按键时,主函数一直执行function1()函数,也就是function1模式;当按下按键1时,进入中断,一直执行function2()函数,设置了flag1标志,实现再次按键时退出中断,再次进入function1模式;当按键2按下时,进入中断,一直执行function3()函数,设置了flag2标志,实现再次按键时退出中断,再次进入function1模式。 使用延时函数是为了实现软件消抖功能。 主要是,如果不用flag标志,只能在function1、function2、function3函数中设置循环,这样更难实现再按一次按键退出中断;您有更好地办法吗?[/quote] 我比较倾向于另一种写法:把按键判断放在定时器中判断,主程序在main()函数中执行。框架如下: 全局变量: static unsigned char flag = 0; -(void)Timer_Irq /* 定时器1ms中断服务程序 */ { static unsigned char count1,count2,count3; if(按键1按下) { count1++; if(count1 >= 50) count1 = 50; } else if((count1 == 50) && (按键1放开)) { count1 = 0; flag = 1; } else count1 = 0; /********按键2和按键3同理***********/ /* 区别为当按键2按下时,flag = 2;按键3按下时,flag = 3; */ /* 清除中断标志 */ } -(void)main() { while(1) { switch(flag) case 1: /* 执行1操作 */ break; case 2: /* 执行2操作 */ break; case 3: /* 执行3操作 */ break; default: break; } } [/quote] 您好,谢谢您的回复,但是感觉您这种方式不太适合我,原因是:我的程序中默认循环执行function1()函数,而且只有两个按键;感觉您的这种思路怎样实现按键切换呢,按一次进入,再按一次退出?还有我的程序有中断优先级要求。 这么说吧,我的工程是这样的:一共四种模式,串口不停地向上位机发送数据。默认为function1模式;当收到来自上位机信号指令时,进入function2模式,上位机信号传来测试结束指令时,返回function1模式;当按键1按一下,进入function3模式,再按一下返回function1模式;按键2按一下,进入function4模式,再按一下返回function1模式;其中,串口接收中断优先级最高;按键1和按键2的抢占式优先级一样,但是按键1的响应优先级比按键2的响应优先级高。[/quote] 如果你要实现这种方式很简单啊: 1。按一次进入,那一次退出,那就在按键判断那里设置一下,如果按下第一个键,如果当前flag为1,说明在function1,那就把flag赋值0,那main函数不是就退出了? 2。优先级的问题,那就更没关系了。难道你会同时按下两个键?中间连1ms时间间隔都没有?不可能的呀,而且,就算同时,你也可以改下程序,比如说在再检测到按键2时,这时检测到了按键1,你也可以吧按键2的检测暂时关掉啊 我写的只是个程序框架,你不要照搬照抄啊,自己也得改下啊。。。 [/quote] 已经解决了,flag设置的有问题,一直处于中断中。 换成 if(flag==0) flag=2; else if(flag==2) flag=0;就好了。谢谢两位大虾!
胜负多少 2015-07-28
  • 打赏
  • 举报
回复
引用 5 楼 mercury70 的回复:
[quote=引用 3 楼 pppppp11 的回复:] [quote=引用 2 楼 mercury70 的回复:] [quote=引用 1 楼 pppppp11 的回复:] 描述有问题吧,按键按一下进入中断程序,再按一下退出,难道如果不按的话就一直死在中断里面?不可能吧。。。而且在中断里面用delay延时。。。这个程序结构不太好吧
谢谢您的解答,我的程序思路是这样的:当不按按键时,主函数一直执行function1()函数,也就是function1模式;当按下按键1时,进入中断,一直执行function2()函数,设置了flag1标志,实现再次按键时退出中断,再次进入function1模式;当按键2按下时,进入中断,一直执行function3()函数,设置了flag2标志,实现再次按键时退出中断,再次进入function1模式。 使用延时函数是为了实现软件消抖功能。 主要是,如果不用flag标志,只能在function1、function2、function3函数中设置循环,这样更难实现再按一次按键退出中断;您有更好地办法吗?[/quote] 我比较倾向于另一种写法:把按键判断放在定时器中判断,主程序在main()函数中执行。框架如下: 全局变量: static unsigned char flag = 0; -(void)Timer_Irq /* 定时器1ms中断服务程序 */ { static unsigned char count1,count2,count3; if(按键1按下) { count1++; if(count1 >= 50) count1 = 50; } else if((count1 == 50) && (按键1放开)) { count1 = 0; flag = 1; } else count1 = 0; /********按键2和按键3同理***********/ /* 区别为当按键2按下时,flag = 2;按键3按下时,flag = 3; */ /* 清除中断标志 */ } -(void)main() { while(1) { switch(flag) case 1: /* 执行1操作 */ break; case 2: /* 执行2操作 */ break; case 3: /* 执行3操作 */ break; default: break; } } [/quote] 您好,谢谢您的回复,但是感觉您这种方式不太适合我,原因是:我的程序中默认循环执行function1()函数,而且只有两个按键;感觉您的这种思路怎样实现按键切换呢,按一次进入,再按一次退出?还有我的程序有中断优先级要求。 这么说吧,我的工程是这样的:一共四种模式,串口不停地向上位机发送数据。默认为function1模式;当收到来自上位机信号指令时,进入function2模式,上位机信号传来测试结束指令时,返回function1模式;当按键1按一下,进入function3模式,再按一下返回function1模式;按键2按一下,进入function4模式,再按一下返回function1模式;其中,串口接收中断优先级最高;按键1和按键2的抢占式优先级一样,但是按键1的响应优先级比按键2的响应优先级高。[/quote] 如果你要实现这种方式很简单啊: 1。按一次进入,那一次退出,那就在按键判断那里设置一下,如果按下第一个键,如果当前flag为1,说明在function1,那就把flag赋值0,那main函数不是就退出了? 2。优先级的问题,那就更没关系了。难道你会同时按下两个键?中间连1ms时间间隔都没有?不可能的呀,而且,就算同时,你也可以改下程序,比如说在再检测到按键2时,这时检测到了按键1,你也可以吧按键2的检测暂时关掉啊 我写的只是个程序框架,你不要照搬照抄啊,自己也得改下啊。。。
mercury70 2015-07-28
  • 打赏
  • 举报
回复
引用 6 楼 u012586257 的回复:
通常中断里面只设标志,把消抖及其他处理都放在主循环里做,这样不会漏中断,否则容易出问题
您好,我刚试过了,有一点不好实现:再按一下按键,进入默认状态。您能再指教一下吗?
mercury70 2015-07-28
  • 打赏
  • 举报
回复
引用 6 楼 u012586257 的回复:
通常中断里面只设标志,把消抖及其他处理都放在主循环里做,这样不会漏中断,否则容易出问题
谢谢,我再改改试试。
mangoalx 2015-07-27
  • 打赏
  • 举报
回复
通常中断里面只设标志,把消抖及其他处理都放在主循环里做,这样不会漏中断,否则容易出问题
mercury70 2015-07-27
  • 打赏
  • 举报
回复
引用 3 楼 pppppp11 的回复:
[quote=引用 2 楼 mercury70 的回复:] [quote=引用 1 楼 pppppp11 的回复:] 描述有问题吧,按键按一下进入中断程序,再按一下退出,难道如果不按的话就一直死在中断里面?不可能吧。。。而且在中断里面用delay延时。。。这个程序结构不太好吧
谢谢您的解答,我的程序思路是这样的:当不按按键时,主函数一直执行function1()函数,也就是function1模式;当按下按键1时,进入中断,一直执行function2()函数,设置了flag1标志,实现再次按键时退出中断,再次进入function1模式;当按键2按下时,进入中断,一直执行function3()函数,设置了flag2标志,实现再次按键时退出中断,再次进入function1模式。 使用延时函数是为了实现软件消抖功能。 主要是,如果不用flag标志,只能在function1、function2、function3函数中设置循环,这样更难实现再按一次按键退出中断;您有更好地办法吗?[/quote] 我比较倾向于另一种写法:把按键判断放在定时器中判断,主程序在main()函数中执行。框架如下: 全局变量: static unsigned char flag = 0; -(void)Timer_Irq /* 定时器1ms中断服务程序 */ { static unsigned char count1,count2,count3; if(按键1按下) { count1++; if(count1 >= 50) count1 = 50; } else if((count1 == 50) && (按键1放开)) { count1 = 0; flag = 1; } else count1 = 0; /********按键2和按键3同理***********/ /* 区别为当按键2按下时,flag = 2;按键3按下时,flag = 3; */ /* 清除中断标志 */ } -(void)main() { while(1) { switch(flag) case 1: /* 执行1操作 */ break; case 2: /* 执行2操作 */ break; case 3: /* 执行3操作 */ break; default: break; } } [/quote] 您好,谢谢您的回复,但是感觉您这种方式不太适合我,原因是:我的程序中默认循环执行function1()函数,而且只有两个按键;感觉您的这种思路怎样实现按键切换呢,按一次进入,再按一次退出?还有我的程序有中断优先级要求。 这么说吧,我的工程是这样的:一共四种模式,串口不停地向上位机发送数据。默认为function1模式;当收到来自上位机信号指令时,进入function2模式,上位机信号传来测试结束指令时,返回function1模式;当按键1按一下,进入function3模式,再按一下返回function1模式;按键2按一下,进入function4模式,再按一下返回function1模式;其中,串口接收中断优先级最高;按键1和按键2的抢占式优先级一样,但是按键1的响应优先级比按键2的响应优先级高。
胜负多少 2015-07-27
  • 打赏
  • 举报
回复
上面switch少了个大括号,自己加吧。。。
胜负多少 2015-07-27
  • 打赏
  • 举报
回复
引用 2 楼 mercury70 的回复:
[quote=引用 1 楼 pppppp11 的回复:] 描述有问题吧,按键按一下进入中断程序,再按一下退出,难道如果不按的话就一直死在中断里面?不可能吧。。。而且在中断里面用delay延时。。。这个程序结构不太好吧
谢谢您的解答,我的程序思路是这样的:当不按按键时,主函数一直执行function1()函数,也就是function1模式;当按下按键1时,进入中断,一直执行function2()函数,设置了flag1标志,实现再次按键时退出中断,再次进入function1模式;当按键2按下时,进入中断,一直执行function3()函数,设置了flag2标志,实现再次按键时退出中断,再次进入function1模式。 使用延时函数是为了实现软件消抖功能。 主要是,如果不用flag标志,只能在function1、function2、function3函数中设置循环,这样更难实现再按一次按键退出中断;您有更好地办法吗?[/quote] 我比较倾向于另一种写法:把按键判断放在定时器中判断,主程序在main()函数中执行。框架如下: 全局变量: static unsigned char flag = 0; -(void)Timer_Irq /* 定时器1ms中断服务程序 */ { static unsigned char count1,count2,count3; if(按键1按下) { count1++; if(count1 >= 50) count1 = 50; } else if((count1 == 50) && (按键1放开)) { count1 = 0; flag = 1; } else count1 = 0; /********按键2和按键3同理***********/ /* 区别为当按键2按下时,flag = 2;按键3按下时,flag = 3; */ /* 清除中断标志 */ } -(void)main() { while(1) { switch(flag) case 1: /* 执行1操作 */ break; case 2: /* 执行2操作 */ break; case 3: /* 执行3操作 */ break; default: break; } }
mercury70 2015-07-27
  • 打赏
  • 举报
回复
引用 1 楼 pppppp11 的回复:
描述有问题吧,按键按一下进入中断程序,再按一下退出,难道如果不按的话就一直死在中断里面?不可能吧。。。而且在中断里面用delay延时。。。这个程序结构不太好吧
谢谢您的解答,我的程序思路是这样的:当不按按键时,主函数一直执行function1()函数,也就是function1模式;当按下按键1时,进入中断,一直执行function2()函数,设置了flag1标志,实现再次按键时退出中断,再次进入function1模式;当按键2按下时,进入中断,一直执行function3()函数,设置了flag2标志,实现再次按键时退出中断,再次进入function1模式。 使用延时函数是为了实现软件消抖功能。 主要是,如果不用flag标志,只能在function1、function2、function3函数中设置循环,这样更难实现再按一次按键退出中断;您有更好地办法吗?
胜负多少 2015-07-27
  • 打赏
  • 举报
回复
描述有问题吧,按键按一下进入中断程序,再按一下退出,难道如果不按的话就一直死在中断里面?不可能吧。。。而且在中断里面用delay延时。。。这个程序结构不太好吧

27,372

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧