
在 esp32 上用 micropython 测量小于 1 秒的时间间隔(如轮速检测中的按钮触发间隔)时,应避免使用 `time.time()`,而需采用基于硬件定时器的 `time.ticks_ms()` 与 `time.ticks_diff()` 组合,以获得毫秒级精度和可靠的时间差计算。
在嵌入式实时测量场景中(例如通过霍尔传感器或机械按键检测车轮转速),时间分辨率至关重要。time.time() 返回的是自 Unix 纪元起的浮点型秒数,在 ESP32 的 MicroPython 实现中其最小分辨率为约 10–50 ms,且受系统调度、GC(垃圾回收)及浮点运算误差影响,无法稳定支持亚百毫秒级测量,更不适用于计算高频脉冲间隔(如每转一次仅几毫秒)。
正确的做法是使用 MicroPython 提供的轻量、无中断风险的“ticks” API:
- time.ticks_ms():返回单调递增的毫秒计数值(32 位无符号整数),由硬件定时器驱动,精度高、开销极低;
- time.ticks_diff(new, old):安全计算两个 ticks 值之差(自动处理 32 位溢出),结果单位为毫秒;
- 若需换算为秒用于物理计算(如速度 = 距离 / 时间),再除以 1000.0 即可。
以下是修正后的轮速测量示例代码:
from machine import Pin
import time
# 初始化按键(建议使用外部中断或防抖逻辑,此处简化演示)
break_btn = Pin(33, Pin.IN, Pin.PULL_DOWN)
speeds = []
start_time = time.ticks_ms() # 首次时间戳
for i in range(1000):
time.sleep_ms(70) # 推荐使用 sleep_ms 而非 sleep(0.07),更精确
if break_btn.value():
# ✅ 正确:使用 ticks_diff 获取毫秒级时间差
time_passed_ms = time.ticks_diff(time.ticks_ms(), start_time)
start_time = time.ticks_ms() # 更新上次触发时刻
print(f"Time passed: {time_passed_ms} ms")
# ✅ 换算为秒(保留浮点精度)用于速度计算
if time_passed_ms > 0:
speed_mps = 0.335 / (time_passed_ms / 1000.0) # 距离 0.335m / 时间(s)
speeds.append(speed_mps)
print(f"Measured speeds: {speeds}")⚠️ 关键注意事项:
立即学习“Python免费学习笔记(深入)”;
- 切勿直接相减 ticks_ms() 值(如 now - start):因 ticks 值会 32 位溢出(约 49.7 天后归零),手动相减在溢出边界处将导致严重错误;必须使用 ticks_diff()。
- 避免在循环中频繁调用 time.time():它涉及系统时间同步开销,且在 ESP32 MicroPython 中底层依赖 gettimeofday(),精度与稳定性均不足。
- 硬件层面建议:对高速轮速测量(>10 Hz),应改用 Pin.irq() 注册下降沿中断,并在中断服务程序(ISR)中仅记录 ticks_ms(),主循环负责计算与处理——可显著提升响应及时性与时间戳准确性。
- 防抖处理不可省略:机械按钮需软件延时(如 time.sleep_ms(20) 后二次确认)或硬件 RC 滤波,否则单次按压可能触发多次误读。
综上,time.ticks_ms() + time.ticks_diff() 是 MicroPython 在资源受限 MCU(如 ESP32)上实现微秒至毫秒级时间测量的事实标准方案。掌握这一模式,是构建可靠传感器测速、PWM 同步、事件计时等应用的基础能力。










