延时和计时
1. 本节介绍
📝本节您将学习如何利用RP2350的延时和计时功能,实现精确的延时控制以及计时应用。
🏆学习目标
1️⃣利用延时功能,设计一个LED灯闪烁的程序,使其按照500ms的间隔闪烁。
2️⃣利用计时功能,实现定时处理指定任务。
2. 为什么要单独写延时?
在嵌入式开发中,延时和计时是常见的功能需求。
在RP2350或其他微控制器的编程中,延时被广泛使用,主要有以下一些原因:
- 处理硬件: 许多硬件都需要一些时间来响应某个命令。例如,如果在一个程序中你启动一个电动机然后立即检查其状态,你可能会得到一个错误的读数,因为电动机可能还没有足够的时间开始旋转。此时你需要使用 延时功能 让系统等待一段时间,使得电动机有足够的时间响应。
- 用户交互: 我们常常需要在用户交互中实现延迟效果。例如,在蜂鸣器播放音乐时,音符之间需要一段沉默的时间。或者,在闪烁LED灯的情况下,"开"和"关"状态之间需要延时以控制闪烁的速度。
- 节省能源: 在一些应用中,比如电池供电的系统,如果不在需要的时候长期保持系统的高速运转,那么电池的寿命会大大缩短。在此情况下,我们可以让系统在一段时间后进入待机或低功耗模式,直到下一个处理周期到来。
- 定时操作: 在许多项目中,我们常常需要实现一些特定时间点的操作。例如,在自动灌溉系统中,我们可能需要在每天的特定时间点进行灌溉。在间隔测量中,我们可能每隔一段时间采集一次数据。
尽管延时函数在很多情况下非常有用,但也需要注意其阻塞性质。过度依赖阻塞延时可能会导致程序对其他事件的响应不及时。为了更好的在RP2350上进行多任务编程,我们还可以学习一些非阻塞延时的编程技术。
❓什么是阻塞延时?
阻塞延时是在程序执行过程中,当某个操作或函数需要一定时间才能完成时,程序会暂停执行直至该操作完成,这段时间程序被阻塞了。阻塞延时可能会导致程序运行速度变慢或出现假死现象。 举个例子,假设你想要煮开水来泡茶。通常情况下,你会将水壶放在炉灶上加热,等待水烧开后才能使用。在这个过程中,存在阻塞延时。 当你将水壶放在火上时,程序可以看作是“等待”水烧开的操作。在这个等待过程中,你不能立即得到热水来泡茶,需要耐心等待水煮沸。期间,你可能无法做其他与烧水无关的事情,因为你需要留意水壶,并等待时机。即便家里着火了,你也还是在等待烧水。
3. 实现延时和计时的方式
使用 time
该 time
类 提供获取当前时间和日期、测量时间间隔和延迟的函数。
要使用 time
,首先需要导入该模块:
import time
常用方法总结
秒单位的延时
time.sleep(seconds)
seconds
为睡眠给定的秒数。
毫秒单位的延时
time.sleep_ms(ms)
ms
为睡眠给定的毫秒数。
微秒单位的延时
time.sleep_us(us)
us
为睡眠给定的微秒数。
递增毫秒计数器
time.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() 或 ticks_add() 也会导致后面的函数产生无效的结果。
递增微秒计数器
time.ticks_us()
就像 ticks_ms()
上面一样,但以微秒为单位。
滴答数偏移
time.ticks_add(ticks, delta)
用于计算时间ticks(滴答数)的相对偏移值。主要用于处理时间相关的计算,特别是在需要计算未来某个时间点或时间间隔时。
参数说明
参数 | 说明 | 可选值 |
---|---|---|
ticks | 原始的ticks值,通常是通过 time.ticks_ms()、time.ticks_us() 等函数获取的。 | 整型数据 |
delta | 要增加的ticks数,表示时间间隔。 | 整型数据 |
示例:
import time
# 找出该开发板使用的最大滴答值
print(ticks_add(0, -1))
2
3
计算两个时间的差值
time.ticks_diff(ticks1, ticks2)
这个函数返回从ticks2到ticks1的时间差,即ticks1 - ticks2。这个差值通常用于测量时间间隔,比如计算某个操作的执行时间。
参数说明
参数 | 说明 | 可选值 |
---|---|---|
ticks1 | 第一个时间戳 | 整型数据 |
ticks2 | 第二个时间戳 | 整型数据 |
注意事项:
时间戳通常是由time.ticks_ms()、time.ticks_us()等函数获取的,这些函数返回自系统启动以来的毫秒数或微秒数。
由于这些时间戳可能会溢出(例如,毫秒计数器可能会从最大值溢回到0),time.ticks_diff()函数内部会处理这种溢出情况,确保返回正确的差值。
返回的差值始终为非负数,因为它是两个时间点的间隔。
4. 延时/计时实验
🏆学习目标
1️⃣利用延时功能,设计一个LED灯闪烁的程序,使其按照500ms的间隔闪烁。
2️⃣利用计时功能,实现定时处理指定任务。
代码验证
代码目标
利用延时功能,设计一个LED灯闪烁的程序,使其按照500ms的间隔闪烁。
from machine import Pin
import time
# 设置GPIO 25为输出模式
led = Pin(25, Pin.OUT)
# 主循环,程序将在这里无限循环
while True:
led.value(1)
time.sleep_ms(500)
led.value(0)
time.sleep_ms(500)
2
3
4
5
6
7
8
9
10
11
12
13
14
代码目标
利用计时功能,实现定时处理指定任务。 指定任务自定义,这里用的任务为 定时1S让LED闪烁任务
from machine import Pin
import time
# 初始化LED引脚,假设LED连接到GPIO 25
led = Pin(25, Pin.OUT)
# 设置翻转LED的时间间隔,例如每秒翻转一次
interval = 1000 # 时间间隔,单位为毫秒
# 记录上一次翻转LED的时间
last_time = time.ticks_ms()
while True:
# 获取当前时间
current_time = time.ticks_ms()
# 检查是否达到了翻转LED的时间间隔
if time.ticks_diff(current_time, last_time) >= interval:
# 指定任务:翻转LED的状态
led.value(not led.value())
# 更新上一次翻转LED的时间
last_time = current_time
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这段代码会每隔一秒钟翻转一次LED的状态。time.ticks_ms()
函数返回当前的运行代码以来的毫秒计时器值,time.ticks_diff()
函数用于计算两个时间之间的差值。