我有一个Arduino Uno(很棒的小设备!)。它有两个中断;我们称之为 0 和 1 。我使用attachInterrupt()
http://www.arduino.cc/en/Reference/AttachInterrupt附加一个处理程序来中断0和另一个处理程序来中断1。
中断 0 被触发并调用其处理程序,它执行一些数字处理。如果在触发中断 1 时中断 0 的处理程序仍在执行,会发生什么?
中断 1 中断中断 0 ,或者中断 1 等到中断 0 的处理程序是完成执行?
请注意,这个问题与Arduino有关。
答案 0 :(得分:25)
在Arduino(aka AVR)硬件上,除非您有意创建条件以允许嵌套中断发生,否则不会发生嵌套中断。
来自avr-lib:
AVR硬件在进入中断向量之前清除SREG中的全局中断标志。因此,通常中断将在处理程序内保持禁用,直到处理程序退出,其中RETI指令(由编译器作为中断处理程序的正常函数结尾的一部分发出)最终将重新启用进一步的中断。因此,中断处理程序通常不会嵌套。对于大多数中断处理程序,这是所需的行为,对于某些行为甚至是必需的,以防止无限递归中断(如UART中断或电平触发的外部中断)。在极少数情况下,虽然可能希望在中断处理程序中尽可能早地重新启用全局中断标志,但是为了不推迟任何其他中断而不是绝对需要。这可以在中断处理程序的开头使用sei()指令来完成,但这仍然会在编译器生成的函数序言中留下很少的指令,以便在禁用全局中断的情况下运行。
答案 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的愚蠢之处是如何使用相同的指令名称,但具有倒置的含义
这就是为什么我更喜欢interrupts
和noInterrupts
的助记符,因为其意图非常明确。这些是通过核心包含文件中的定义来实现的。
答案 2 :(得分:1)
The documentation提到Arduino中断具有优先权:
如果草图使用多个ISR,则一次只能运行一个ISR。其他中断将在当前中断完成后按照优先级顺序执行。
它还提供了其他信息的链接:
有关中断的详细信息,请参阅Nick Gammon's notes。
根据什么是中断优先级?和中断被禁用时可以发生中断?,我们可以得出结论:
因此,不同的中断不会互相中断。它们将根据其优先级执行。