[讨论]关于单片机如何在处理多个中断保持实时性

时间:2022-02-24 19:47:18
问题:当51单片机系统中,中断嵌套只有两层,高低优先级之分。如果我们有一个5ms的中断(来自外部的定时),还有串口,SPI等等
当中断数目有两个以上的时候(包括两个) 单片机处理多个中断肯定存在不实时,也许会漏去5ms速度很快的中断(单片机处理低优先级的中断时候,恰好来了5ms的中断)

所以向大家请教一下 如果规划或安排一个单片机的程序设计结构 以及中断服务程序的编写(要求)

欢迎大家讨论!

16 个解决方案

#1


尽量减少中断内部执行的语句,最好只有1、2条语句,然后赶紧出中断。这是确保中断实时的软件处理方法。
比如,串口中断中,只将FIFO中的数据取出,放到一个统一的buffer,然后立即出中断,这样其实只有一条实际操作语句。至于如何处理buffer的数据,可以在定时器或者在最后的while(1)中处理。
SPI中断也一样。

#2


楼上说的好

但是有些关键场合,必须关闭中断,执行完才能开,否则时序被打乱,得不到正确的结果的。

#3


1楼: 将buffer中的数据放到定时器里?什么意思

其实就是有些时候必须要在来临中断的时候做些SPI或者串口操作怎么办呢?难道就得在ISR中写这么多程序?

#4


1楼说的好,尽量减少ISR程序的长度。只是保证实时性的关键。
不要在中断服务程序中处理数据。在中断服务程序中只进行关键性的操作。

#5


只能说尽量不要在中断里面处理实时性不强的数据,但是像通讯数据,无线模块接收的数据就没办法回避了

#6


继续请教 

如果我要在INT来临后 固定做一些操作 如存储数据 且判断;使用SPI操作等等

自然会想到在INT外面做 但是INT结束后又会返回现场 现场所做的操作又是时间不确定的 那么应该放到什么地方呢?

我不知道怎么处理 只好写在ISR中了
 
 

#7


引用 3 楼 dengyixinos 的回复:
1楼: 将buffer中的数据放到定时器里?什么意思 

其实就是有些时候必须要在来临中断的时候做些SPI或者串口操作怎么办呢?难道就得在ISR中写这么多程序?

不是说将buffer中的数据放到定时器里,而是说,在中断里面取了数据放到buffer中,不立即处理,直接退出中断。在定时器里每隔一个时间段(比如1ms)就处理一次buffer的数据(buffer肯定是全局的数组)。有点类似操作系统的“时间片”一样。

#8


你说的很有道理 很像我们版上的那篇文章“中断驱动多任务” 虽然损失了些程序效率 但是思路很不错!

其实当返回现场的时候 中断要做的后续工作也需要速度快 否则连续来了两个中断前后的数据就冲突了

有三个问题向大家请教: 

1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了

3. 由于外部事件的处理不能漏去任何一个中断(UART和SPI) 所以请问下如果三个中断中的任何两个在同一个延上同时触发(UART 和SPI UART和定时器) 单片机实际中是否会漏收掉中断吗?(UART和定时器 可能会因为优先级而排序  那UART
和SPI同优先级 当然会按照硬件中断的顺序来执行 那么单片机处理完UART后还会相应SPI的吗?)

小弟用多个中断的经验不是很足 希望大家指导指导

谢谢 

 

#9


引用 6 楼 dengyixinos 的回复:
继续请教 

如果我要在INT来临后 固定做一些操作 如存储数据 且判断;使用SPI操作等等 

自然会想到在INT外面做 但是INT结束后又会返回现场 现场所做的操作又是时间不确定的 那么应该放到什么地方呢? 

我不知道怎么处理 只好写在ISR中了 

以SPI读数据为例:
main里面一般有个while(1),你所希望的对从SPI读到的数据的操作(运算呀,存储呀等等随便)都放到这个while里面,设个变量,以0和1表示是否开始,或者以0,1,2....表示进行到第几步了(比如希望读10个字节,那8就表示读到第8个了)。

