这里我们介绍的是软件定时器。
定时器是一个内核对象,它使用内核的系统时钟来测量时间。当达到定时器的指定时间限制时,它可以执行应用程序定义的操作,也可以简单地记录过期时间并等待应用程序读取其状态。

概念

可以定义任意数量的定时器(仅受可用 RAM 的限制)。每个定时器都由其内存地址引用。
定时器具有以下关键属性:

  • 指定计时器首次过期的时间。使用k_timeout_t类型定义。
  • 指定周期时间。例如,如果计时器的首次过期时间为200,周期为 75,则它将首先在 200 毫秒后过期,然后每隔 75 毫秒过期一次。
  • 每次定时器过期时执行的过期函数。该函数由系统时钟中断处理程序执行。如果不需要过期函数,则可以指定NULL。
  • 一个停止函数,如果定时器在运行时过早停止,则执行该函数。该函数由停止计时器的线程执行。如果不需要停止功能,则可以指定NULL。
  • 一个状态值,该值指示自上次读取状态值以来定时器已过期的次数。

必须先初始化计时器,然后才能使用它。这将指定其到期函数和停止函数,将定时器的状态设置为零,并定计时器置于停止状态。
定时器通过指定首次过期时间和周期时间来启动。定时器的状态重置为零,然后计时器进入运行状态并开始运行。
当正在运行的定时器过期时,其状态递增,定时器执行其过期函数(如果存在);如果线程正在等待定时器,则会解除该线程阻塞。如果定时器的周期为零,则定时器进入停止状态;否则,定时器将重新启动,新的持续时间等于其周期。
如果需要,可以在倒计时中停止运行定时器。定时器的状态保持不变,然后定时器进入停止状态并执行其停止功能(如果存在)。如果线程正在等待定时器,则会解除该线程阻塞。允许尝试停止未运行的计时器,但对计时器没有影响,因为它已停止。
如果需要,可以在倒计时中重新启动运行定时器。定时器的状态重置为零,然后定时器开始使用调用方指定的新持续时间和周期值进行倒计时。如果线程正在等待定时器,它将继续等待。
可以随时直接读取定时器的状态,以确定自上次读取其状态以来定时器已过期的次数。读取定时器的状态会将其值重置为零。还可以读取定时器过期之前的剩余时间量;值为零表示定时器已停止。
线程可以通过与定时器同步来间接读取定时器的状态。这将阻塞线程,直到定时器的状态为非零(指示它至少已过期一次)或定时器停止;如果定时器状态已经不为零或定时器已停止,则线程将继续运行而无需等待。同步操作返回定时器的状态并将其重置为零。

定义定时器

定时器是使用k_timer类型定义的变量。然后必须通过调用k_timer_init()对其进行初始化。

  1. struct k_timer my_timer;
  2. extern void my_expiry_function(struct k_timer *timer_id);
  3. k_timer_init(&my_timer, my_expiry_function, NULL);

也可以通过调用K_TIMER_DEFINE在编译时定义和初始化计时器。

  1. K_TIMER_DEFINE(my_timer, my_expiry_function, NULL);

使用定时器过期功能

下面的代码使用定时器定期执行重要的操作。由于无法在中断级别完成所需的工作,因此定时器的到期函数将工作项提交到系统工作队列。

  1. void my_work_handler(struct k_work *work)
  2. {
  3. /* do the processing that needs to be done periodically */
  4. ...
  5. }
  6. K_WORK_DEFINE(my_work, my_work_handler);
  7. void my_timer_handler(struct k_timer *dummy)
  8. {
  9. k_work_submit(&my_work);
  10. }
  11. K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);
  12. ...
  13. /* start periodic timer that expires once every second */
  14. k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1));

读取定时器状态

以下代码直接读取定时器的状态,以确定定时器是否已过期。

  1. K_TIMER_DEFINE(my_status_timer, NULL, NULL);
  2. ...
  3. /* start one shot timer that expires after 200 ms */
  4. k_timer_start(&my_status_timer, K_MSEC(200), K_NO_WAIT);
  5. /* do work */
  6. ...
  7. /* check timer status */
  8. if (k_timer_status_get(&my_status_timer) > 0) {
  9. /* timer has expired */
  10. } else if (k_timer_remaining_get(&my_status_timer) == 0) {
  11. /* timer was stopped (by someone else) before expiring */
  12. } else {
  13. /* timer is still running */
  14. }

使用定时器状态同步

下面的代码执行定时器状态同步。

  1. K_TIMER_DEFINE(my_sync_timer, NULL, NULL);
  2. ...
  3. /* do first protocol operation */
  4. ...
  5. /* start one shot timer that expires after 500 ms */
  6. k_timer_start(&my_sync_timer, K_MSEC(500), K_NO_WAIT);
  7. /* do other work */
  8. ...
  9. /* ensure timer has expired (waiting for expiry, if necessary) */
  10. k_timer_status_sync(&my_sync_timer);
  11. /* do second protocol operation */
  12. ...