Timer

在树莓派 Pico 上用 MicroPython 时,rp2 端口的固件只支持“虚拟定时器”(也叫软定时器),也就是 machine.Timer 里 id 固定为 -1 的那一只;硬件定时器(id 从 0 起)在 Pico 上没有开放给 Python。 因此“全部用法”其实就是围绕 这一只虚拟定时器 的几种典型玩法,归纳如下:

  1. 基本用法
    • 导入:from machine import Timer
    • 创建/初始化/停止(回调函数 on_tick 要先定义好):
tim = Timer(-1)                    # 创建计时器对象,或 Timer() 留空也默认 -1
tim.init(period=500,               # 周期,单位毫秒
         mode=Timer.PERIODIC,      # PERIODIC 周期性重复,ONE_SHOT 只执行一次
         callback=on_tick)         # 到点调用哪个函数;这一句执行完定时器就启动了
tim.deinit()                       # 停止定时器

回调函数 回调函数必须带一个形参(定时器对象本身),例如:

def toggle(t):          # t 就是触发它的 Timer 实例
    led.value(not led.value())
  1. 周期闪烁(最常见)
    周期模式 + 回调里翻转 LED,主循环可以同时干别的事,不会被 sleep 阻塞。
# ============ 接线 ============
# 本段用板载 LED(Pin 25),不需要外接元件
# =============================
from machine import Pin, Timer        # 导入 GPIO 和定时器模块
import time

led = Pin(25, Pin.OUT)                # 创建板载 LED 对象

def blink(timer_obj):                 # 回调函数,参数必须是定时器自身
    led.value(not led.value())        # 每进来一次就把 LED 电平翻转

t = Timer(-1)                         # 申请系统软定时器,编号固定 -1
t.init(                               # 初始化定时器
    period=100,                        # 周期 100 毫秒
    mode=Timer.PERIODIC,               # 模式设为“周期性”
    callback=blink)                    # 时间到就调用 blink 函数

# 主循环可以空转,也可以干别的事,LED 会自己闪
i = 0
while True:
    print(i)
    time.sleep(1)
    i = i + 1
  1. 一次性延时任务
    把 mode 设成 Timer.ONE_SHOT,到点执行一次后自动关闭,适合做“20 s 后关闭灯”这类场景。
# ============ 接线 ============
# 本段用板载 LED(Pin 25),不需要外接元件
# =============================
from machine import Pin, Timer        # 同样导入必要模块
led = Pin(25, Pin.OUT)                # 板载 LED

def once_off(timer_obj):              # 一次性定时器回调
    led.off()                         # 时间到了关闭 LED

led.value(1)                          # 先打开灯
t = Timer(-1)                         # 新建一个软定时器
t.init(                               # 初始化成“一次性”
    period=2000,                       # 延时 2000 毫秒
    mode=Timer.ONE_SHOT,               # 模式:只执行一次
    callback=once_off)

# 主循环同样空转,等待执行
while True:
    pass                              # 程序持续运行,不退出
  1. 多只“软”定时器
    虚拟定时器由软件统一管理,可以同时建好几个、同时生效:
t1 = Timer(-1); t1.init(period=500,  mode=Timer.PERIODIC, callback=job1)
t2 = Timer(-1); t2.init(period=2000, mode=Timer.PERIODIC, callback=job2)
  1. 软件消抖
    外部中断触发后,立即启动一个 ONE_SHOT 定时器(如 150~200 ms),等时间到了才真正处理按键,期间忽略新的边沿,达到消抖目的。
# ============ 接线 ============
# 板载 LED:不用外接
# 按键:一脚 → GP0,另一脚 → GND(开内部上拉,不用外接电阻)
# =============================
from machine import Pin, Timer

led   = Pin(25, Pin.OUT)           # 板载 LED
key   = Pin(0, Pin.IN, Pin.PULL_UP)  # 按键,内部上拉
timer = Timer(-1)                    # 软定时器对象先建好
# 消抖时间 150 ms,可视手感微调
DEBOUNCE_MS = 150

def real_handler(timer_obj):
    """真正的处理:只在消抖结束后调用一次"""
    led.value(not led.value())       # 翻转 LED

def key_isr(pin_obj):
    """按键中断:只做一件事——启动一次性定时器"""
    # 先关闭可能还在跑的定时器(防连续快速抖动重复触发)
    timer.deinit()
    # 重新初始化成一次性,到点后再执行 real_handler
    timer.init(
        period=DEBOUNCE_MS,
        mode=Timer.ONE_SHOT,
        callback=real_handler)

# 给按键注册下降沿中断
key.irq(trigger=Pin.IRQ_FALLING, handler=key_isr)

# 主循环空转,系统全靠中断+定时器干活
while True:
    pass

运行效果:
按键每次 稳定按下(经过 150 ms 消抖窗口),LED 翻转一次;
快速抖动、机械弹跳都会被定时器过滤掉,不会误触发。

  1. “看门狗”式刷新
    周期定时器里定期喂狗、采样传感器或刷新屏幕,主循环只做高优先级事务,系统整体响应更快。

  2. 动态改周期 / 开关
    运行中可随时 deinit() 再 init() 改参数,也可以先 tim.deinit() 关闭,等需要时再打开,节省一点 CPU。

# ============ 接线 ============
# 本段用板载 LED(Pin 25),不需要外接元件
# =============================
from machine import Pin, Timer        # 导入必要模块
import time

led = Pin(25, Pin.OUT)                # 创建板载 LED 对象
cnt = 0                               # 全局计数器:记录已翻转次数

def blink(timer_obj):                 # 回调函数:每进来一次就翻转 LED 并计数
    global cnt                        # 声明使用外部变量
    led.value(not led.value())        # 翻转 LED
    cnt += 1                          # 次数 +1

t = Timer(-1)                         # 申请系统软定时器(编号固定 -1)
t.init(                               # 第一次初始化:慢闪模式 1000 ms 周期
    period=1000,                       # 1000 毫秒
    mode=Timer.PERIODIC,               # 周期性
    callback=blink)                    # 回调函数

while True:                           # 主循环:持续监控次数,到达 5 次就重设定时器
    if cnt >= 5:                      # 已经闪了 5 次
        t.deinit()                    # 先关闭旧定时器,释放资源
        cnt = 0                       # 计数器清零
        t.init(
            period=200,                # 新周期 200 毫秒
            mode=Timer.PERIODIC,
            callback=blink)            # 重新注册同一个回调
    # 这里可以干别的事,不会被 sleep 阻塞
    time.sleep_ms(50)                 # 给 CPU 一点喘息,防止 while 跑满

运行现象:
前 5 次翻转间隔 1000 ms(慢闪),随后自动变成每 200 ms 翻转一次(快闪),
全程只靠 deinit() → 改参数 → init() 完成,无需重启或重新导入。

  1. 注意事项
    • 回调里别占用太长时间,否则会阻塞后续定时事件。
    • 不要直接在回调里做大量打印或 I²C/SPI 操作,容易丢中断。
    • 软定时器最小可靠周期约 1 ms,再低就会受解释器调度影响。