打印
[STM32F1]

关于stm32中断里面嵌套中断的遇到的奇葩现象(原因从12楼看

[复制链接]
10091|32
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 摩天轮1111 于 2015-8-10 12:07 编辑

又遇到一个奇葩的事情,我有两个中断,一个EXTI1一个systick,我再EXTI1的中断服务函数里面采用了delay,然后delay里面又使用了systick的中断服务函数,然后我设置了systick的主优先级0,从也是0,而EXTI1的主1,从1,照理说,这里在执行EXTI的中断函数时候,进入delay之后delay会使能systick开始计数,然后一直while(flag)等待(flag默认1),直到systick中断发生了,进入该中断函数,会使得flag变成1,然后出中断,然后while就出去了,然后delay就出去了,然后接着执行EXTI1里面的下面的句子,但是为什么实际情况是进不去systick的中断服务函数,程序就停在while(flag)上面,flag这里是main.c的全局变量,中断服务函数全部写在main.c里面的



源码附上 13 外部触发 PA1 中断实现 USART3重映射打印(FLASH版本).rar (306.54 KB) 呢?


沙发
airwill| | 2015-8-6 22:02 | 只看该作者
首先, 从编程习惯上讲, 中断服务函数应该尽量快地结束任务, 而不应该搞 while 等待循环.
不过从楼主的思路上看, 这个情况应该是能够实现的. 是不是 printf() 导致的问题, 执行这个函数太费时, 在中断中尽量避免调用哦

使用特权

评论回复
板凳
摩天轮1111|  楼主 | 2015-8-6 22:03 | 只看该作者
还没有人回复呢,我自己找到原因了,首先看到内核手册里面有段话,关于中断服务函数的优先级寄存器SHPRx,设置的中断优先级只是操作的NVIC->IPx寄存器,尼玛,这意思就是中断优先级是中断优先级,中断服务函数是中断服务函数,他也有优先级,中断发生了,不一定立马就发生中断服务函数,就是这么简单,我原来的程序里面的delay出去是用的while(flag),而flag要用systick的中断服务函数执行,虽然我调的systick的中断优先级很高,但是其服务函数优先级不高,意思是我EXTI1服务函数执行的时候,里面发生了delay,然后delay启动了systick,然后delay一直干等着,然后这时候systick的中断发生了,这个中断发生了会打断现在EXTI1里面的程序,也就是while(flag)的死循环,打断完之后,也就让systick->ctrl 的COUNT FLAG变成1,然后就又返回执行while了,因为systick的中断服务函数优先级并没有跟着中断一起调,我看的视频教程什么的,都只有讲中断优先级的设定,好像没有讲中断服务函数的优先级设定,那么也就是有时候我们只需用中断,用其标志位,那正常的逻辑理解肯定没问题了,中断发生了,我要的操作就实现了,但是如果是中断服务函数来执行的这个操作,那就不一定是这样的了,而且我感觉一般我们要用到中断嵌套的话,在中断里面出现的中断,这个中断要操作的事情肯定不是其标志位变化一下那么简单,肯定要操作对应的中断服务函数才行的,所以也就是我们在NVIC 配置的时候,不但要配置中断优先级,还要配置对应的中断服务函数优先级才行,怎么配置中断服务函数优先级我还没看,以后再说吧感觉暂时自己用不着,看了不用还是会忘,以后要用再查,然后就是知道这么个注意事项就好了,下次自己用的时候,就会意识到这个问题,不会发生现实和预期不相符的情况
实验结果可以看到,执行完了EXTI1中断服务函数之后,接着执行了systick的中断服务函数,因为我delay里面用中断标志位来控制的退出while,所以没有操作systick的中断服务函数,而之前的那种通过操作systick的中断服务函数来置flag为0退出while会由于systick的中断服务函数一直没法执行而实现不了(因为一直在执行EXTI1的中断服务函数)
然后改用标志位之后呢,delay正常执行了,肯定是执行完了EXTI1的中断服务函数之后,才接着执行之前的那个systick的中断服务函数,因为我再systick中断服务函数里面也加了打印,为了便于查看程序的运行过程,可以发现执行完EXTI1之后是输出you have already pushed the botton之后,有时候出一组时间值,有时候出两组时间值,出两组的说明EXTI1中断发生了两次,这是插拔插针的抖动导致的,EXTI1里面的延时是为了消除抖动,出两组时间值,说明消抖动目的达到了。


使用特权

评论回复
地板
摩天轮1111|  楼主 | 2015-8-6 22:08 | 只看该作者
airwill 发表于 2015-8-6 22:02
首先, 从编程习惯上讲, 中断服务函数应该尽量快地结束任务, 而不应该搞 while 等待循环.
不过从楼主的思路 ...

谢谢提醒,问题我已经找到也总结了,下面 的帖子,我这个不是做什么工程,就是学习stm32,练一些外设什么的,这也是我想到的最简单的中断嵌套的实现思路,所以就这么弄了,“中断里面尽量不要用延时等待,中断里面都是很快速就过去”,这个问题,我看的那个刘凯的视频上面也这么讲的,不清楚他说这个话的起因是用延时,用等待这么做容易出现bug还是别的原因,不过看他的意思是说有时候会出现意想不到的问题,但是我现在感觉准确点的说,应该不叫中断里面要快,应该是中断服务函数里面要快,但是我现在又感觉,中断服务函数的优先级也设置好了之后的话,里面管它有没有延时,什么的,等多久,都应该不会出现bug了,或者另外角度上说这样的编程思路不好

使用特权

评论回复
5
airwill| | 2015-8-6 22:15 | 只看该作者
是的, 这样的编程思路不好.
中断服务函数里面要快,这是为了避免占用太多时间, 影响其它中断的及时响应

使用特权

评论回复
6
摩天轮1111|  楼主 | 2015-8-6 22:28 | 只看该作者
本帖最后由 摩天轮1111 于 2015-8-7 14:23 编辑
airwill 发表于 2015-8-6 22:15
是的, 这样的编程思路不好.
中断服务函数里面要快,这是为了避免占用太多时间, 影响其它中断的及时响应 ...

你看,看主要思路,
其他的中断的及时响应,和我中断服务函数里面耽误不耽误时间没关系,该及时响应还是会及时响应的,只是响应了之后,他不一定操作对应的中断服务函数,这个要看中断服务函数的优先级,
两个要领,
1 ,中断优先级管的是中断发生的优先级,不管中断服务函数,
2.中断服务函数也有优先级可以设置,这个就能管中断服务函数了
  ps一句(不要上来看到中断里面用延时的就大谈延时在中断里面不好云云的,谁都知道这点,讲课的讲教程的老师都会这么说吧,不过实话说,估计他也没说出个所以然,只是有时候这么用错了,有时对了,所以不建议用,但这不是本问题的关键,我这里的问题关键是我描述的这个现象产生的原因,是有原因的,不要跑偏了,,,)
这里的解释有问题,不正确,正确的解释看我最后下面的回复

使用特权

评论回复
7
airwill| | 2015-8-6 22:32 | 只看该作者
嗯, 我看明白了, 因为你自己找到了问题, 就不进一步深入了.

使用特权

评论回复
8
摩天轮1111|  楼主 | 2015-8-6 22:38 | 只看该作者
airwill 发表于 2015-8-6 22:32
嗯, 我看明白了, 因为你自己找到了问题, 就不进一步深入了.

哎,真的是看明白了吗,我写这个程序,就是为了简单实验中断嵌套这个现象的,其中发现了这么个问题,我设置了systick是高优先级,反而在执行低优先级的中断时候,高优先级的中断发生了,还执行不了?不岂不是很诡异?这是我的问题,我探究了里面发生的问题,找到了这个现象产生的原因。
我不深究了?还有什么要深究的?请问还要深究什么?中断里面不该用延时?我天,,,,

使用特权

评论回复
9
摩天轮1111|  楼主 | 2015-8-6 22:59 | 只看该作者

这次真的是吊炸天了,呵呵,我这次EXTI1的中断服务函数里面的delay用的是systick的标志位来做的 ,然后我把systick的中断优先级全降下来了,比EXTI1低,然后呢,我发现在执行EXTI1的中断服务函数时候,如果systick发生了中断,它也执行了,标志位置1了,那意思是说执行EXTI1的中断服务函数的时候,要发生了systick中断,它就发生了?优先级低的systick啊,
实际上这里标志位置1是systick的特性,手册上systick部分说的是标志位置1,同时发生中断,那么这里到底发生了systick中断呢,还是没发生呢?谁有更好的检验办法?(ps不要付上那个中文说明,说明也是别人理解的,可能有不严谨地方,不然stm32干嘛还要搞个中断服务函数优先级设置?)

使用特权

评论回复
10
松哥无敌| | 2015-8-6 23:27 | 只看该作者
摩天轮1111 发表于 2015-8-6 22:59
这次真的是吊炸天了,呵呵,我这次EXTI1的中断服务函数里面的delay用的是systick的标志位来做的 ,然后我 ...

我觉得你有点蛇精病了

使用特权

评论回复
11
摩天轮1111|  楼主 | 2015-8-6 23:31 | 只看该作者
刚刚看了那个中断处理函数优先级寄存器,好像还不是我上面大概说的那些个样子呢,因为这个中断处理函数优先级寄存器也就三个,只是设置系统的6个特别的中断,不管其他的中断,所以应该可以看,中断优先级寄存器设置的,也就是NVIC->IPx这个寄存器,一共有有21个,他们是用来设置普遍的的中断的,也就是除了那个6个特别的系统中断之外,其他的外部中断(内核级别之外的)都是按照上面的那个中文的方式来运作的,简单点说就是可以把中断服务函数的执行和中断的发生绑在一起,认为是一块的,一体的,也就是主优先级高的,中断发生了在执行中断函数过程中,比他主优先级低的,一样高的,中断将发生,但是处理函数会被挂起来,不处理,等这个完事了再处理,而低主优先级的中断处理函数在执行的话,一个高主优先级的中断发生了,会立即执行它对应的中断服务函数,执行完了中断服务函数,再接着执行之前的那个中断服务函数,而从优先级是给好几个一样主优先级一样的中断同时发生这种事情准备的,
另外就是systick是属于那个特别的6个内核中断之一,它的情况比较特别了,,

使用特权

评论回复
12
摩天轮1111|  楼主 | 2015-8-6 23:37 | 只看该作者
再更正一下我想原因应该是
1.Systick属于内核中断,“handled by system handlers”,优先级由Systemhandler priority registers (SHPRx)来设置;(摘自cortex-M3内核编程手册)
2.timer、串口等属于外设中断,“handled by ISRs(Interrupt ServiceRoutines(ISRs))”优先级由Interruptpriority registers (NVIC_IPRx)来设置
所以我设置systick的优先级的方式并不对,应该,我那个函数是设置不了它?

使用特权

评论回复
13
摩天轮1111|  楼主 | 2015-8-7 00:33 | 只看该作者
最后给个总结

这里就有设置优先级的一个函数


如上图,其实priority就是0-15的数,转成二进制就是0000-1111,然后自己看这怎么拆分,是拆1bit3bit还是2bit2bit随意,反正这个priority数越小就优先级越高,下面看看实验,我直接把(1<<__NVIC_PRIO_BITS-1换成数了,这里__NVIC_PRIO_BITS可以查一下,定义的是4,这个一算就是15,也就是1111,不论怎么分组,优先级都是最低的了,所以要改,我改了0立马就好用了(delay里面的whileflag)等待采用了systick的中断服务函数处理flag0),改了别的数,比如9就不好使了,因为我EXTI1设置都是主2,从1,也就是1001,这就是9,所以9肯定不好使了,比9大肯定没门,但是8是不是就可以了呢?也不可以,因为81000,高二位和9的高二位一样,所以也进不去systick的中断服务函数如下图
上两图,因为EXTI1的优先级和systick一样,故不行,但是改成8也不行,然后7往下都行了,这个9变成1001,   81000,    70111,参见我的本篇的https://bbs.21ic.com/icview-1037576-1-1.html,至此应该是一个合乎逻辑完整的结论的出来了,应该是正确的结论,


使用特权

评论回复
14
摩天轮1111|  楼主 | 2015-8-7 00:35 | 只看该作者
松哥无敌 发表于 2015-8-6 23:27
我觉得你有点蛇精病了

呵呵,是因为之前的那种逻辑的理解还是有对实验现象有解释不通的地方,这下好了,最后的这个结论什么地方都解释通了,供借鉴

使用特权

评论回复
15
Dick00| | 2015-8-7 10:11 | 只看该作者
学习了,Systick是内部中断,默认是最低的,所以LZ一开始会出现嵌套不了的状况,所以要用NVIC_SetPriority()函数去设置其优先级,当其优先级高于EXIT中断优先级时就可以嵌套了,是这个意思不?

使用特权

评论回复
16
zhixin15| | 2015-8-7 10:56 | 只看该作者
stm32解密,加密技术交流,QQ:2424720092.15313166207.李明阳。

使用特权

评论回复
17
lzhyqq| | 2015-8-7 14:07 | 只看该作者
本帖最后由 lzhyqq 于 2015-8-7 14:19 编辑
Dick00 发表于 2015-8-7 10:11
学习了,Systick是内部中断,默认是最低的,所以LZ一开始会出现嵌套不了的状况,所以要用NVIC_SetPriority ...

应该是这样的。

使用特权

评论回复
18
摩天轮1111|  楼主 | 2015-8-7 14:17 | 只看该作者
Dick00 发表于 2015-8-7 10:11
学习了,Systick是内部中断,默认是最低的,所以LZ一开始会出现嵌套不了的状况,所以要用NVIC_SetPriority ...

是的,就是你这个意思,设置systick的优先级不是使用和设置外设中断优先级一样的办法,应为他是系统的东西,有他的设置办法,就是你说的这个函数去设置,但是设置外设的那个中断优先级用的函数里面填那个外设名称的部分,库函数它没有列表,所以也许有时候会犯错,也用他来设置系统部分的中断了,我就不知道这里面哪来的一堆人瞎嚷嚷那个中断嵌套里面不该用延时这个问题,真不懂这些人脑子里想啥,都跑偏了我发这个帖子的初衷了,尽给无关痛痒的东西揪着说,就好像我不知道中断里面用延时不好一样,看到这样的人真烦,我再说中断的设置的问题,他在说延时,就好像我出的这个现象的问题就是因为我用了延时的原因,真不明白这些人怎么学习的

使用特权

评论回复
19
摩天轮1111|  楼主 | 2015-8-7 14:20 | 只看该作者
lzhyqq 发表于 2015-8-7 14:07
不是,实际是他关于中断优先级按着两级抢占式分配的,那抢占式优先级只有0和1,2和1的抢占优先级是一样的 ...

不是你理解的这样的,systick的默认是1111,也就是15,不论怎么分组,他都是最低的优先级,不同的外设中断,不论哪个寄存器高四位怎么设置的,只要一分组,你改了分组,前面设置过的那个中断优先级的那个寄存器的高四位不变,但是按照分组重新来算优先级,见我这篇帖子https://bbs.21ic.com/icview-1037576-1-1.html

使用特权

评论回复
20
sjnh| | 2015-8-7 14:31 | 只看该作者
不是你找到了问题,使用了其它方**好避免了
中断里用:while(flag),flag要用volatile定义

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

38

主题

224

帖子

15

粉丝