5. 开关、回调和中断

pyboard 有 2 个小开关,标记为 USR 和 RST。RST开关是一个硬复位开关,如果你按下它,它会从头开始重新启动pyboard,相当于关闭电源然后重新打开。

USR 开关用于一般用途,并通过 Switch 对象控制。要制作开关对象,请执行以下操作:

>>> sw = pyb.Switch()

请记住,如果您收到名称不存在的错误,您可能需要键入。 import pyb pyb

使用 switch 对象,您可以获得其状态:

>>> sw.value()
False

False 如果开关没有保持,或者True 它被保持,这将打印。尝试在运行上述命令时按住 USR 开关。

还有一个速记符号可以通过“调用”开关对象来获取开关状态:

>>> sw()
False

5.1. 切换回调

开关是一个非常简单的对象,但它确实有一个高级特性: sw.callback()函数。回调函数设置在按下开关时运行的东西,并使用中断。在理解中断如何工作之前,最好先从一个例子开始。尝试在提示符下运行以下命令:

>>> sw.callback(lambda:print('press!'))

这告诉开关在press! 每次按下开关时打印。继续尝试:按下 USR 开关并在您的 PC 上观看输出。请注意,此打印将中断您正在键入的任何内容,并且是异步运行的中断例程的示例。

作为另一个例子尝试:

>>> sw.callback(lambda:pyb.LED(1).toggle())

每次按下开关时,这将切换红色 LED。它甚至可以在其他代码运行时工作。

要禁用开关回调,请传递 None 给回调函数:

>>> sw.callback(None)

您可以将任何函数(采用零参数)传递给 switch 回调。上面我们使用lambdaPython的特性动态创建了一个匿名函数。但我们同样可以做到:

>>> def f():
...   pyb.LED(1).toggle()
...
>>> sw.callback(f)

这将创建一个被调用的函数f 并将其分配给 switch 回调。当您的函数比 a lambda 允许的更复杂时,您可以这样做 。

请注意,您的回调函数不得分配任何内存(例如,它们不能创建元组或列表)。回调函数应该比较简单。如果您需要创建列表,请事先创建并将其存储在全局变量中(或将其设为本地并关闭)。如果你需要做一个长而复杂的计算,那么使用回调来设置一个标志,然后其他代码响应。

5.2. 中断的技术细节

让我们逐步了解开关回调发生的情况的详细信息。当您使用 注册函数时sw.callback(),开关会在开关所连接的引脚上设置外部中断触发器(下降沿)。这意味着微控制器将侦听引脚上的任何更改,并将发生以下情况:

  1. 当按下开关时,引脚上会发生变化(引脚从低电平变为高电平),微控制器会记录此变化。

  2. 微控制器完成当前机器指令的执行,停止执行,并保存其当前状态(将寄存器压入堆栈)。这具有暂停任何代码的效果,例如您正在运行的 Python 脚本。

  3. 微控制器开始执行与开关外部触发相关的特殊中断处理程序。此中断处理程序获取您注册的函数sw.callback() 并执行它。

  4. 您的回调函数会一直执行,直到它完成,将控制权返回给 switch 中断处理程序。

  5. 切换中断处理程序返回,通知微控制器中断已处理。

  6. 微控制器恢复它在步骤 2 中保存的状态。

  7. 继续执行开始时运行的代码。除了暂停,这段代码没有注意到它被中断了。

当多个中断同时发生时,上述事件序列会变得更加复杂。在这种情况下,具有最高优先级的中断首先执行,然后按优先级顺序执行其他中断。开关中断设置为最低优先级。

5.3. 进一步阅读

有关使用硬件中断的更多信息,请参阅 编写中断处理程序