这里我们介绍的是软件定时器。
定时器是一个内核对象,它使用内核的系统时钟
来测量时间。当达到定时器
的指定时间限制时,它可以执行应用程序定义的操作,也可以简单地记录过期时间并等待应用程序读取其状态。
概念
可以定义任意数量的定时器(仅受可用 RAM 的限制)。每个定时器都由其内存地址引用。
定时器具有以下关键属性:
- 指定计时器首次过期的时间。使用
k_timeout_t
类型定义。 - 指定周期时间。例如,如果计时器的首次过期时间为200,周期为 75,则它将首先在 200 毫秒后过期,然后每隔 75 毫秒过期一次。
- 每次定时器过期时执行的过期函数。该函数由
系统时钟中断处理程序执行
。如果不需要过期函数,则可以指定NULL。 - 一个停止函数,如果定时器在运行时过早停止,则执行该函数。该函数由
停止计时器的线程执行
。如果不需要停止功能,则可以指定NULL。 - 一个状态值,该值指示自上次读取状态值以来定时器已过期的次数。
必须先初始化计时器,然后才能使用它。这将指定其到期函数和停止函数,将定时器的状态设置为零,并定计时器置于停止状态。
定时器通过指定首次过期时间和周期时间来启动。定时器的状态重置为零,然后计时器进入运行状态并开始运行。
当正在运行的定时器过期时,其状态递增,定时器执行其过期函数(如果存在);如果线程正在等待定时器,则会解除该线程阻塞。如果定时器的周期为零,则定时器进入停止状态;否则,定时器将重新启动,新的持续时间等于其周期。
如果需要,可以在倒计时中停止运行定时器。定时器的状态保持不变,然后定时器进入停止状态并执行其停止功能(如果存在)。如果线程正在等待定时器,则会解除该线程阻塞。允许尝试停止未运行的计时器,但对计时器没有影响,因为它已停止。
如果需要,可以在倒计时中重新启动运行定时器。定时器的状态重置为零,然后定时器开始使用调用方指定的新持续时间和周期值进行倒计时。如果线程正在等待定时器,它将继续等待。
可以随时直接读取定时器的状态,以确定自上次读取其状态以来定时器已过期的次数。读取定时器的状态会将其值重置为零。还可以读取定时器过期之前的剩余时间量;值为零表示定时器已停止。
线程可以通过与定时器同步来间接读取定时器的状态。这将阻塞线程,直到定时器的状态为非零(指示它至少已过期一次)或定时器停止;如果定时器状态已经不为零或定时器已停止,则线程将继续运行而无需等待。同步操作返回定时器的状态并将其重置为零。
定义定时器
定时器是使用k_timer
类型定义的变量。然后必须通过调用k_timer_init()
对其进行初始化。
struct k_timer my_timer;
extern void my_expiry_function(struct k_timer *timer_id);
k_timer_init(&my_timer, my_expiry_function, NULL);
也可以通过调用K_TIMER_DEFINE
在编译时定义和初始化计时器。
K_TIMER_DEFINE(my_timer, my_expiry_function, NULL);
使用定时器过期功能
下面的代码使用定时器定期执行重要的操作。由于无法在中断
级别完成所需的工作,因此定时器
的到期函数将工作项提交到系统工作队列。
void my_work_handler(struct k_work *work)
{
/* do the processing that needs to be done periodically */
...
}
K_WORK_DEFINE(my_work, my_work_handler);
void my_timer_handler(struct k_timer *dummy)
{
k_work_submit(&my_work);
}
K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);
...
/* start periodic timer that expires once every second */
k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1));
读取定时器状态
以下代码直接读取定时器的状态,以确定定时器是否已过期。
K_TIMER_DEFINE(my_status_timer, NULL, NULL);
...
/* start one shot timer that expires after 200 ms */
k_timer_start(&my_status_timer, K_MSEC(200), K_NO_WAIT);
/* do work */
...
/* check timer status */
if (k_timer_status_get(&my_status_timer) > 0) {
/* timer has expired */
} else if (k_timer_remaining_get(&my_status_timer) == 0) {
/* timer was stopped (by someone else) before expiring */
} else {
/* timer is still running */
}
使用定时器状态同步
下面的代码执行定时器状态同步。
K_TIMER_DEFINE(my_sync_timer, NULL, NULL);
...
/* do first protocol operation */
...
/* start one shot timer that expires after 500 ms */
k_timer_start(&my_sync_timer, K_MSEC(500), K_NO_WAIT);
/* do other work */
...
/* ensure timer has expired (waiting for expiry, if necessary) */
k_timer_status_sync(&my_sync_timer);
/* do second protocol operation */
...