utime – 时间相关功能

该模块实现了相应CPython 模块的 一个子集,如下所述。有关更多信息,请参阅原始 CPython 文档:time.

utime模块提供获取当前时间和日期、测量时间间隔和延迟的函数。

时间纪元:Unix 端口使用 1970-01-01 00:00:00 UTC 的 POSIX 系统纪元标准。但是,嵌入式端口使用 2000-01-01 00:00:00 UTC 的纪元。

维护实际日历日期/时间:这需要实时时钟 (RTC)。在具有底层操作系统(包括某些 RTOS)的系统上,RTC 可能是隐式的。设置和维护实际日历时间是 OS/RTOS 的责任,是在 MicroPython 之外完成的,它只是使用 OS API 来查询日期/时间。然而,在裸机端口上,系统时间取决于machine.RTC() 对象。当前日历时间可通过machine.RTC().datetime(tuple)函数设置,并通过以下方式维护:

  • 通过备用电池(可能是特定板的附加可选组件)。

  • 使用网络时间协议(需要由端口/用户设置)。

  • 由用户在每次上电时手动设置(许多板在硬复位后保持 RTC 时间,尽管在这种情况下有些可能需要再次设置)。

如果系统/MicroPython RTC 未维护实际日历时间,则下面需要参考当前绝对时间的函数的行为可能与预期不同。

功能

utime.gmtime([secs])
utime.localtime([secs])

将自 Epoch(见上文)以来以秒表示的时间秒转换为一个 8 元组,其中包含: 如果未提供secs或 None,则使用来自 RTC 的当前时间。 (year, month, mday, hour, minute, second, weekday, yearday)

gmtime()函数以 UTClocaltime() 返回日期时间元组,并以本地时间返回日期时间元组。

8元组中条目的格式为:

  • 年份包括世纪(例如 2014)。

  • 月份是 1-12

  • mday 是 1-31

  • 小时是 0-23

  • 分钟是 0-59

  • 第二个是 0-59

  • 周一至周日的工作日是 0-6

  • 年是 1-366

utime.mktime()

这是本地时间的反函数。它的参数是一个完整的 8 元组,表示按照本地时间的时间。它返回一个整数,它是自 2000 年 1 月 1 日以来的秒数。

utime.sleep(seconds)

睡眠给定的秒数。某些板可能接受秒作为浮点数以休眠几秒钟。请注意,为了与它们的使用sleep_ms()sleep_us()功能兼容,其他板可能不接受浮点参数。

utime.sleep_ms(ms)

给定毫秒数的延迟,应为正数或 0。

utime.sleep_us(us)

给定微秒数的延迟,应为正数或 0。

utime.ticks_ms()

返回带有任意参考点的递增毫秒计数器,该计数器在某个值之后环绕。

环绕值未明确公开,但我们将其称为TICKS_MAX以简化讨论。值的周期为 TICKS_PERIOD = TICKS_MAX + 1。TICKS_PERIOD保证是 2 的幂,但其他方面可能因端口而异。相同的周期值用于所有ticks_ms(), ticks_us(), ticks_cpu()函数(为简单起见)。因此,这些函数将返回 [ 0 .. TICKS_MAX ]范围内的值,包括总TICKS_PERIOD值。请注意,仅使用非负值。在大多数情况下,您应该将这些函数返回的值视为不透明的。他们唯一可用的操作是 ticks_diff()ticks_add() 功能描述如下。

注意:直接对这些值执行标准数学运算(+、-)或关系运算符(<、<=、>、>=)将导致无效结果。执行数学运算然后将它们的结果作为参数传递给ticks_diff() or ticks_add() 也会导致后面的函数产生无效的结果。

utime.ticks_us()

就像ticks_ms() 上面一样,但以微秒为单位。

utime.ticks_cpu()

类似于 ticks_ms()ticks_us(),但在系统中具有尽可能高的分辨率。这通常是 CPU 时钟,这就是函数以这种方式命名的原因。但它不一定是 CPU 时钟,可以使用系统中可用的其他一些定时源(例如高分辨率定时器)来代替。此功能的确切计时单位(分辨率)未在utime模块级别指定,但特定端口的文档可能会提供更具体的信息。此功能用于非常精细的基准测试或非常紧凑的实时循环。避免在可移植代码中使用它。

可用性:并非每个端口都实现此功能。

utime.ticks_add(ticks, delta)

按给定数字偏移刻度值,可以是正数也可以是负数。给定一个刻度值,这个函数允许 在它之前或之后计算刻度值增量刻度,遵循刻度值的模算术定义(见ticks_ms() 上文)。蜱参数必须调用的直接结果ticks_ms(), ticks_us(), or ticks_cpu()功能(或从先前调用ticks_add())。但是,delta可以是任意整数或数字表达式。 ticks_add() 可用于计算事件/任务的截止日期。(注意:您必须使用ticks_diff()函数来处理截止日期。)

