UCOSII從V2.83版本以後,加入了軟件定時器,這使得UCOSII的功能更加完善,在其上的應用程序開發與移植也更加方便。在實時操作系統中一個好的軟件定時器實現要求有較高的精度、較小的處理器開銷,且佔用較少的存儲器資源。
ucosII關於定時器的內容在os_tmr.c文件內,需使能os_cfg.h中的OS_CFG_TMR_EN來啓動定時器服務。
定時器服務爲在協議棧處理,IO定時輪詢的設備中提供了很大的方便。
1)軟件定時器工作原理
軟件定時器同樣由OSTimTick提供時鐘,但是軟件定時器的時鐘還OS_TMR_CFG_TICKS_PER_SEC設置的控制,也就是在UCOSII的時鐘節拍上面再做了一次“分頻”,軟件定時器的最快時鐘節拍就等於UCOSII的系統時鐘節拍。這也決定了軟件定時器的精度。
定時時間一到,則系統會調用用戶函數實現特定功能。
2)軟件定時器在ucos_ii的實現原理
UCOSII中軟件定時器的實現方法是,將定時器按定時時間分組,使得每次時鐘節拍到來時只對部分定時器進行比較操作,縮短了每次處理的時間。但這就需要動態地維護一個定時器組。定時器組的維護只是在每次定時器到時時才發生,而且定時器從組中移除和再插入操作不需要排序。這是一種比較高效的算法,減少了維護所需的操作時間。
UCOSII軟件定時器實現了3類鏈表的維護:
OS_EXT OS_TMR OSTmrTbl[OS_TMR_CFG_MAX]; //定時器控制塊數組
OS_EXT OS_TMR *OSTmrFreeList; //空閒定時器控制塊鏈表指針
OS_EXT OS_TMR_WHEEL OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE]; //定時器輪
其中OS_TMR爲定時器控制塊,定時器控制塊是軟件定時器管理的基本單元,包含軟件定時器的名稱、定時時間、在鏈表中的位置、使用狀態、使用方式,以及到時回調函數及其參數等基本信息。
OSTmrTbl[OS_TMR_CFG_MAX];:以數組的形式靜態分配定時器控制塊所需的RAM空間,並存儲所有已建立的定時器控制塊,OS_TMR_CFG_MAX爲最大軟件定時器的個數。
OSTmrFreeLiSt:爲空閒定時器控制塊鏈表頭指針。空閒態的定時器控制塊(OS_TMR)中,OSTmrNext和OSTmrPrev兩個指針分別指向空閒控制塊的前一個和後一個,組織了空閒控制塊雙向鏈表。建立定時器時,從這個鏈表中搜索空閒定時器控制塊。
OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE]:該數組的每個元素都是已開啓定時器的一個分組,元素中記錄了指向該分組中第一個定時器控制塊的指針,以及定時器控制塊的個數。運行態的定時器控制塊(OS_TMR)中,OSTmrNext和OSTmrPrev兩個指針同樣也組織了所在分組中定時器控制塊的雙向鏈表。軟件定時器管理所需的數據結構示意圖如圖所示
如果使能了定時器服務,在ucos初始化的時候,系統便自動創建了一個任務OSTmr_Task(),每次節拍到達便判斷相應定時輪中定時器的定時是否到達,如果到達則調用相應的回調函數。
3)軟件定時器在ucosII的實現過程
軟件定時器由硬件定時器提供基準Tr,可以通過宏定義OS_TMR_CFG_TICKS_PER_SECOND對硬件定時器節拍進行分頻即軟件定時器時鐘節拍爲 Tr*OS_TMR_CFG_TICKS_PER_SECOND。
硬件定時器節拍時刻到後觸發中斷。如果使能了定時器服務,在SysTic_Handler()中斷函數中通過一系列調用,最後到執行到OSTimeTickhook()函數,在該函數中會判斷該時刻是否是軟件定時器的節拍時刻,如果是,則通過釋放一個信號量OSTmrSemSignal來激活正在等待改信號量的OSTmrTask()任務。
在ucos初始化的時候,系統便自動創建了一個任務OSTmr_Task(),其優先級,堆棧大小等於任務相關的參數在os_cfg.h中定義。在OSTmr_Task()任務中等待OSTmrSemSignal信號量。並定義了一個變量OSTimTick來計時軟件定時器的節拍。OSTmrSemSignal信號量一旦有效OSTimTick便加1並判斷相應定時輪中定時器的定時是否到達,如果到達則調用相應的回調函數完成定時器操作。
4)使用軟件定時器
在ucos_ii.h中,聲明瞭下面8個函數供用戶使用。
OSTmrCreate();
OSTmrDel();
OSTmrNameGet();
OSTmrRemainGet();
OSTmrStateGet();
OSTmrStart();
OSTmrStop();
OSTmrSignal();
1、定時器任務參數配置
定時任務有OSInit()在初始化時創建,其優先級,堆棧大小等於任務相關的參數在os_cfg.h中定義。用戶可通過項目實際需求修改相應參數。
2、創建定時器
OS_TMR *OSTmrCreate (INT32U dly,
INT32U period,
INT8U opt,
OS_TMR_CALLBACK callback,
void *callback_arg,
INT8U *pname,
INT8U *perr)
3、編寫回調函數
typedef void (*OS_TMR_CALLBACK)(void *ptmr, void *parg);
4、啓動定時器
BOOLEAN OSTmrStart ( OS_TMR *ptmr,
INT8U *perr)
5、關於回調函數
回調函數執行時所用到的堆棧是是定時器任務堆棧,所以要確保分配的定時器任務堆棧大小能夠滿足回調函數的堆棧要求回調函數的執行是根據它們在定時器鏈表中的位置先後執行(一個定時器只能執行一個回調函數)。
定時器任務的執行時間極大程度是有溢出的定時器個數和回調函數執行時間決定。回調函數執行期間,調度是處於被鎖狀態,所以回調函數越快執行越好,更不要去在回調函數中去等待事件。