freertos(第五課 softtimer)

freertos提供了soft timer,需要爲softtimer掛接callback,當時間到達後,就會觸發callback執行。
callback在timer的服務任務中執行的,所以,不能使用可能阻塞任務的API。
一般使用SysTick作爲softtimer的基礎時鐘。
兩次觸發callback的時間間隔xTimerPeriodInTicks叫做定時週期。

freertos通過一個prvTimerTask任務(Daemon Task)管理softtimer。這個任務是在啓動調度器時,自動創建的。
Daemon Task 會在執行期間,輪詢軟件定時器,如果滿足條件,則調用callback。

#define configUSE_TIMERS 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTICK_RATE_HZ 1000

這兩個配置宏,使能了軟件定時器,並設置了TICK。

類似於linux中的jiffies,freertos中,也會維護一個全局變量xTickCount,作爲系統時間。
當用戶創建一個softtimer時,freertos會根據用戶設置的定時數,在當前jiffies上後延設置的定時數,並填充到softtimer的喚醒時間中。然後將softtimer的控制塊插入軟件定時器列表。
freertos維護了兩個TIMERLIST。
pxCurrentTimerList, pxOverflowTimerList。
新創建的SoftTimer,會以jiffies升序的順序,插入pxCurrentTimerList.
DaemonTask在運行時,會按順序掃描pxCurrentTimerList,如果首元超時,則調用首元對應的Callback,如果首元都沒有超時,那麼其他定時器也一定沒有超時,所以這時,DaemonTask掛起。
pxOverflowTimerList作用與之一致。

編寫軟件定時器的callback時,應該快進快出,不允許阻塞DaemonTask,更不允許死循環。
DaemonTask的任務優先級應該儘量高,從而獲得更好的時間響應度。
單次軟件定時器的Callback被執行完並返回後,系統會自動刪除TIMER,並回收資源。

用戶程序通過Timer command queue和 Daemon Task進行通信。
在用戶程序中,使用TIMER API,freertos負責將一個command發送到Timer command queue中,當DaemonTask運行時,從command queue中獲取命令。

#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH
#define configTIMER_STACK_DEPTH

這幾個宏,用來配置DaemonTask。

來看看TIMER的控制塊。

typedef struct tmrTimerControl{
	const char* pcTimerName;
	ListItem_t xTimerListItem;
	TickType_t xTimerPeriodInTicks;
	UBaseType_t uxAutoReload;

	TimerCallbackFunction_t pxCallbackFunction;
	void* pvTimerID;
}xTIMER;
typedef xTIMER Timer_t;

在xTimerListItem的value中,存放喚醒時間jiffies。

來看看TIMER API。
1)創建。
xTimerCreate(),動態創建一個TIMER對象,並返回句柄。

TimerHandle_t 
xTimerCreate(
			const char* const pcTimerName,
			const TickType_t xTimerPeriodInTicks,
			void * const pvTimerID,
			TimerCallbackFunction_t pxCallbackFunction
			);

2)啓動。
xTimerStart,將TIMER啓動,並添加到ACTIVELIST中。

BaseType_t xTimerStart(TimerHandle_t xTimer, TickType_t xBlockTime);

BaseType_t 
xTimerStartFromISR(
		TimerHandle_t xTimer, 
		BaseType_t* pxHigherPriorityTaskWoken
		);

3)停止。
xTimerStop,將TIMER停止,並從ACTIVELIST中移除。

BaseType_t xTimerStop(TimerHandle_t xTimer, TickType_t xBlockTime);

BaseType_t 
xTimerStopFromISR(
		TimerHandle_t xTimer, 
		BaseType_t* pxHigherPriorityTaskWoken
		);

4)復位。
xTimerReset,用來複位TIMER。

BaseType_t xTimerReset(TimerHandle_t xTimer, TickType_t xTicksToWait);

BaseType_t 
xTimerResetFromISR(
		TimerHandle_t xTimer, 
		BaseType_t* pxHigherPriorityTaskWoken
		);

5)刪除。

BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xTicksToWait);

來看一個具體的例子。

static TimerHandle_t Swtmr1_Handle = NULL;
static TmerHandle_t Swtmr2_Handle = NULL;

// in apptask
Swtmr1_Handle = xTimerCreate(
			(const char*)"AutoReloadTimer",
			(TickType_t)1000,
			(UBaseType_t)pdTRUE,
			(void*)1,
			(TimerCallbackFunction_t)Swtmr1_Callback 
	);

if(Swtmr1_Handle != NULL){
	xTimerStart(Swtmr1_Handle, 0);
}

Swtmr2_Handle = xTimerCreate(
			(const char*)"OneShotTimer",
			(TickType_t)5000,
			(UBaseType_t)pdFALSE,
			(void*)2,
			(TimerCallbackFunction_t)Swtmr2_Callback 
	);

if(Swtmr2_Handle != NULL){
	xTimerStart(Swtmr2_Handle, 0);
}

static void Swtmr1_Callback(void* parameter)
{
	TmrCb_Count1++;
	return;
}

static void Swtmr2_Callback(void* parameter)
{
	TmrCb_Count2++;
	return;
}

對於系統中,一些基於時間事件驅動的操作和行爲,用TIMER是比較合適的。
系統負責管理時間點,開發者只需要關注於TIMEEVENT ACTION。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章