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 回调。上面我们使用lambda
Python的特性动态创建了一个匿名函数。但我们同样可以做到:
>>> def f():
... pyb.LED(1).toggle()
...
>>> sw.callback(f)
这将创建一个被调用的函数f
并将其分配给 switch 回调。当您的函数比 a
lambda
允许的更复杂时,您可以这样做 。
请注意,您的回调函数不得分配任何内存(例如,它们不能创建元组或列表)。回调函数应该比较简单。如果您需要创建列表,请事先创建并将其存储在全局变量中(或将其设为本地并关闭)。如果你需要做一个长而复杂的计算,那么使用回调来设置一个标志,然后其他代码响应。
5.2. 中断的技术细节¶
让我们逐步了解开关回调发生的情况的详细信息。当您使用 注册函数时sw.callback()
,开关会在开关所连接的引脚上设置外部中断触发器(下降沿)。这意味着微控制器将侦听引脚上的任何更改,并将发生以下情况:
当按下开关时,引脚上会发生变化(引脚从低电平变为高电平),微控制器会记录此变化。
微控制器完成当前机器指令的执行,停止执行,并保存其当前状态(将寄存器压入堆栈)。这具有暂停任何代码的效果,例如您正在运行的 Python 脚本。
微控制器开始执行与开关外部触发相关的特殊中断处理程序。此中断处理程序获取您注册的函数
sw.callback()
并执行它。您的回调函数会一直执行,直到它完成,将控制权返回给 switch 中断处理程序。
切换中断处理程序返回,通知微控制器中断已处理。
微控制器恢复它在步骤 2 中保存的状态。
继续执行开始时运行的代码。除了暂停,这段代码没有注意到它被中断了。
当多个中断同时发生时,上述事件序列会变得更加复杂。在这种情况下,具有最高优先级的中断首先执行,然后按优先级顺序执行其他中断。开关中断设置为最低优先级。