例子:

# Find out what ticks value there was 100ms ago
print(ticks_add(time.ticks_ms(), -100))

# Calculate deadline for operation and test for it
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
    do_a_little_of_something()

# Find out TICKS_MAX used by this port
print(ticks_add(0, -1))
utime.ticks_diff(ticks1, ticks2)

测量从ticks_ms(), ticks_us(), 或ticks_cpu()函数返回的值之间的刻度差异,作为可能环绕的带符号值。

参数顺序与减法运算符相同,与具有相同的含义。但是,等函数返回的值可能会回绕,因此直接对它们使用减法会产生错误的结果。这就是为什么 需要它,它实现模块化(或更具体地说,环)算术以产生正确的结果,即使是环绕值(只要它们之间不太远,见下文)。该函数返回[ -TICKS_PERIOD/2 .. TICKS_PERIOD/2-1 ]范围内的有符号值(这是二进制补码有符号二进制整数的典型范围定义)。如果结果为负,则表示 ticks1发生的时间早于ticks2ticks_diff(ticks1, ticks2) ticks1 - ticks2 ticks_ms() ticks_diff(). 否则,这意味着 ticks1发生在ticks2之后。这仅在ticks1和ticks2 彼此分开不超过TICKS_PERIOD/2-1 个滴答时成立。如果不成立,将返回错误的结果。具体来说,如果两个刻度值分开TICKS_PERIOD/2-1 个刻度,该值将由函数返回。然而,如果实时报价的 TICKS_PERIOD/2在它们之间传递,函数将返回-TICKS_PERIOD/2,即结果值将环绕到可能值的负范围。

上述限制的非正式理由:假设您被锁在一个房间里,除了标准的 12 档时钟之外,无法监控时间的流逝。那么如果你现在看表盘,再过13个小时不要再看(例如,如果你睡了很久),那么一旦你终于再看,你可能觉得只过去了1个小时. 为避免这种错误,只需定期查看时钟即可。您的应用程序也应该这样做。“睡眠时间过长”的比喻也直接映射到应用程序的行为:不要让您的应用程序运行任何单个任务的时间太长。分步运行任务,并在其间进行计时。

ticks_diff()旨在适应各种使用模式,其中包括:

  • 轮询超时。在这种情况下,事件的顺序是已知的,您将只处理以下的积极结果 ticks_diff():

    # Wait for GPIO pin to be asserted, but at most 500us
    start = time.ticks_us()
    while pin.value() == 0:
        if time.ticks_diff(time.ticks_us(), start) > 500:
            raise TimeoutError
    
  • 安排活动。在这种情况下,ticks_diff()如果事件逾期,结果可能为负:

    # This code snippet is not optimized
    now = time.ticks_ms()
    scheduled_time = task.scheduled_time()
    if ticks_diff(scheduled_time, now) > 0:
        print("Too early, let's nap")
        sleep_ms(ticks_diff(scheduled_time, now))
        task.run()
    elif ticks_diff(scheduled_time, now) == 0:
        print("Right at time!")
        task.run()
    elif ticks_diff(scheduled_time, now) < 0:
        print("Oops, running late, tell task to run faster!")
        task.run(run_faster=true)
    

注意:不要将 time()值传递给 ticks_diff(),您应该对它们使用正常的数学运算。但请注意,time() 可能(并且将会)也会溢出。这被称为 https://en.wikipedia.org/wiki/Year_2038_problem .

utime.time()

以整数形式返回自 Epoch 以来的秒数,假设底层 RTC 已按上述方式设置和维护。如果未设置 RTC,则此函数返回自特定于端口的参考时间点以来的秒数(对于没有电池后备 RTC 的嵌入式板,通常自上电或复位后)。如果你想开发可移植的 MicroPython 应用程序,你不应该依赖这个函数来提供高于秒的精度。如果您需要更高的精度、绝对时间戳,请使用time_ns(). 如果可以接受相对时间,则使用 ticks_ms()ticks_us()函数。如果您需要日历时间,gmtime() 或者 localtime() 没有参数是更好的选择。

与 CPython 的区别

在 CPython 中,此函数返回自 Unix 纪元 1970-01-01 00:00 UTC 以来的秒数,作为浮点数,通常具有微秒精度。使用 MicroPython,只有 Unix 端口使用相同的 Epoch,如果浮点精度允许,则返回亚秒级精度。嵌入式硬件通常没有浮点精度来表示长时间范围和亚秒精度,因此它们使用具有秒精度的整数值。一些嵌入式硬件也没有电池供电的 RTC,因此返回自上次加电或从其他相关的硬件特定点(例如重置)开始的秒数。

utime.time_ns()

类似于time()但返回自 Epoch 以来的纳秒,作为一个整数(通常是一个大整数,所以会在堆上分配)。