找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 433|回复: 14
打印 上一主题 下一主题
收起左侧

STM32单片机外部中断结束后的返回问题

[复制链接]
跳转到指定楼层
楼主
     大家好!我最近在学习STM32的外部中断,遇到一个问题,在这里请教大家。因为程序简单,附件里也有程序,所以就不画图了,大致描述一下:
1,用STM32F103C8T6的最小系统写了一个最简单的程序,主程序里就一个while(1),里面是让一个LED灯循环闪烁。
2,在主程序基础上,增加了一个外部中断,按下按键则进入中断,在中断里LED灯闪烁两次。
      程序正常运行,上电LED闪烁,按下按键可以进入中断,也能观察到灯闪烁两次。但是,中断执行完后,程序并不是返回while(1)里让灯继续闪烁,而是停止了(灯熄灭状态)。再次按下按键,仍然可以进入中断,仍然不返回主程序的while(1)。
     初学者,水平很差,我想问一下,中断执行完毕后,不是返回主程序继续执行中断前的程序吗?是我的理解不对吗?
     中断里已经清除了标志位的。附件里是程序,文件BUZZER是灯,METAL是按键及中断。谢谢。

外部中断.7z

183.82 KB, 下载次数: 0

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:205485 发表于 2025-5-13 08:39 | 只看该作者








这是原理图和程序,原理图就是一个最小系统,两个箭头PA8是按键,PB1是LED灯,其他IO口可忽略

回复

使用道具 举报

板凳
ID:744809 发表于 2025-5-13 08:46 | 只看该作者
中断里面不要放软件延时函数,另外中断里面的代码一定要精简,最好控制在100us以内
回复

使用道具 举报

地板
ID:469589 发表于 2025-5-13 09:33 | 只看该作者
应该是中断级别的我问题,高级中断里调用了更高级中断DELAY(SYSTICK).
回复

使用道具 举报

5#
ID:592807 发表于 2025-5-13 09:52 | 只看该作者
嗯,一般人很少会在中断里面用放延时函数的,像你这种直接在中断里面放4个delay_ms(500)加一个delay_ms(100),更加少见,大概就像,你正常情况下每秒钟必须呼吸一次(中断需要要循环访问,后台自动控制决定的),然后你训练拳法,没呼吸一次要打300拳法(你一个中断占用了2秒多),你不管你的肺抗不扛得住,憋晕过去也要打完300拳法(你也不管其他中断会不会冲突是吧,),打完拳你也不呼气(按键中断的标签去除了,但是按键弹起来了吗)
void EXTI9_5_IRQHandler(void)
{
         
   if(EXTI_GetITStatus(EXTI_Line8)==SET)
        {
                Delay_ms(100);
         if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8) == 0)
         {
                  Buzzer_ON();
                  Delay_ms(500);
                  Buzzer_OFF();
                  Delay_ms(500);
                  Buzzer_ON();
                  Delay_ms(500);
                  Buzzer_OFF();
                  Delay_ms(500);
         }
          
        }
          EXTI_ClearITPendingBit(EXTI_Line8);
}
回复

使用道具 举报

6#
ID:205485 发表于 2025-5-13 10:40 | 只看该作者
谢谢大家,我刚才把延时全部调整成了1毫秒,问题依然存在。估计是前面那个朋友说的,是延时函数的优先级问题。
回复

使用道具 举报

7#
ID:205485 发表于 2025-5-13 12:59 | 只看该作者
中断里只要有延时函数,不论长短(即使几微秒),都会卡死;注释掉延时函数,就好了。
回复

使用道具 举报

8#
ID:685462 发表于 2025-5-14 00:06 | 只看该作者
红花无常 发表于 2025-5-13 10:40
谢谢大家,我刚才把延时全部调整成了1毫秒,问题依然存在。估计是前面那个朋友说的,是延时函数的优先级问 ...