在中断里,读到数据,就取出数据放到buffer,然后将对应的标志位设置一下,就退出中断。

在进中断前,系统都是在while(1)里面,所以,出来后,还是在这里面循环,最多循环一次就能对刚才的数据进行处理。

最差的情况是:刚做完n次的数据处理,就又发生了SPI中断,取到了数据,退出中断,返回while,继续原来的循环。要将后续的语句全执行完,才能再次进行数据处理,这次是n+1了。也就是说,数据处理有延时,这个需要评估。

#10


引用 9 楼 shuiyan 的回复:
引用 6 楼 dengyixinos 的回复:
继续请教 

如果我要在INT来临后 固定做一些操作 如存储数据 且判断;使用SPI操作等等 

自然会想到在INT外面做 但是INT结束后又会返回现场 现场所做的操作又是时间不确定的 那么应该放到什么地方呢? 

我不知道怎么处理 只好写在ISR中了 
 
以SPI读数据为例: 
main里面一般有个while(1),你所希望的对从SPI读到的数据的操作(运算呀,存储呀等等随便)都放到这个while里面,设个变量…


这种状态机的设计模式确实不错 需要评估好收到几个字节开始处理

但是对于其他中断UART EX_INT 主程序中都在这查询语句是否会对程序的效率有影响?
(呵呵SPI的数据还需要编码 虽然是查表 但是影响时间)

谢谢shuiyan

请你看看我8楼的帖 呵呵……

#11


1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

-->定时器优先级放低,确保不会丢掉任何中断。


2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了

-->事实上,定时器tick应该尽量快,这样才能尽量减少两次事件处理间的间隔,也就等于提升了非中断事件的执行效率了。



3. 由于外部事件的处理不能漏去任何一个中断(UART和SPI) 所以请问下如果三个中断中的任何两个在同一个延上同时触发(UART 和SPI UART和定时器) 单片机实际中是否会漏收掉中断吗?(UART和定时器 可能会因为优先级而排序  那UART 
和SPI同优先级 当然会按照硬件中断的顺序来执行 那么单片机处理完UART后还会相应SPI的吗?) 

-->只要程序中enable了相应的中断,那么就一定能响应。同样等级下,完成前一个中断退出后,就会自动再次响应后一个中断。不会丢。

#12


引用 11 楼 shuiyan 的回复:
1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

-->定时器优先级放低,确保不会丢掉任何中断。 


2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了 

-->事实上,定时器tick应该尽量快,这样才能尽量减少两次事件…


ls 非常感谢你!

定时器查询事件的标志位 分别进行任务的响应 主程序对中断进行状态机的响应  我没有说错吧?

不过 单片机进行任务响应的时候 定时器还是做1ms的中断吗?是否动态改变时间?

我的理解是
1. 定时器还是做1ms的中断 使得其他任务能够实时响应

2. 我认为动态改变为一个固定的时间的好处 可以让此任务快速完成(反复地出入栈 比较占用CPU时间) 这个得需要按实际情况变化

谢谢shuiyan!

#13


小伙子:

还得技术钻研的这么认真!好。

处理中断的问题是嵌入式系统中必须解决好的问题。

当你在单片机中运行一个操作系统时(比如ucosII),你上文中提到的1ms的定时器中断实际充当了

系统调度的脉搏(Tick),正是这个脉搏提醒操作系统应该给予时间片给当前最高优先级的进程。

如果你的定时器中断(System Tick)的优先级设为一个较低级别,这无非是将整个系统至于死地,因为系统

失去了一个保证实时性的根本动力。这就是我们常说的“使得系统的调度时间不可预见”。

所以,Tick的中断优先级非常高。

那么,你可能需要响应一些慢速的外部设备,就拿串口来说。当收到一个字符的数据时,它可能立刻给CPU发出

一个 COM_RECEIVE 的中断,如果这个中断的优先级最高,那么系统将响应这个中断。

中断响应时间是嵌入式系统中最为关键的概念,他决定了系统实时性的好坏。我们作为上层的程序员,在写中断响应

程序的时候可以把握一个通用的原则:

