我可以在中断中使用 cli() 和 sei() 吗?

May I use cli() and sei() in the interrupt?

我可以像这样使用 cli() 和 sei() 吗:

ISR(EXT_INT0_vect)
{
    cli();
    MyFunction();
    sei();
}

听说是禁止的。是这样还是我可以像上面那样使用 cli() 和 sei()?

在中断回调中(直接或间接)调用 sei() 会过早地重新启用中断。

出于这个原因,许多库函数(可以从主任务或中断处理程序调用)在禁用中断之前保存中断掩码,然后恢复以前的中断掩码而不是盲目地启用它。

如果您想要正常的中断行为,手动调用 cli() 和 sei() 是多余的(就像在您的示例中一样)。也就是说,因为 AVR 在执行 ISR 之前会自动清除全局中断标志。 嵌套中断很少见,您可能希望在 ISR 中使用 sei() 手动重新启用中断。

来自Nested interrupts

Normally, the AVR hardware clears the global interrupt flag (in SREG) before entering an interrupt. This means other interrupts are disabled inside the running handler until the handler finishes and exits.

The RETI instruction is the normal function epilogue for an interrupt handler, and thus re-enables interrupts (just like executing an SEI instruction). For this reason, normally, interrupt handlers can not be nested.

For most interrupt handlers, this is the desired behavior. For some its even required in order to prevent infinitely recursive interrupts. Recursion could easily exceed the available stack space and crash the running program. In rare circumstances it might be desirable to re-enable the global interrupt flag as early as possible inside the interrupt handler, allowing recursive interrupt handling. Carefully.

This could be accomplished by inserting an sei() instruction right at the beginning of the interrupt handler, but this still leaves a few instructions inside the (compiler-generated) interrupt prologue to run with global interrupts disabled. [...]