osal_start_timerEx是一個用來設置定時器,使某任務能夠定時運行的函數。但是想要了解這個函數,需要層層上推,瞭解到更深層次,才能夠明白它工作的原理。
首先了解一下osal_start_timerEx函數的原型:
uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
halIntState_t intState;
osalTimerRec_t *newTimer;
HAL_ENTER_CRITICAL_SECTION( intState );
newTimer = osalAddTimer( taskID, event_id, timeout_value ); //添加新定時器
HAL_EXIT_CRITICAL_SECTION( intState );
return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL );
}
其中,參數的含義是:
taskID:要設定定時器的任務ID號;
event_id:事件的類型(我的理解是要設定定時器的事件是個什麼類型的事件);
timeout_value:定時時間,即發送週期信息的時間週期。
函數裏需要注意的是osalAddTimer函數,這個函數的功能就是添加一個新定時器。但是新的定時器添加到哪裏了呢?我們先來了解一下定時器的數據結構:
typedef struct
{
void *next;
uint16 timeout;
uint16 event_flag;
uint8 task_id;
uint16 reloadTimeout;
} osalTimerRec_t;
數據結構中包括timeout、event_flag、task_id和reloadTimeout,除此之外,還有一個next指針。瞭解數據結構的話都知道,這項的存在說明這個結構體能夠組成一個鏈表,因此實際上是存在一個由定時器結構體組成的鏈表,這個鏈表叫做軟件定時器數據鏈表。
因此osalAddTimer函數就是在這個鏈表中新增添了一個定時器節點,那麼這個鏈表是由哪個函數來管理的呢?是由osalTimerUpdate函數管理的。由osalTimerUpdate以ms爲單位對這些“軟定時器”減計數,當定時器溢出,即調用osal_set_event函數。Osal_set_event是專門用來設置tasksEvents,而tasksEvents數組存放了一個任務是否該被運行的序列(tasksEvents不清楚的話似乎應該先從頭學起)。
所以總結起來是這樣子的:osal_start_timerEx通過osalAddTimer向鏈表中添加定時器,由osalTimerUpdate來減計數,當這個定時器溢出後,則會對taskID對應的task設置一個event_id,從而讓這個任務在後面的主循環中運行到。能夠在主循環中運行到的原因是會調用osal_set_event函數來實現主循環裏對此項任務的調用。
舉例:
osal_start_timerEx( SampleApp_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF) );
SampleApp_TaskID:任務優先級ID,在任務初始化函數SampleApp_Init()中被初始化,ID號是由協議棧的操作系統OSAL分配;
SAMPLEAPP_SEND_PERIODIC_MSG_EVT:發送週期信息事件;
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT:定時時間,在自己的應用文件夾App中定義。
(如:#define SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT 3000 //每隔3秒)
當網絡組建成功後,每隔SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF),即3秒的時間就會去執行SAMPLEAPP_SEND_PERIODIC_MSG_EVT觸發的函數。