中断来-》中断响应程序保存必要的数据-》开中断-》系统调度-》处理中断服务程序。

dengyixinos的疑问是,如果在中断响应程序中,定时器中断来了怎么办?

其实在系统中,我们有一个中断悬挂寄存器,在中断响应程序预存完必要的数据后,开中断时,立刻检查其中断悬挂寄存器,

这个时候,定时器中断可以得到相应了!

但是我们这样设计的代价是定时器变得不稳定了,恩,没错,但是保证了实时性。

我们学习嵌入式目的,并不是一味的遵循什么统一个处理方法,在遇见不同情况时,一定要特殊处理,因为嵌入式系统本来

就是面向具体应用的。

你完全可以把你的系统设置成中断驱动的!那就全靠项目的对你的某一任务的实时性要求来决定了。






#14



补充一下:

中断响应程序(ISR)可以理解为预处理中断,它干的第一件事情就是清中断,至于是不是

关中断-》ISR-》开中断,就看你的具体设备应用了。

中断处理程序(IST)可以理解为真正处理中断数据,他一般实现为一个线程(windows CE 下)或

任务(VxWorks or Ucos/II 下),属于逻辑上的用户态的东西。

当然如果你觉得你中断处理很简单,只需要在ISR中处理完就行了。不过尽量不要这么做,就是为了满足

该死的可预见的中断响应时间! 

#15


学习l

#16


引用 12 楼 dengyixinos 的回复:
引用 11 楼 shuiyan 的回复:
1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

-->定时器优先级放低,确保不会丢掉任何中断。 


2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了 

-->事实上,定时器tick应该尽量…

定时器是否设为1ms,是需要根据具体项目的运行情况来调整的。经过大量测试没有丢数据、丢中断、响应延迟、处理延迟的情况,那么这个Tick其实是尽量大一点好,毕竟cpu进定时器中断也是有消耗的,即使判断了一圈不需要做某些处理,这些判断还是要耗指令时间的。

以前做的项目从来没有在这样的需求下动态改变定时器时间的,如果没有找出明确的需求点,最好不要来回改动。当然这只是感觉,毕竟很久没做了,没法立即给出什么理由。欢迎讨论。

#1


尽量减少中断内部执行的语句,最好只有1、2条语句,然后赶紧出中断。这是确保中断实时的软件处理方法。
比如,串口中断中,只将FIFO中的数据取出,放到一个统一的buffer,然后立即出中断,这样其实只有一条实际操作语句。至于如何处理buffer的数据,可以在定时器或者在最后的while(1)中处理。
SPI中断也一样。

#2


楼上说的好

但是有些关键场合,必须关闭中断,执行完才能开,否则时序被打乱,得不到正确的结果的。

#3


1楼: 将buffer中的数据放到定时器里?什么意思

其实就是有些时候必须要在来临中断的时候做些SPI或者串口操作怎么办呢?难道就得在ISR中写这么多程序?

#4


1楼说的好,尽量减少ISR程序的长度。只是保证实时性的关键。
不要在中断服务程序中处理数据。在中断服务程序中只进行关键性的操作。

#5


只能说尽量不要在中断里面处理实时性不强的数据,但是像通讯数据,无线模块接收的数据就没办法回避了

#6


继续请教 

如果我要在INT来临后 固定做一些操作 如存储数据 且判断;使用SPI操作等等

自然会想到在INT外面做 但是INT结束后又会返回现场 现场所做的操作又是时间不确定的 那么应该放到什么地方呢?

我不知道怎么处理 只好写在ISR中了
 
 

#7


引用 3 楼 dengyixinos 的回复:
1楼: 将buffer中的数据放到定时器里?什么意思 

其实就是有些时候必须要在来临中断的时候做些SPI或者串口操作怎么办呢?难道就得在ISR中写这么多程序?

不是说将buffer中的数据放到定时器里,而是说,在中断里面取了数据放到buffer中,不立即处理,直接退出中断。在定时器里每隔一个时间段(比如1ms)就处理一次buffer的数据(buffer肯定是全局的数组)。有点类似操作系统的“时间片”一样。

