中断是否会中断Arduino上的其他中断?

时间:2011-02-24 22:34:33

标签: embedded microcontroller arduino interrupt interrupt-handling

我有一个Arduino Uno(很棒的小设备!)。它有两个中断;我们称之为 0 1 。我使用attachInterrupt() http://www.arduino.cc/en/Reference/AttachInterrupt附加一个处理程序来中断0和另一个处理程序来中断1。

中断 0 被触发并调用其处理程序,它执行一些数字处理。如果在触发中断 1 时中断 0 的处理程序仍在执行,会发生什么?

中断 1 中断中断 0 ,或者中断 1 等到中断 0 的处理程序是完成执行?

请注意,这个问题与Arduino有关。

3 个答案:

答案 0 :(得分:25)

在Arduino(aka AVR)硬件上,除非您有意创建条件以允许嵌套中断发生,否则不会发生嵌套中断。

来自avr-lib:

  

AVR硬件在进入中断向量之前清除SREG中的全局中断标志。因此,通常中断将在处理程序内保持禁用,直到处理程序退出,其中RETI指令(由编译器作为中断处理程序的正常函数结尾的一部分发出)最终将重新启用进一步的中断。因此,中断处理程序通常不会嵌套。对于大多数中断处理程序,这是所需的行为,对于某些行为甚至是必需的,以防止无限递归中断(如UART中断或电平触发的外部中断)。在极少数情况下,虽然可能希望在中断处理程序中尽可能早地重新启用全局中断标志,但是为了不推迟任何其他中断而不是绝对需要。这可以在中断处理程序的开头使用sei()指令来完成,但这仍然会在编译器生成的函数序言中留下很少的指令,以便在禁用全局中断的情况下运行。

(来源:http://linux.die.net/man/3/avr_interrupts

答案 1 :(得分:4)

  

中断1中断中断0,还是中断1等待,直到中断0的处理程序执行完毕?

除非您在ISR(中断服务程序)中专门重新启用中断,否则在下一个中断服务之前,当前正在运行的任何中断都会完成,再加上一个机器代码指令

大多数中断在处理器内部设置一个标志,在指令之间检查,以查看是否应该为中断服务。标志按优先顺序检查。在Uno上:

 1  Reset 
 2  External Interrupt Request 0  (pin D2)          (INT0_vect)
 3  External Interrupt Request 1  (pin D3)          (INT1_vect)
 4  Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect)
 5  Pin Change Interrupt Request 1 (pins A0 to A5)  (PCINT1_vect)
 6  Pin Change Interrupt Request 2 (pins D0 to D7)  (PCINT2_vect)
 7  Watchdog Time-out Interrupt                     (WDT_vect)
 8  Timer/Counter2 Compare Match A                  (TIMER2_COMPA_vect)
 9  Timer/Counter2 Compare Match B                  (TIMER2_COMPB_vect)
10  Timer/Counter2 Overflow                         (TIMER2_OVF_vect)
11  Timer/Counter1 Capture Event                    (TIMER1_CAPT_vect)
12  Timer/Counter1 Compare Match A                  (TIMER1_COMPA_vect)
13  Timer/Counter1 Compare Match B                  (TIMER1_COMPB_vect)
14  Timer/Counter1 Overflow                         (TIMER1_OVF_vect)
15  Timer/Counter0 Compare Match A                  (TIMER0_COMPA_vect)
16  Timer/Counter0 Compare Match B                  (TIMER0_COMPB_vect)
17  Timer/Counter0 Overflow                         (TIMER0_OVF_vect)
18  SPI Serial Transfer Complete                    (SPI_STC_vect)
19  USART Rx Complete                               (USART_RX_vect)
20  USART, Data Register Empty                      (USART_UDRE_vect)
21  USART, Tx Complete                              (USART_TX_vect)
22  ADC Conversion Complete                         (ADC_vect)
23  EEPROM Ready                                    (EE_READY_vect)
24  Analog Comparator                               (ANALOG_COMP_vect)
25  2-wire Serial Interface  (I2C)                  (TWI_vect)
26  Store Program Memory Ready                      (SPM_READY_vect)

(请注意,无法屏蔽重置)。

可以想象,低级别中断可能正在进行中(例如,TIMER0_OVF_vect)。当忙于执行其操作时,可能会发生多个其他中断事件(并设置CPU中的相应位)。它们将按上述顺序进行维修,而不是按照它们实际发生的顺序进行维修。

可以写入硬件寄存器,以取消挂起的中断 - 也就是清除标志。

提及另外一个机器代码指令的原因"是因为处理器被设计成保证当它从未启用的中断转换到启用中断时,总是执行一条指令。

这可以让你编写如下代码:

  interrupts ();             // guarantees next instruction executed
  sleep_cpu ();              // sleep now

如果不这样,在进入睡眠状态之前可能会发生中断。这意味着你永远不会醒来,因为你依赖于在睡眠期间发生的中断,而不是在它之前。

  

Freescale和Atmel的愚蠢之处是如何使用相同的指令名称,但具有倒置的含义

这就是为什么我更喜欢interruptsnoInterrupts的助记符,因为其意图非常明确。这些是通过核心包含文件中的定义来实现的。

答案 2 :(得分:1)

The documentation提到Arduino中断具有优先权:

  

如果草图使用多个ISR,则一次只能运行一个ISR。其他中断将在当前中断完成后按照优先级顺序执行。

它还提供了其他信息的链接:

  

有关中断的详细信息,请参阅Nick Gammon's notes

根据什么是中断优先级?中断被禁用时可以发生中断?,我们可以得出结论:

  1. 中断基于标志列表。发生事件时,将设置相应的标志。
  2. 如果ISR现在无法启动,可以在以后随时调用,因为该标志已保存。
  3. 有一个所有可用中断的列表,它通常取决于芯片。列表越高,优先级越高
  4. 因此,不同的中断不会互相中断。它们将根据其优先级执行。