6.3. Virtual timers

The Timing page covered timestamps and non-blocking loops driven by time.ticks_diff(). A virtual timer is the flip side: software asks the runtime to call a function on a schedule, and the runtime invokes the callback without the script having to check the clock itself.

6.3.1. The machine.Timer class

machine.Timer constructs a virtual timer. Cross-port behaviour requires the special id -1; everything else – period, mode, callback – is set through keyword arguments:

from machine import Timer

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

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

The callback is invoked like any ordinary function call – it can allocate objects, print(), and call other library code without any special restrictions.

6.3.2. Periodic and one-shot

Two modes are available:

  • Timer.PERIODIC (the default). The callback fires every period milliseconds, forever, until deinit() is called or the timer is re-initialised.

  • Timer.ONE_SHOT. The callback fires once, period milliseconds after init(), and the timer then stops.

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

deinit() stops a periodic timer and cancels any pending callback:

tim.deinit()

6.3.3. When to reach for a timer

Virtual timers and the ticks_diff() polling pattern from Timing solve the same problem from opposite directions. A polled loop checks the clock every iteration and acts when enough time has passed; a timer asks the runtime to wake the script when enough time has passed.

  • Polled ticks_diff. Everything stays in one place – the loop owns the timing, no extra callbacks to keep track of. Best for short, well-defined work that ties together several time-driven tasks.

  • Virtual timer. Moves the schedule out of the loop body. Best when the periodic task is independent of the main flow (a heartbeat LED, a periodic sensor sample) and lets the main loop spend its time on other work.

Both approaches use the same underlying clock and give the same accuracy at periods of a millisecond or more. Neither is appropriate for precise pin toggling or sub-millisecond waveform generation – the callback latency is on the order of the scheduler tick, not nanoseconds.