目录
摘要
1 概念
2 实现
2.1 定义一个定时器
2.2 使用定时器超时回调函数
2.3 读取定时器状态
2.4 使用计时器状态同步
3 参考链接
本学笔记基于zephyr 工程版本 2.2.99,主机环境为ubuntu18.04,开发平台 nrf52840dk_nrf52840
timer是一个内核对象,它使用内核的系统时钟(基于tick)测量时间。当计时器达到指定的时间限制时,它可以执行应用程序定义的操作(回调函数),或者它可以简单地记录过期时间并等待应用程序读取其状态(不执行回调函数)。
可以定义任意数量的计时器。每个定时器由它的内存地址引用。
定时器有以下关键属性::
duration :指定计时器第一次超时之前的时间间隔,以毫秒为单位。它必须大于0。
period :指定在第一个计时器结束后所有计时器之间的时间间隔,以毫秒为单位。它必须是非负的。周期为零意味着计时器是一个单次性计时器,在一次超时后停止。(例如,如果计时器的持续时间为200,周期为75,那么它将在200毫秒后首次超时,之后每隔75毫秒超时一次。)
expiry function :在每次计时器超时时执行的回调函数。该函数由系统时钟中断处理程序执行。如果不需要超时回调函数,可以指定NULL。
stop function:如果计时器在运行时过早停止,则执行的停止函数。函数由停止计时器的线程执行。如果不需要停止函数,则可以指定NULL。
status:表示自上次读取状态值以来计时器已超时的次数,读取后清零。
计时器在使用之前必须进行初始化。初始化将设置定时器的超时函数和停止函数,将计时器的状态设置为零,并将计时器置于停止状态。
计时器通过指定持续时间(duration )和周期(period )来启动。计时器的状态被重置为零,然后计时器进入运行状态,并开始倒数计时。
当一个正在运行的定时器超时时,它的状态会增加(status加1),并且如果存在一个定时器,它会执行它的超时回调函数;如果一个线程正在等待计时器,超时后线程(调用k_timer_status_sync()这函数的线程)将被解除阻塞。如果定时器的周期为零,则定时器进入停止状态;否则,计时器将重新启动。
如果需要,可以停止正在运行计的时器,之后计时器的状态保持不变(status不再加1),然后计时器进入停止状态并执行它的停止回调函数(如果存在的话)。如果一个线程正在等待计时器,线程(调用k_timer_status_sync()这函数的线程)将被解除阻塞。允许尝试停止一个不运行的计时器,但是对计时器没有影响,因为它已经停止了。
如果需要,可以在倒计时中重新启动正在运行的计时器。计时器的状态被重置为零(status清零),然后计时器开始使用调用者指定的新持续时间和周期值运行。如果一个线程正在等待计时器(调用了k_timer_status_sync()函数),它将继续等待。
可以在任何时候直接读取计时器的状态(读取status值,代表超时的次数),以确定自上次读取其状态以来计时器已超时了多少次。读取计时器的状态后会将status值重置为零。计时器到期前的剩余时间也可以读取,值为0表示计时器停止。
使用struct 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);
下面的代码,使用一个计时器来定期执行一个重要的操作。由于所需的工作无法在ISR中完成,计时器的过期函数将向系统工作队列提交一个工作项,让工作队列的线程将执行该工作:
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), 0);
/* 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), 0);
/* do other work */
...
/* ensure timer has expired (waiting for expiry, if necessary) */
k_timer_status_sync(&my_sync_timer);
/* do second protocol operation */
...
https://docs.zephyrproject.org/latest/reference/kernel/timing/timers.html#id4