軟件定時(shí)器
概述
AliOS Things操作系統(tǒng)內(nèi)核使用tick作為時(shí)間片輪轉(zhuǎn)調(diào)度以及延遲操作的時(shí)間度量單位,tick是實(shí)現(xiàn)定時(shí)觸發(fā)功能的基礎(chǔ)。tick計(jì)數(shù)發(fā)生在每次時(shí)鐘中斷處理的過程,時(shí)鐘中斷是定時(shí)產(chǎn)生的,系統(tǒng)在默認(rèn)情況下為1ms觸發(fā)一次,即一個(gè)tick代表1ms,用戶可根據(jù)應(yīng)用需要調(diào)整該時(shí)間。 軟件定時(shí)器是用來在指定時(shí)間或者觸發(fā)一次或多次某個(gè)功能函數(shù)的調(diào)用。這種由定時(shí)器來執(zhí)行的函數(shù)叫做定時(shí)器回調(diào)函數(shù),定時(shí)器回調(diào)函數(shù)以及觸發(fā)時(shí)間由應(yīng)用程序來設(shè)定。當(dāng)定時(shí)器的觸發(fā)時(shí)間到來,則定時(shí)器的回調(diào)函數(shù)會被執(zhí)行。定時(shí)器支持兩種工作模式:單次模式和周期性模式。定時(shí)器在創(chuàng)建時(shí),用戶可通過option參數(shù)來制定該定時(shí)器的工作模式是單次還是周期性的,若option設(shè)置了AOS_TIMER_REPEAT則為周期性的,否則為單次。
單次模式
定時(shí)器會從應(yīng)用程序設(shè)置的初始時(shí)間開始,以tick為計(jì)時(shí)單位進(jìn)行倒計(jì)時(shí),當(dāng)計(jì)數(shù)值減為0時(shí)調(diào)用回調(diào)函數(shù)執(zhí)行。回調(diào)函數(shù)執(zhí)行完畢,則定時(shí)器停止。
周期性模式
周期定時(shí)器在時(shí)間到期執(zhí)行完回調(diào)函數(shù)后,重新開始計(jì)時(shí),直到下次時(shí)間到期,再次執(zhí)行回調(diào)函數(shù),然后一直循環(huán)下去。
定時(shí)器任務(wù)
為了在定時(shí)器創(chuàng)建、刪除、啟動、停止以及參數(shù)并更的過程中,避免鎖操作,系統(tǒng)采用一個(gè)定時(shí)器任務(wù)來處理這些操作。當(dāng)應(yīng)用程序調(diào)用定時(shí)器管理接口時(shí),將接口調(diào)用命令發(fā)送到一個(gè)消息隊(duì)列,定時(shí)器任務(wù)從消息隊(duì)列中讀取消息并處理該命令。 定時(shí)器任務(wù)除了處理命令外,還對當(dāng)前已運(yùn)行的定時(shí)器進(jìn)行實(shí)時(shí)調(diào)度。所有正在運(yùn)行的定時(shí)器會被掛接到g_timer_head鏈表,定時(shí)器任務(wù)循環(huán)的從g_timer_head鏈表中取出時(shí)間最近一次的定時(shí)器,通過當(dāng)前tick計(jì)數(shù)和該定時(shí)器的超時(shí)tick數(shù)來判斷定時(shí)時(shí)間是否到,如果該定時(shí)器觸發(fā)時(shí)間已到則立即執(zhí)行其處理函數(shù),否則代表最近一次的定時(shí)器時(shí)間尚未到來,則在此時(shí)差,繼續(xù)從命令buffer中收取消息,直到時(shí)間差到來后,再立即執(zhí)行定時(shí)器處理函數(shù)。 上述流程在g_timer_head中有待處理定時(shí)器時(shí)才會進(jìn)入,如果沒有待處理定時(shí)器,在定時(shí)器任務(wù)將只會進(jìn)入定時(shí)器管理循環(huán)中。
定時(shí)器管理函數(shù)
函數(shù)名 | 描述 |
aos_timer_create() | 定時(shí)器創(chuàng)建函數(shù)(推薦) |
aos_timer_new() | 定時(shí)器創(chuàng)建函數(shù)(兼容3.1) |
aos_timer_new_ext() | 定時(shí)器創(chuàng)建函數(shù) |
aos_timer_free() | 定時(shí)器刪除函數(shù) |
aos_timer_start() | 定時(shí)器啟動函數(shù) |
aos_timer_stop() | 定時(shí)器停止函數(shù) |
aos_timer_change() | 定時(shí)器初始時(shí)長和周期間隔參數(shù)變更函數(shù) |
aos_timer_change_once() | 定時(shí)器初始時(shí)長參數(shù)變更函數(shù) |
aos_timer_gettime() | 獲取定時(shí)器時(shí)間參數(shù)函數(shù) |
常用配置
軟件定時(shí)器功能:默認(rèn)使能,如需修改,在YAML中修改RHINO_CONFIG_TIMER配置
def_config:
RHINO_CONFIG_TIMER: 0
軟件定時(shí)器任務(wù)棧:默認(rèn)200Bytes,如需修改,在YAML中修改RHINO_CONFIG_TIMER_TASK_STACK_SIZE配置
def_config:
RHINO_CONFIG_TIMER_TASK_STACK_SIZE: 512
軟件定時(shí)器任務(wù)優(yōu)先級:默認(rèn)5,如需修改,在YAML中修改RHINO_CONFIG_TIMER_TASK_PRI配置
def_config:
RHINO_CONFIG_TIMER_TASK_PRI: 5
定時(shí)器消息隊(duì)列消息數(shù):默認(rèn)20,如需修改,在YAML中修改RHINO_CONFIG_TIMER_MSG_NUM配置
def_config:
RHINO_CONFIG_TIMER_MSG_NUM: 24
每秒tick數(shù):默認(rèn)100,如需修改,在YAML中修改RHINO_CONFIG_TICKS_PER_SECOND配置
def_config:
RHINO_CONFIG_TICKS_PER_SECOND: 1000
時(shí)間片:默認(rèn)50個(gè)tick,如需修改,在YAML中修改RHINO_CONFIG_TIME_SLICE_DEFAULT配置
def_config:
RHINO_CONFIG_TIME_SLICE_DEFAULT: 100
API說明
使用示例
示例代碼參考example/timer_example.c,該示例使用定時(shí)器管理函數(shù)來控制定時(shí)器的執(zhí)行,具體場景為創(chuàng)建一個(gè)周期性定時(shí)器,定時(shí)調(diào)用回調(diào)函數(shù)執(zhí)行,停止定時(shí)器該變定時(shí)器的時(shí)間參數(shù),則定時(shí)器按照修改后的時(shí)間間隔定時(shí)調(diào)用回調(diào)函數(shù)執(zhí)行。
示例說明如下:
t0時(shí)刻,測試任務(wù)調(diào)用aos_timer_create()創(chuàng)建一個(gè)周期性的定時(shí)器,周期間隔為1秒,回調(diào)函數(shù)為timer1_func。然后測試任務(wù)調(diào)用aos_sleep()進(jìn)入休眠狀態(tài)。
t1時(shí)刻,相對t0過去1秒,定時(shí)器到期,回調(diào)函數(shù)timer1_func被執(zhí)行。該過程重復(fù)10次。
tn時(shí)刻,測試任務(wù)休眠到期,調(diào)用aos_timer_stop()停止定時(shí)器。然后調(diào)用aos_timer_change()接口修改周期間隔為2秒。
tn+1時(shí)刻,相對tn過去2秒,定時(shí)器到期,回調(diào)函數(shù)timer1_func被執(zhí)行。該過程重復(fù)5次。
該示例可配置到helloworld_demo中運(yùn)行,相關(guān)代碼的下載、編譯和固件燒錄均依賴AliOS Things配套的開發(fā)工具 ,所以首先需要參考《AliOS Things集成開發(fā)環(huán)境使用說明之搭建開發(fā)環(huán)境》,下載安裝 。 待開發(fā)環(huán)境搭建完成后,可以按照以下步驟進(jìn)行示例的測試。
步驟1 創(chuàng)建或打開工程
打開已有工程
如果用于測試的案例工程已存在,可參考《AliOS Things集成開發(fā)環(huán)境使用說明之打開工程》打開已有工程。
創(chuàng)建新的工程
組件的示例代碼可以通過編譯鏈接到AliOS Things的任意案例(solution)來運(yùn)行,這里選擇helloworld_demo案例。helloworld_demo案例相關(guān)的源代碼下載可參考《AliOS Things集成開發(fā)環(huán)境使用說明之創(chuàng)建工程》。
步驟2 添加組件
helloworld_demo組件的package.yaml中添加
depends:
- osal_aos: dev_aos # helloworld_demo中引入osal_aos組件
步驟3 下載組件
在已安裝了的開發(fā)環(huán)境工具欄中,選擇Terminal -> New Terminal啟動終端,并且默認(rèn)工作路徑為當(dāng)前工程的workspace,此時(shí)在終端命令行中輸入:
aos install osal_aos
上述命令執(zhí)行成功后,組件源碼則被下載到了./components/osal_aos路徑中。
步驟4 添加示例
osal_aos組件的package.yaml中添加example示例代碼:
depends:
- rhino: dev_aos
- cli: dev_aos # 添加cli依賴
source_file:
- "*.c"
- "example/timer_example.c" # 添加 timer_example.c
步驟5 編譯固件
在示例代碼已經(jīng)添加至組件的配置文件,并且helloworld_demo已添加了對該組件的依賴后,就可以編譯helloworld_demo案例來生成固件了,具體編譯方法可參考《AliOS Things集成開發(fā)環(huán)境使用說明之編譯固件》。
步驟6 燒錄固件
helloworld_demo案例的固件生成后,可參考《AliOS Things集成開發(fā)環(huán)境使用說明之燒錄固件》來燒錄固件。
步驟7 打開串口
固件燒錄完成后,可以通過串口查看示例的運(yùn)行結(jié)果,打開串口的具體方法可參考《AliOS Things集成開發(fā)環(huán)境使用說明之查看日志》。
當(dāng)串口終端打開成功后,可在串口中輸入help來查看已添加的測試命令。
步驟8 測試示例
CLI命令行輸入:
timer_example
關(guān)鍵日志:
[aos_timer_example]timer expires 10 times
[aos_timer_example]timer expires 5 times
注意事項(xiàng)
tick是內(nèi)核調(diào)度和延遲操作的基礎(chǔ),所以RHINO_CONFIG_TICKS_PER_SECOND參數(shù)必須配置,而定時(shí)器是基于tick實(shí)現(xiàn)的軟件定時(shí)器功能,可以通過配置RHINO_CONFIG_TIMER參數(shù)來使能或關(guān)閉該功能。
FAQ
Q1: 定時(shí)器回調(diào)函數(shù)的執(zhí)行上下文是在哪里?
答:定時(shí)器回調(diào)函數(shù)是在定時(shí)器任務(wù)中執(zhí)行的,所以定時(shí)器回調(diào)函數(shù)的執(zhí)行上下文為定時(shí)器任務(wù),當(dāng)回調(diào)函數(shù)所需棧空間超過定時(shí)器任務(wù)棧大小時(shí),用戶需要通過配置 RHINO_CONFIG_TIMER_TASK_STACK_SIZE參數(shù)來增加棧大小。