zephyr学习之k_timer

简介

定时器(k_timer) 是一个使用内核系统时钟来计时的内核对象。当一个定时器指定的时间计时结束,它将执行一个应用层面已定义的行为,或简单地记录下这个“期满”事件,并等待应用层读取该状态。

zerphyr 定时器有两种: 一次性定时器和周期性定时器。

每个定时器有以下关键属性:

  • 时限(Duration) 是指从启动到定时器第一次期满之间的时间间隔,单位为毫秒。该值必须大于0。
  • 周期(Period) 是指在定时器第一次期满之后,后续每次期满之间的时间间隔,单位为毫秒。该值不能为负数,若该值为0,则该定时器为一次性计时,并会在单次期满后停止工作。
  • 期满函数(Expiry function) 是在定时器每次期满时所执行的函数,该函数由系统时钟中断处理函数来执行。若在期满时无函数需要执行,则该期满函数需要指定为 NULL 。
  • 终止函数(Stop function) 是在定时器运行期间提前终止时所执行的函数。该函数由终止定时器的线程来执行。若在提前终止时无函数需要执行,则该终止函数需要指定为 NULL 。
  • 状态值(status) 指示了自最后一次读取该状态值后,定时器经历了多少次期满。
    定时器在使用前必须先初始化。初始化时将设置期满函数和终止函数,清零定时器状态值,并设置定时器为 停止 状态。

使用方法

定义一个定时器

通过使用类型为 struct k_timer 的变量来定义一个定时器。 该定时器随后必须通过调用 k_timer_init() 来初始化。
如下的代码定义并初始化了一个定时器:

struct k_timer my_timer;
void my_expiry_function(struct k_timer *timer_id) {/* do some work here */};
k_timer_init(&my_timer, my_expiry_function, NULL);

或者,定时器可以在编译阶段通过调用 K_TIMER_DEFINE 来定义和初始化。如下的代码与上面的代码效果一致。

K_TIMER_DEFINE(my_timer, my_expiry_function, NULL);

启动定时器

k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1));

停止定时器

k_timer_stop(&my_timer);

定时器剩余时间

k_timer_remaining_get(&my_timer);

关于duration和period的个人理解

duration为第一次定时器的超时时间,若period不为0,往后定时器是一个周期性定时器,超时时间为period的值。若period为0,则为一次性定时器,超时时间为duration。duration只用于第一次超时时间。

系统ticks获得:

k_cycle_get_32();

当系统时钟为32MHz时,1s = 32000000 ticks

k_timer流程分析

  1. 启动定时器
k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1));
	_add_timeout(NULL, &timer->timeout, &timer->wait_q, duration_in_ticks);
		sys_dlist_append(&_timeout_q, &timeout->node);  // insert to list _timerout_q
  1. 停止定时器
k_timer_stop(&my_timer);
	int inactive = (_abort_timeout(&timer->timeout) == _INACTIVE);
		if (!sys_dlist_is_tail(&_timeout_q, &timeout->node)) {
			struct _timeout *next = (struct _timeout *)next_node;
			next->delta_ticks_from_prev += timeout->delta_ticks_from_prev;
		}
		sys_dlist_remove(&timeout->node);  // remove form list _timerout_q
		timeout->delta_ticks_from_prev = _INACTIVE;
  1. 定时器超时函数
    由前文可知定时器是一个使用内核系统时钟来计时的内核对象。当定时器超时时其超时函数将在系统时钟超时函数中执行。
  • 系统时钟初始化
// sys_clock_init.c (drivers\timer)
SYS_DEVICE_DEFINE("sys_clock", _sys_clock_driver_init, sys_clock_device_ctrl,
		PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
  • 系统时钟中断服务函数
// vector_table.S (arch\arm\core\cortex_m)
 #if defined(CONFIG_CORTEX_M_SYSTICK)
    .word _timer_int_handler
#else
    .word __reserved
#endif

// cortex_m_systick.c (drivers\timer)
void _timer_int_handler(void *unused)
	_sys_clock_tick_announce();
		_nano_sys_clock_tick_announce(_sys_idle_elapsed_ticks)
			handle_timeouts(ticks);
				sys_dlist_t expired;
				struct _timeout *head =
					(struct _timeout *)sys_dlist_peek_head(&_timeout_q);
				while (timeout && timeout->delta_ticks_from_prev == 0) {
					sys_dlist_prepend(&expired, next);
					next = sys_dlist_peek_head(&_timeout_q);
					timeout = (struct _timeout *)next;
				}
				_handle_expired_timeouts(&expired);
					SYS_DLIST_FOR_EACH_CONTAINER_SAFE(expired, timeout, next, node) {
						sys_dlist_remove(&timeout->node);
						_handle_one_expired_timeout(timeout);
							if (timeout->func) 
								timeout->func(timeout);
					}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章