#8


你说的很有道理 很像我们版上的那篇文章“中断驱动多任务” 虽然损失了些程序效率 但是思路很不错!

其实当返回现场的时候 中断要做的后续工作也需要速度快 否则连续来了两个中断前后的数据就冲突了

有三个问题向大家请教: 

1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了

3. 由于外部事件的处理不能漏去任何一个中断(UART和SPI) 所以请问下如果三个中断中的任何两个在同一个延上同时触发(UART 和SPI UART和定时器) 单片机实际中是否会漏收掉中断吗?(UART和定时器 可能会因为优先级而排序  那UART
和SPI同优先级 当然会按照硬件中断的顺序来执行 那么单片机处理完UART后还会相应SPI的吗?)

小弟用多个中断的经验不是很足 希望大家指导指导

谢谢 

 

#9


引用 6 楼 dengyixinos 的回复:
继续请教 

如果我要在INT来临后 固定做一些操作 如存储数据 且判断;使用SPI操作等等 

自然会想到在INT外面做 但是INT结束后又会返回现场 现场所做的操作又是时间不确定的 那么应该放到什么地方呢? 

我不知道怎么处理 只好写在ISR中了 

以SPI读数据为例:
main里面一般有个while(1),你所希望的对从SPI读到的数据的操作(运算呀,存储呀等等随便)都放到这个while里面,设个变量,以0和1表示是否开始,或者以0,1,2....表示进行到第几步了(比如希望读10个字节,那8就表示读到第8个了)。

在中断里,读到数据,就取出数据放到buffer,然后将对应的标志位设置一下,就退出中断。

在进中断前,系统都是在while(1)里面,所以,出来后,还是在这里面循环,最多循环一次就能对刚才的数据进行处理。

最差的情况是:刚做完n次的数据处理,就又发生了SPI中断,取到了数据,退出中断,返回while,继续原来的循环。要将后续的语句全执行完,才能再次进行数据处理,这次是n+1了。也就是说,数据处理有延时,这个需要评估。

#10


引用 9 楼 shuiyan 的回复:
引用 6 楼 dengyixinos 的回复:
继续请教 

如果我要在INT来临后 固定做一些操作 如存储数据 且判断;使用SPI操作等等 

自然会想到在INT外面做 但是INT结束后又会返回现场 现场所做的操作又是时间不确定的 那么应该放到什么地方呢? 

我不知道怎么处理 只好写在ISR中了 
 
以SPI读数据为例: 
main里面一般有个while(1),你所希望的对从SPI读到的数据的操作(运算呀,存储呀等等随便)都放到这个while里面,设个变量…


这种状态机的设计模式确实不错 需要评估好收到几个字节开始处理

但是对于其他中断UART EX_INT 主程序中都在这查询语句是否会对程序的效率有影响?
(呵呵SPI的数据还需要编码 虽然是查表 但是影响时间)

谢谢shuiyan

请你看看我8楼的帖 呵呵……

#11


1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

-->定时器优先级放低,确保不会丢掉任何中断。


2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了

-->事实上,定时器tick应该尽量快,这样才能尽量减少两次事件处理间的间隔,也就等于提升了非中断事件的执行效率了。



3. 由于外部事件的处理不能漏去任何一个中断(UART和SPI) 所以请问下如果三个中断中的任何两个在同一个延上同时触发(UART 和SPI UART和定时器) 单片机实际中是否会漏收掉中断吗?(UART和定时器 可能会因为优先级而排序  那UART 
和SPI同优先级 当然会按照硬件中断的顺序来执行 那么单片机处理完UART后还会相应SPI的吗?) 

-->只要程序中enable了相应的中断,那么就一定能响应。同样等级下,完成前一个中断退出后,就会自动再次响应后一个中断。不会丢。

#12


引用 11 楼 shuiyan 的回复:
1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

-->定时器优先级放低,确保不会丢掉任何中断。 


2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了 

-->事实上,定时器tick应该尽量快,这样才能尽量减少两次事件…


ls 非常感谢你!

