(特定于 Arduino Uno...)
当 AVR 微控制器上发生中断并且我调用函数时,堆栈会发生什么?编译器是否内联代码?它是否在某处缓存堆栈然后重置堆栈指针?它是否有一个仅用于中断的辅助堆栈?
据我了解,中断向量是汇编中的直接 GOTO 命令。另外,我不认为微控制器会自动弄乱堆栈,所以它可能会被单独留下。但是,这仍然不能解释函数在 ISR 期间是如何工作的。
(特定于 Arduino Uno...)
当 AVR 微控制器上发生中断并且我调用函数时,堆栈会发生什么?编译器是否内联代码?它是否在某处缓存堆栈然后重置堆栈指针?它是否有一个仅用于中断的辅助堆栈?
据我了解,中断向量是汇编中的直接 GOTO 命令。另外,我不认为微控制器会自动弄乱堆栈,所以它可能会被单独留下。但是,这仍然不能解释函数在 ISR 期间是如何工作的。
AVR 是 RISC 架构,因此它具有非常基本的中断硬件处理。大多数处理器在中断期间都会弄乱堆栈,尽管有几个,尤其是 ARM 和 PowerPC,它们使用不同的方法。
无论如何,这就是 AVR 对中断所做的事情:
当中断发生时,处理器硬件会执行这些步骤,而不仅仅是简单的 GOTO:
现在,硬件已经完成了它要做的所有事情。该软件必须正确编写,以免破坏。通常,接下来的步骤是沿着这些路线进行的。
将状态寄存器压入堆栈。(这必须在更改之前先完成)。
将任何将(或可能)更改的 CPU 寄存器压入堆栈。需要以这种方式保存哪些寄存器由编程模型定义。编程模型由编译器定义。
现在可以运行工作中断代码。为了回答调用函数的问题,它只是做它一直做的事情,将返回值压入堆栈,然后在完成后将其弹出。这不会影响我们之前保存在堆栈中的任何这些值。
现在我们完成了,想要从中断中返回。首先,我们必须进行软件清理。
执行 RTI 指令。硬件为此指令执行以下步骤:
一种。启用全局中断标志。(请注意,在处理下一个中断之前必须至少运行一条指令。这样可以防止重度中断完全阻塞后台工作。)
湾。将保存的返回地址弹出到 PC 中。
现在我们回到正常的代码。
请注意,有些地方我们必须非常小心,尤其是在状态寄存器和保存可能更改的寄存器周围。幸运的是,如果您使用的是 C 编译器,所有这些都是在幕后处理的。
此外,您必须注意您的堆栈深度。在启用中断的任何时候,ISR 可以使用比通过查看本地代码显而易见的更多的堆栈。当然,除非您将记忆力推到极限,否则这真的不会出现太多。
如果您需要参考,这里是描述此过程的链接。