基于轮询或中断的方法

时间:2010-06-18 20:23:43

标签: embedded operating-system interrupt processor rtos

什么时候应该使用轮询方法什么时候应该使用基于中断的方法? 有两种情况都可以使用吗?

14 个答案:

答案 0 :(得分:55)

如果感兴趣的事件是:

  1. 异步
  2. 紧急
  3. 不常
  4. 然后基于中断的处理程序才有意义。

    如果感兴趣的事件是:

    1. 同步(即您知道何时在一个小窗口内预期)
    2. 不紧急(即缓慢的轮询间隔没有不良影响)
    3. 频繁(即您的大多数投票周期创建'点击')
    4. 然后轮询可能更适合。

      其他考虑因素包括您是为OS编写设备驱动程序还是仅编写没有线程支持的裸机代码。在裸机情况下,CPU通常只是在不忙时循环,所以它也可以轮询一些东西。

答案 1 :(得分:15)

应尽可能避免轮询,因为它通常会不必要地占用大量CPU周期(除非(a)您只是短时间内轮询或(b)您可以在合理的时间内睡觉你的投票循环)。浪费CPU周期不仅从性能角度来看很糟糕,而且还会增加功耗,这对于电池供电的嵌入式应用来说可能是一个问题。

答案 2 :(得分:8)

在决定投票或中断时,您必须完全了解您尝试遵循的事件的性质以及您对事件的回应。

当发生任何事情时,中断不需要处理,但在发生任何事情时需要你全神贯注。如果事件是外部的并且具有噪声边沿或快速脉冲,那么这可能会导致严重的中断,您必须小心设置中断。

在这个例子中,中断程序正在响应一个已经变得清晰的激光束并且正在设置它被阻挡的事件:

   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*/

此代码有两个弱点: 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*/

强制中断使系统使用相同的状态机,只需强制将其圆形覆盖盲点。

基本上:

   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

如果对事件的响应时间必须一致(例如在输入线变高后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;
   }
}

在上面的示例中,MODE_INPUT是一个外部开关,如果轮询两次MODE_INPUT不同,则行为是意外的。在读取这些类型的信号时,最好使用过滤来决定输入的长期状态,并对过滤后的版本执行操作。

例如,如果使用开关去抖动,只需定期检查一个开关(每1ms?),如果它们(例如16个)的数量与过滤版本(开关打开)不同(开关关闭),则更新结果并执行需要采取的行动。注意信号混叠,振荡信号可能看起来稳定!

使用轮询和中断的一个例子是,使用一个不经常改变的输入,但是当它输入时会产生噪声。再一次,开关就是一个很好的例子:代码可以设置一个中断来检查开关状态的变化,当发生中断时,可以定期轮询开关直到开关状态“稳定”(要么改变)陈述或回到原来的状态。这样可以在没有任何事情发生时降低处理开销,并在发生某些事情时进行噪声过滤。

答案 3 :(得分:7)

有时你实际上需要同时使用它们。例如,如果事件是零星的,但是发生了高速爆发;您可能需要先响应一个中断,然后再重新启用中断轮询,看看是否已经发生了另一个事件,避免了中断上下文切换的一些开销。我相信Linux网络接口在这种模式下运行。

答案 4 :(得分:4)

答案 5 :(得分:3)

简短的回答是在轮询太慢时使用中断方法。 (太慢了,我的意思是如果轮询丢失数据,则需要中断方法)

答案 6 :(得分:3)

基本上,由于某些硬件或软件原因,在中断模式不可用的情况下使用轮询模式。因此,从功耗,性能等角度来看,中断模式更为可取(与Paul R一致)。轮询模式也可用于原型设计,无需外围设备的内核以及某些测试目的。

答案 7 :(得分:3)

当需要低延迟时,首选中断。如果你每秒N次轮询一些条件,那么平均你会在实际发生后的1 / N的一半时间内发现这个条件。

当需要绝对确定性时序时,轮询有时是首选。就其性质而言,中断可能在不可预测的时间发生,并且使时序分析变得非常复杂,而对于轮询系统,可以相对容易地对截止日期满意度做出可证明的陈述。

答案 8 :(得分:3)

始终使用中断。这样你永远不会丢失数据。在事件驱动或线程应用中,即使是最慢的信号也应该是中断驱动的。