定时器查询事件的标志位 分别进行任务的响应 主程序对中断进行状态机的响应  我没有说错吧?

不过 单片机进行任务响应的时候 定时器还是做1ms的中断吗?是否动态改变时间?

我的理解是
1. 定时器还是做1ms的中断 使得其他任务能够实时响应

2. 我认为动态改变为一个固定的时间的好处 可以让此任务快速完成(反复地出入栈 比较占用CPU时间) 这个得需要按实际情况变化

谢谢shuiyan!

#13


小伙子:

还得技术钻研的这么认真!好。

处理中断的问题是嵌入式系统中必须解决好的问题。

当你在单片机中运行一个操作系统时(比如ucosII),你上文中提到的1ms的定时器中断实际充当了

系统调度的脉搏(Tick),正是这个脉搏提醒操作系统应该给予时间片给当前最高优先级的进程。

如果你的定时器中断(System Tick)的优先级设为一个较低级别,这无非是将整个系统至于死地,因为系统

失去了一个保证实时性的根本动力。这就是我们常说的“使得系统的调度时间不可预见”。

所以,Tick的中断优先级非常高。

那么,你可能需要响应一些慢速的外部设备,就拿串口来说。当收到一个字符的数据时,它可能立刻给CPU发出

一个 COM_RECEIVE 的中断,如果这个中断的优先级最高,那么系统将响应这个中断。

中断响应时间是嵌入式系统中最为关键的概念,他决定了系统实时性的好坏。我们作为上层的程序员,在写中断响应

程序的时候可以把握一个通用的原则:

中断来-》中断响应程序保存必要的数据-》开中断-》系统调度-》处理中断服务程序。

dengyixinos的疑问是,如果在中断响应程序中,定时器中断来了怎么办?

其实在系统中,我们有一个中断悬挂寄存器,在中断响应程序预存完必要的数据后,开中断时,立刻检查其中断悬挂寄存器,

这个时候,定时器中断可以得到相应了!

但是我们这样设计的代价是定时器变得不稳定了,恩,没错,但是保证了实时性。

我们学习嵌入式目的,并不是一味的遵循什么统一个处理方法,在遇见不同情况时,一定要特殊处理,因为嵌入式系统本来

就是面向具体应用的。

你完全可以把你的系统设置成中断驱动的!那就全靠项目的对你的某一任务的实时性要求来决定了。






#14



补充一下:

中断响应程序(ISR)可以理解为预处理中断,它干的第一件事情就是清中断,至于是不是

关中断-》ISR-》开中断,就看你的具体设备应用了。

中断处理程序(IST)可以理解为真正处理中断数据,他一般实现为一个线程(windows CE 下)或

任务(VxWorks or Ucos/II 下),属于逻辑上的用户态的东西。

当然如果你觉得你中断处理很简单,只需要在ISR中处理完就行了。不过尽量不要这么做,就是为了满足

该死的可预见的中断响应时间! 

#15


学习l

#16


引用 12 楼 dengyixinos 的回复:
引用 11 楼 shuiyan 的回复:
1. 如果使用1ms的定时器中断来依次查询事件 那么定时器中断的优先级应该高还是低?(我认为应该低,让其他所有的中断级别都为高 这样如果两个中断同时发生时不会影响到外部事件的触发) 

-->定时器优先级放低,确保不会丢掉任何中断。 


2. 如果查询到某些任务需要去完成 我想应该停止定时器中断 不能完全按照时间片去完成 所以我觉得定时器的tick不能太快了 

-->事实上,定时器tick应该尽量…

定时器是否设为1ms,是需要根据具体项目的运行情况来调整的。经过大量测试没有丢数据、丢中断、响应延迟、处理延迟的情况,那么这个Tick其实是尽量大一点好,毕竟cpu进定时器中断也是有消耗的,即使判断了一圈不需要做某些处理,这些判断还是要耗指令时间的。

以前做的项目从来没有在这样的需求下动态改变定时器时间的,如果没有找出明确的需求点,最好不要来回改动。当然这只是感觉,毕竟很久没做了,没法立即给出什么理由。欢迎讨论。