3.3. 虚拟定时器

计时 页面介绍了时间戳以及由 time.ticks_diff() 驱动的非阻塞循环。虚拟定时器则是另一面:软件请求运行时按某个时间表调用一个函数,而运行时会调用该回调,无需脚本自己去检查时钟。

3.3.1. machine.Timer 类

machine.Timer 用于构造一个虚拟定时器。跨移植版本的行为需要使用特殊的 id -1;其他一切——周期、模式、回调——都通过关键字参数设置:

from machine import Timer

def tick(t):
    print("tick")

tim = Timer(-1)
tim.init(period=100, callback=tick)   # 10 Hz

回调像任何普通函数调用一样被调用——它可以分配对象、调用 print() 以及调用其他库代码,没有任何特殊限制。

3.3.2. 周期性与单次

有两种模式可供选择:

  • Timer.PERIODIC(默认)。回调每隔 period 毫秒触发一次,永远持续,直到调用 deinit() 或重新初始化定时器。

  • Timer.ONE_SHOT。回调在 init() 之后 period 毫秒触发一次,随后定时器停止。

Timer(-1).init(mode=Timer.ONE_SHOT, period=2000, callback=fire)

deinit() 停止一个周期性定时器并取消任何待处理的回调:

tim.deinit()

3.3.3. 何时该使用定时器

虚拟定时器和 计时 中的 ticks_diff() 轮询模式从相反的方向解决同一个问题。轮询循环每次迭代都检查时钟,并在过去了足够时间时动作;定时器则请求运行时在过去了足够时间时唤醒脚本。

  • 轮询式 ticks_diff。一切都保持在一处——循环掌管着计时,没有额外的回调需要跟踪。最适合那些短小、定义明确、把多个时间驱动任务联系在一起的工作。

  • 虚拟定时器。把时间表从循环体中移出去。最适合周期性任务独立于主流程的情形(心跳 LED、周期性传感器采样),并让主循环把时间花在其他工作上。

两种方法都使用同一个底层时钟,在毫秒或更长的周期上给出相同的精度。两者都不适合精确的引脚翻转或亚毫秒级的波形生成——回调延迟在调度器 tick 这个量级上,而不是纳秒级。