void Delay_us(uint32_t xus)
{
        SysTick->LOAD = 72 * xus;                                //设置定时器重装值
        SysTick->VAL = 0x00;                                        //清空当前计数值
        SysTick->CTRL = 0x00000005;                                //设置时钟源为HCLK,启动定时器
        while(!(SysTick->CTRL & 0x00010000));        //等待计数到0
        SysTick->CTRL = 0x00000004;                                //关闭定时器
}
打个断点仿真下就看到了,中断运行后卡到了deay函数等待计数到0。感觉是在main中delay时,进入中断,中断delay后闭定时器,中断完回到main中的delay,这时的计数器已经关闭了。卡到“while(!(SysTick->CTRL & 0x00010000));”这一句。在while中添加个检测计数器是否关闭,如果关闭的,打开计时器。

        while(!(SysTick->CTRL & 0x00010000))        //等待计数到0
        {
                if(SysTick->CTRL == 0x00000004)
                {

              SysTick->CTRL = 0x00000005;                                //设置时钟源为HCLK,启动定时器                       
                }
                       
                       
回复

使用道具 举报

9#
ID:205485 发表于 2025-5-14 12:02 | 只看该作者
lose2836 发表于 2025-5-14 00:06
void Delay_us(uint32_t xus)
{
        SysTick->LOAD = 72 * xus;                                //设置定时器重装值

      谢谢!看来问题应该就是出在这里。主函数里有DELAY,主函数正在执行DELAY时,发生了中断,中断函数里也有DELAY,中断函数里执行完DELAY后,关闭了计时器,导致主函数里的DELAY也关闭了。
      所以如果在中断函数里需要延时,最好是用定时计数器重新写一个。
回复

使用道具 举报

10#
ID:401564 发表于 2025-5-14 12:39 | 只看该作者
1,中断中不要做太多的任务,delay这种延时更加不要加,不管是按键也好,ADC也好,还是其它的什么,中断事件只要触发某个事件的标志就可以了,再在主函数中根据对应的标志进行处理
比如ADC,串口之类的,就只管把数据保存就可以了,不要在中断中处理,当然,STM32有DMA,那是以后的事了
2,长时间延时,可以用定时器来进行,类似于SysTick的方式,不要死等,让单片机500mS什么事都不做,这不是一个好习惯
回复

使用道具 举报

11#
ID:205485 发表于 2025-5-14 21:35 | 只看该作者
Y_G_G 发表于 2025-5-14 12:39
1,中断中不要做太多的任务,delay这种延时更加不要加,不管是按键也好,ADC也好,还是其它的什么,中断事件只要 ...

好的,谢谢。原则我明白了,具体是通过何种方式实现呢?比如,在触发中断后,有一连串的操作,耗时6-7秒。现在我知道,不能在中断中处理这么多任务,只能在主程序里处理。那么,该怎么通知主程序呢?是让主程序不断在while循环里扫描,看中断标志位是否为1吗?那样的话,是不是都可以不用外部中断了,直接在主程序里扫描那个IO口的电平判断按钮是否按下即可。
回复

使用道具 举报

12#
ID:401564 发表于 2025-5-15 10:04 | 只看该作者
红花无常 发表于 2025-5-14 21:35
好的,谢谢。原则我明白了,具体是通过何种方式实现呢?比如,在触发中断后,有一连串的操作,耗时6-7秒 ...

假设你是按键触发,那么好,你全声明一个全局变量
u8 key_f = 0;//这个变量就是用来通知主程序的
在中断程序中

EXTI9-5中断
{
  key_f = 1;
}

主程序中
main()
{
   if(key_f)
   {
      key_f = 0;
      按键处理相关代码;
    }
}
key_f 在中断记录, 在主程序中清除,这是提供一个思路,原理就大概是这么个原理
回复

使用道具 举报

13#
ID:205485 发表于 2025-5-15 13:52 | 只看该作者
Y_G_G 发表于 2025-5-15 10:04
假设你是按键触发,那么好,你全声明一个全局变量
u8 key_f = 0;//这个变量就是用来通知主程序的
在中断 ...

     您说的这个意思我能明白,只是,如果这样的话,是不是中断都可以不要了,像下面这样就行了。我一直没搞清楚的就是这个。
main()
{
   if(KEY按下)
   {
      按键处理相关代码;
    }
}
回复

使用道具 举报

14#
ID:401564 发表于 2025-5-15 16:23 | 只看该作者
红花无常 发表于 2025-5-15 13:52
您说的这个意思我能明白,只是,如果这样的话,是不是中断都可以不要了,像下面这样就行了。我一直 ...

对于按键中断,并不是绝对需要的,可以不用中断,直接在主程序中扫描按键就可以了
但有时候是要中断的,比如按键级别要求要高的,或者是按键要唤醒单片机的,这个时候就会用到中断
而且,按键不是中断还是在主程序中扫描,都是需要去抖动和识别按键的
不然的话,你这个
if(KEY按下)
   {
      按键处理相关代码;
    }
如果按键一直按着,程序就一直在执行
回复

使用道具 举报

15#
ID:205485 发表于 2025-5-16 13:48 | 只看该作者
Y_G_G 发表于 2025-5-15 16:23
对于按键中断,并不是绝对需要的,可以不用中断,直接在主程序中扫描按键就可以了
但有时候是要中断的,比如 ...

谢谢,学到了很多知识
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表