5.按键开关,回调函数和中断
pyboard 开发板上有两个小按键,分别标示为 USR 和 RTS。RTS 按键属于复位按键,如果按下的话将重新擦写重启开发板,相当于将开发板断电再重启。
USR按键供用户使用,且其可以通过声明一个按键对象(Switch object)进行控制。创建开关对象的方法如下:
当提示 pyb 不存在的错误出现时 ,其大意为你忘记键入 import pyb 语句。
利用按键对象可以得到按键的状态:
如果按键被按下将打印 True ,松开则打印 False 。可以尝试运行上述指令时按下 USR 按键。
5.1 按键回调函数
尽管按键算是一种简单的构造,但它具有明显的优势特征:sw.callback( ) 函数。该回调函数将在按键按下时创建一些东西,且使用了一个中断。在理解中断工作机制前最好用一个例子进行描述。尝试在解释器里边运行如下的代码:
- >>> sw.callback(lambda:print('press!'))
这个例程要求每次按下按键时都能打印 press! 字符。先进行尝试:按下USR按键并观测你 PC 上的输出。注意该打印将打断目前你在 pyborad 板上的任何程序,且其属于一种异步中断例程。
可以尝试如下另一个例子:
- >>> sw.callback(lambda:pyb.LED(1).toggle())
这将在每次按键按下时翻转 LED 的亮灭状态,且其能打断目前其他代码的运行。
关闭按键回调,只需将回调函数的参数设置为 None 即可。
你可以传递不带参数的函数作为参数给按键回调函数使用。所以我们可以充分利用 Python 中的 lamba 声明特性。但我们可以用下面的形式替代:
- >>> def f():...
- pyb.LED(1).toggle()
- ...
- >>> sw.callback(f)
这将创建一个名为 f 的函数并将其传递给按键回调函数。当 lamba 比较复杂时你可以尝试使用这种方法。
注意回调函数一定不能含有任何分配内存的定义(比如不能声明创建列表和元组)。回调函数越简单越好。如果确切需要定义列表,请在使用回调函数前定义并用一个全局变量存储(或者定义为局部变量并对其进行封装?)。如果需要多次复杂的计算,那么可以用按键回调设置一个标志供其他代码响应使用。
5.2 中断的原理细节
现在谈谈按键回调函数发生时的细节。当你调用了含有 sw.callback( )的函数时,按键将在其连接引脚产生一个边沿触发(下降沿)外部中断。这意味着芯片将监听该引脚的任何状态变换,且如下事情会发生:
1. 当按键被按下时引脚将发生改变(电平由低到高?),芯片处理器将记录这种变化;
2.处理器完成当前机器指令,退出执行状态并保存当前的状态(将寄存器的内容推入栈中)。这将停止当前运行的任何代码,例如正在执行着的 python 脚本;
3.芯片开始执行与按键相关的特定外部中断触发处理。该处理指向你在 sw.callback( )函数中指定的函数功能并执行之;
4.直到回调函数执行完毕,控制主权将回到中断处理手上;
5.按键中断处理将返回,芯片处理器确认记录该中断被执行过;
6.芯片调回步骤 2 的状态;
7.继续执行开始时的代码,除了短暂的暂停,这部分代码看起来似乎没有被打断过。
当同一时间多个中断同时发生上述的过程将复杂得多。这种情况下拥有最高优先级别的中断将被首先执行,其他的中断按各自的优先级数序执行。按键中断的优先级最低。
5.3进一步参考
进一步使用硬件中断的信息可参考文档
writing interrupt handlers 。