Arduino 上的中断会中断其他中断吗?

发布于 2024-10-19 03:32:46 字数 625 浏览 5 评论 0原文

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

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

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

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

I have an Arduino Uno (awesome little device!). It has two interrupts; let's call them 0 and 1. I attach a handler to interrupt 0 and a different one to interrupt 1, using attachInterrupt() : http://www.arduino.cc/en/Reference/AttachInterrupt.

Interrupt 0 is triggered and it calls its handler, which does some number crunching. If interrupt 0's handler is still executing when interrupt 1 is triggered, what will happen?

Will interrupt 1 interrupt interrupt 0, or will interrupt 1 wait until interrupt 0's handler is done executing?

Please note that this question specifically relates to Arduino.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

瑶笙 2024-10-26 03:32:46

在 Arduino(又名 AVR)硬件上,嵌套中断不会发生,除非您有意创建允许其发生的条件。

来自 avr-lib:

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

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

On Arduino (aka AVR) hardware, nested interrupts don't happen unless you intentionally create the conditions to allow it to happen.

From avr-lib:

The AVR hardware clears the global interrupt flag in SREG before entering an interrupt vector. Thus, normally interrupts will remain disabled inside the handler until the handler exits, where the RETI instruction (that is emitted by the compiler as part of the normal function epilogue for an interrupt handler) will eventually re-enable further interrupts. For that reason, interrupt handlers normally do not nest. For most interrupt handlers, this is the desired behaviour, for some it is even required in order to prevent infinitely recursive interrupts (like UART interrupts, or level-triggered external interrupts). In rare circumstances though it might be desired to re-enable the global interrupt flag as early as possible in the interrupt handler, in order to not defer any other interrupt more than absolutely needed. This could be done using an sei() instruction right at the beginning of the interrupt handler, but this still leaves few instructions inside the compiler-generated function prologue to run with global interrupts disabled.

(source: http://linux.die.net/man/3/avr_interrupts )

瑶笙 2024-10-26 03:32:46

中断 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

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


飞思卡尔和 Atmel 都使用完全相同的指令名称,但含义却相反,真是太白痴了

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

Will interrupt 1 interrupt interrupt 0, or will interrupt 1 wait until interrupt 0's handler is done executing?

Unless you specifically re-enable interrupts inside an ISR (Interrupt Service Routine) then whatever interrupt is currently running completes, plus one more machine code instruction, before the next interrupt is serviced.

Most interrupts set a flag inside the processor, which is checked between instructions, to see if the interrupt should be serviced. Flags are checked in priority order. On the Uno that is:

 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)

(Note that Reset cannot be masked).

Conceivably a low-level interrupt might be in progress (eg. TIMER0_OVF_vect). While that is busy doing its stuff multiple other interrupt events might occur (and set the corresponding bits in the CPU). They will be serviced in the above order, not in the order in which they actually occur in time.

There are hardware registers that can be written to, to cancel a pending interrupt - that is, to clear the flag.


The reason for mentioning "one more machine code instruction" is that the processor is designed to guarantee that when it transitions from interrupts not enabled, to interrupts enabled, one more instruction is always executed.

This lets you write code like this:

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

Without that, an interrupt might occur before going to sleep. Which means you never wake, because you were relying upon the interrupt occuring during sleep, not before it.


How wonderfully moronic of Freescale and Atmel to both use the very same instruction names, but with inverted meanings

That is why I prefer the mnemonics of interrupts and noInterrupts because the intent there is very clear. These are implemented by defines in the core include files.

笔落惊风雨 2024-10-26 03:32:46

文档提到Arduino中断具有优先级:

如果您的草图使用多个 ISR,则一次只能运行一个。其他中断将在当前中断完成后执行,执行顺序取决于它们的优先级。

它还提供了附加信息的链接:

有关中断的更多信息,请参阅Nick Gammon 的笔记

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

  1. 中断是基于标志列表的。当事件发生时,相应的标志被设置。
  2. 如果 ISR 现在无法启动,则可以在以后随时调用它,因为标志已保存。
  3. 有一个所有可用中断的列表,它通常取决于芯片。列表位置越高,优先级就越高。

所以,不同的中断不会互相中断。它们将根据其优先级被执行。

The documentation mention that Arduino interrupts have priority:

If your sketch uses multiple ISRs, only one can run at a time. Other interrupts will be executed after the current one finishes in an order that depends on the priority they have.

It also provides a link for additional information:

For more information on interrupts, see Nick Gammon's notes.

According to sections What is interrupt priority? and Can interrupts occur while interrupts are disabled?, we can conclude that:

  1. Interrupts are based on the list of flags. When an event occurs the corresponding flag is set.
  2. If the ISR can't fire right now, it can be called at any time later because the flag is saved.
  3. There is a list of all available interrupts, and it generally depends on the chip. The higher up the list, the higher the priority.

So, different interrupts will not interrupt each other. They will be executed according to their priority.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文