Kar*_*uru 39 embedded operating-system processor rtos interrupt
什么时候应该使用轮询方法什么时候应该使用基于中断的方法?是否存在可以使用两者的情况?
Ama*_*9MF 60
如果感兴趣的事件是:
那么基于中断的处理程序就有意义了.
如果感兴趣的事件是:
然后轮询可能更合适.
其他考虑因素包括您是为OS编写设备驱动程序还是仅编写没有线程支持的裸机代码.在裸机情况下,CPU通常只是在不忙时循环,所以它也可以轮询某些东西.
Pau*_*l R 15
应尽可能避免轮询,因为它通常会不必要地占用大量CPU周期(除非(a)您只是短时间轮询或(b)您可以在轮询循环中合理的时间内睡觉).浪费CPU周期不仅从性能角度来看很糟糕,而且还会增加功耗,这对于电池供电的嵌入式应用来说可能是一个问题.
在决定投票或中断时,您必须完全了解您尝试遵循的事件的性质以及您对事件的回应.
当没有任何事情发生时,中断不需要处理,但在发生事情时需要你全神贯注.如果事件是外部的并且具有噪声边缘或快速脉冲,那么这可能会导致严重的中断,您必须小心设置中断.
在这个例子中,中断程序响应已经变得清晰的激光束并且正在为它被阻挡的事件设置自己:
BEAM_INTR_EN = TRUE; /*re-enable the beam interrupts*/
/*Set the beam interrupt for the next clear to blocked event*/
BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/
Run Code Online (Sandbox Code Playgroud)
该代码有两个弱点:1)如果在中断标志清零之前激光束再次被阻挡(BEAM_INTR_FLAG = FALSE;).中断将被遗漏,代码将与激光束状态不同步.
2)在后台例程中设置中断或者优先级高于此代码的优先级时,在启用中断时必须小心.如果中断标志在启用之前已经设置(错误),则一旦启用中断例程就会被错误地调用,可能是错误的边缘.
修复1)的最简单方法是在设置中断后进行双重检查,如果已经发生,则强制中断.要修复2)在双重检查后将中断的启用移到:
/*Set the beam interrupt for the next clear to blocked event*/
BEAM_INTR_EDGE = CLEAR_TO_BLOCKED;
BEAM_INTR_FLAG = FALSE; /*Clear the interrupt*/
/*Double check beam state to see if it has already gone blocked*/
if (BEAM_STATE == BEAM_BLOCKED)
{
BEAM_INTR_FLAG = TRUE; /*Force the interrupt to re-enter the ISR after exiting*/
}
BEAM_INTR_EN = TRUE; /*re-enable the beam interrupts*/
Run Code Online (Sandbox Code Playgroud)
强制中断使系统使用相同的状态机,只需强制将其圆形覆盖盲点.
基本上:
Set the edge to detect the next interrupt event
Clear the interrupt flag
if (the event has already occurred)
{
Set the interrupt flag to force the interrupt
}
Enable the interrupt
Run Code Online (Sandbox Code Playgroud)
如果对事件的响应时间必须一致(例如在输入线变高后传输事件信号后1ms +/- 10us),那么中断通常是最好的.
如果对事件的响应时间必须在一定时间内(例如在输入线路的高1ms内变高,则发送事件信号),则中断最好.
中断的问题是你必须开始考虑线程,并且两段代码可以同时访问相同的数据.
中断也有利于允许处理器在等待某些事情发生时进入低功耗模式(睡眠/空闲等).
如果处理器只做一件事,说过所有轮询可以给事件提供非常紧凑的时间响应,通常中断硬件需要几个周期来响应事件,而紧密的轮询循环会这样做.
如果事件没有时间关键且可能有噪声(例如有人按下开关),则轮询允许简单过滤而不会错过长期转换.一个常见的错误是在设置时多次轮询:
void fnInitialiseSystem(void)
{
if (MODE_INPUT == MODE_A) /*First polling of the MODE_INPUT*/
{
PR2 = PR2_MODE_A;
}
else
{
PR2 = PR2_MODE_B;
}
OpenTimer2( TIMER_INT_ON &
T2_PS_1_1 &
T2_POST_1_8 );
if (MODE_INPUT == MODE_A) /*Second polling of the MODE_INPUT*/
{
CurrentMode = MODE_A;
PROBE_INT_EDGE = CLEAR_TO_BLOCKED;
}
else
{
CurrentMode = MODE_B;
PROBE_INT_EDGE = BLOCKED_TO_CLEAR;
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,MODE_INPUT是一个外部开关,如果轮询两次MODE_INPUT不同,则行为是意外的.在读取这些类型的信号时,最好使用过滤来决定输入的长期状态,并对过滤后的版本执行操作.
例如,使用交换机去抖动只需定期检查一个交换机(每1ms?),如果它们中的一些(比如16)与过滤版本(交换机打开)不同(交换机已关闭),则更新结果并执行所需的操作.小心信号混叠,振荡信号可能看起来稳定!
再次使用轮询和中断的一个例子是使用不经常改变的输入,但是当它输入时有噪声.再一次,开关就是一个很好的例子:代码可以设置一个中断来检查开关状态的变化,当发生中断时,可以定期轮询开关直到开关状态"稳定"(要么改变)陈述或回到原来的状态.这样可以在没有任何事情发生时降低处理开销,并在发生某些事情时进行噪声过滤.
有时你实际上需要同时使用它们.例如,如果事件是零星的,但是发生了高速爆发; 您可能需要先响应一个中断,然后再重新启用中断轮询,看看是否已经发生了另一个事件,避免了中断上下文切换的一些开销.我相信Linux网络接口在这种模式下运行.
| 归档时间: |
|
| 查看次数: |
44103 次 |
| 最近记录: |