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);
					}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章