您应该使用轮询的唯一时间是使用调度程序,并且硬件上的缓冲区足够深,以确保不会丢失数据。

答案 9 :(得分:3)

有许多设计约束可以推动决策。我的应用程序结合了中断和轮询:

  • 外部和内部时钟源触发中断 - 这是至关重要的 时间戳准确,所以我们可以同步它们。
  • 传入的串行消息触发中断。收到的FIFO必须在溢出之前进行维修。
  • 当FIFO部分为空时,传出消息会触发中断 - 必须在它下溢之前重新填充。
  • ISR在后台轮询的设置信号量。这有两个好处:
    • 处理传入事件所需的计算可能很长;如果它留在ISR中,它可能会延迟其他ISR超出其服务期限。
    • 可以对事件进行排序。例如,轮询循环可以确保计算X始终在ADC数据收集和传入消息解析之间发生,即使有时消息的到达时间比预期的要早。

答案 10 :(得分:2)

轮询模式在具有高频事件的系统中非常有用,其中与进入和退出中断处理程序相关的开销比简单轮询使用更多的CPU周期。例如,可以在IP路由器中使用轮询来最大化可用于数据包处理的CPU带宽。

答案 11 :(得分:0)

您不希望主机在繁忙的循环中等待很长时间,并且当频繁检查不常存在的数据时,轮询也会变得效率低下。因此,如果主机和设备都快,那么轮询是否相当快。

答案 12 :(得分:0)

Interrupt based design 相比,与polling based相比要好得多,因为基于轮询是有缺陷的,因为它希望在每次轮询时返回数据。现在,您可能会说我将解决这种情况,其中单个轮询已经给我一个错误,但为什么这会浪费所有CPU周期轮询某些东西,当它也可以返回错误?并且期望投票可能失败是实际的产品情景。

当单个民意调查中涉及许多功能层时,

Interrupt based designs会更有意义。对我来说这是一个常见的做法:你会再次询问(民意调查)你的朋友吗?每天他是否有你需要的信息,或者当你掌握我需要的信息时,你会告诉他interrupt我。我认为我们在日常生活中做正确的事但却没有意识到。

interrupt based architectures实施时需要充分了解publish-subscribe design principle。并且,当在应用程序域中完成时,它们需要部分代码发送中断才能写得非常好。这很好,因为它也将复杂性压缩到一个地方。

除上述内容外,以下是基于轮询的体系结构为您免费提供的其他优势:

  • - 异步
  • 适用于偶发事件/更新的情况
  • 仅在有可用数据的情况下更新
  • 更好的错误处理&管理
  • 更好地利用CPU周期
  • 更好的电池续航时间mgmt
  • 让听众摆脱
  • 下的复杂性

每当你设计sw&如果您有这个选择,则应始终选择基于interrupt的基于polling的设计,因为基于interrupt的设计可以使用侦听器填充基于polling的情况,但是轮询基于设计永远无法满足基于interrupt设计的要求。

以下是简短的比较矩阵:

                     -INTERRUPT-      -LOOP-
Speed                  fast            slow
Eficiency              good            poor
CPU waste              low             high
multitasking           yes             no
complexity             high            low
debugging              +/- easy        easy
critical in time       excellent       poor
code bloat             low impact      high impact

答案 13 :(得分:0)

看,我们有5种主要方法:

1)盲目

CPU每隔x ms检查一次数据。 ETC检查针脚12。

2)投票(忙/闲)

CPU始终在检查并等待标志升起,就像UART在传输数据包后升起标志一样。永远检查标志寄存器。 (最佳响应时间),但CPU无法执行其他任何操作。

3)中断:

CPU正常运行,如果发生中断,CPU会将上下文切换到ISR。如果引脚18看到下降沿,则执行ISR(1)。 ISR未激活时,响应时间还不错,CPU可以执行任何操作。使用您不知道何时会发生的紧急应用来执行此操作。

4)定期轮询:

CPU正在执行其任务,但是每隔ms秒执行一次其检查引脚11。如果您不信任硬件会引发中断,则响应时间会更短,而不是紧急应用程序,请执行此操作。可以使用计时器中断来创建它。

5)直接访问内存。

高级接口方法。直接从内存传输数据到内存。 输入将直接读入存储器。 输出将直接从存储器写入。 两者都使用控制器。