時間管理服務函數是以系統節拍爲處理單位的,實際的時間與希望的時間是有誤差的,最壞的情況下誤差接近一個系統節拍。因此時間管理服務函數只能用在對時間精度要求不高的場合,或者時間間隔較長的場合。
1. void OSSchedLock(void);
void OSSchedLock (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
if (OSRunning == OS_TRUE) { /* Make sure multitasking is running */
OS_ENTER_CRITICAL();
if (OSIntNesting == 0) { /* Can't call from an ISR */
if (OSLockNesting < 255u) { /* Prevent OSLockNesting from wrapping back to 0 */
OSLockNesting++; /* Increment lock nesting level */
}
}
OS_EXIT_CRITICAL();
}
}
這個函數又叫上鎖函數,如果在一個任務裏面調用了上鎖函數,那麼OSSched()這個任務切換函數就不會執行也就是說不會進任務調度。
調用OSSchedLock()以後,用戶的應用程序不得使用任何能將現行任務掛起的系統調用。也就是說,用戶程序不得調用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或OSTimeDlyHMSM(),直到OSLockNesting回零爲止。因爲調度器上了鎖,用戶就鎖住了系統,任何其它任務都不能運行。
但是上鎖了任務是可以中斷,若任務遇到中斷,則中斷函數的執行會爲OSIntNesting變量加1,當中斷返回時又要判斷OSLockNesting是否爲0,如果不爲0說明系統仍被鎖,直接退出中斷。如果OSLockNesting爲0說明系統未被鎖,CPU進入任務就緒表查找優先級最高的任務。所以上鎖函數執行後,CPU一直處於當前任務與中斷服務函數之間的運行,直到解鎖函數將OSLockNesting和OSIntNesting的值減到0時,方可解除系統鎖定。
OSSchedUnlock() 取消函數上鎖。
2.void OSTimeDly (INT16U ticks);
void
OSTimeDly (INT16U ticks)
{
INT8U y;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
if (OSIntNesting > 0) { /* See if trying to call from an ISR */
return;
}
if (ticks > 0) { /* 0 means no delay! */
OS_ENTER_CRITICAL();
y = OSTCBCur->OSTCBY; /* Delay current task */
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /*取消當前任務的就緒狀態
}
OSTCBCur->OSTCBDly = ticks; /* 延時節拍數存入任務控制塊TCB */
OS_EXIT_CRITICAL();
OS_Sched(); /* 調度函數 */
}
}
將一個任務延時若干個時鐘節拍。如果延時時間大於0,系統將立即進行任務調度。延時時間的長度可從0到65535個時鐘節拍。延時時間0表示不進行延時,函數將立即返回調用者。延時的具體時間依賴於系統每秒鐘有多少時鐘節拍(由文件OS_CFG.H中的常量OS_TICKS_PER_SEC設定):
#define OS_TICKS_PER_SEC 1000
調用該函數會使uCOS-II進行一次任務調度,並且執行下一個優先級最高的就緒態任務。任務調用OSTimeDly()後,一旦規定的時間期滿或者有其它的任務通過調用OSTimeDlyResume()取消了延時,它就會馬上進入就緒狀態。注意,只有當該任務在所有就緒任務中具有最高的優先級時,它纔會立即運行。
3.INT8U
OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U ms);
這個函數是以小時(H)、分(M)、秒(S)和毫秒(m)四個參數來定義延時時間的,函數在內部把這些參數轉換爲時鐘節拍,再通過單次或多次調用OSTimeDly()進行延時和任務調度,所以延時原理和調用延時函數OSTimeDly()是一樣的。
4.INT8U OS_TCBInit(INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt);
任務控制塊初始化
描述:這個函數是uCOS-II內部函數,在建立任務時調用的初始化任務控制塊OS_TCB函數,含7個參數,查看OSTaskCreate()和OSTaskCreateExt()
初始化任務控制塊TCB(優先級指針,堆棧指針,棧底指針,任務標誌符,堆棧容量,擴展指針,選擇項)
INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
{
#if OS_CRITICAL_METHOD == 3 //中斷函數被設定爲模式3
OS_CPU_SR cpu_sr;
- #endif
- OS_TCB *ptcb; //定義一個PCB變量
- OS_ENTER_CRITICAL(); //關閉中斷
- ptcb = OSTCBFreeList; //分配一個空任務控制塊給ptcb
- if (ptcb != (OS_TCB *)0) { //如果緩衝池有空餘TCB,這個TCB被初始化
- OSTCBFreeList = ptcb->OSTCBNext; //指向TCB的雙向鏈接的後鏈接
- OS_EXIT_CRITICAL(); //打開中斷
- ptcb->OSTCBStkPtr = ptos; //指向當前TCB的棧頂指針(輸入的數據)
- ptcb->OSTCBPrio = (INT8U)prio; //保存當前TCB的優先級別(輸入的數據)
- ptcb->OSTCBStat = OS_STAT_RDY; //設定當前TCB的狀態字(內容爲(準備完畢))
- ptcb->OSTCBDly = 0; //允許任務等待的最大字節節拍爲0
- #if OS_TASK_CREATE_EXT_EN > 0 //允許生成OSTaskCreateExt()函數
- ptcb->OSTCBExtPtr = pext; //指向用戶定義的任務控制塊(擴展指針)
- ptcb->OSTCBStkSize = stk_size; //設定堆棧的容量
- ptcb->OSTCBStkBottom = pbos; //指向堆棧棧底的指針
- ptcb->OSTCBOpt = opt; //保存OS_TCB的選擇項
- ptcb->OSTCBId = id; //保存任務標誌符
- #else //否則使用舊的參數
- pext = pext; //擴展指針
- stk_size = stk_size; //堆棧的容量
- pbos = pbos; //棧底的指針
- opt = opt; //選擇項
- id = id; //任務標誌符
- #endif
- #if OS_TASK_DEL_EN > 0 //允許生成OSTaskDel()函數代碼函數
- ptcb->OSTCBDelReq = OS_NO_ERR; //如果可以刪除任務本身,可以從每個OS_TCB中節省出一個布爾量
- #endif
- ptcb->OSTCBY = prio >> 3; //對一些參數提前運算,爲了節省CPU的操作事件
- ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
- ptcb->OSTCBX = prio & 0x07;
- ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
- #if OS_EVENT_EN > 0 //如果不打算在應用程序中使用各類事件
- ptcb->OSTCBEventPtr = (OS_EVENT *)0; //OS_TCB中OSTCBEventPtr就不會出現
- #endif
- //針對的事件爲信號量,互斥型信號量,消息郵箱,消息隊列,當滿足版本大於2.51且事件標誌允許且有最大事件標誌及允許刪除任務
- #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
- ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; //則向事件標誌節點的指針被初始化爲空指針
- #endif
- #if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
- ptcb->OSTCBMsg = (void *)0; //滿足以上條件,指向傳遞給任務的消息指針爲0空指針
- #endif
- #if OS_VERSION >= 204 //如果版本大於2.04
- OSTCBInitHook(ptcb); //允許使用OSTCBInitHook(ptcb)函數,可對其加代碼
- #endif //主要增加OS_TCB擴展,浮點運算,MMU寄存器,與任務相關內容,調用此程序時中斷開着的
- OSTaskCreateHook(ptcb); //調用戶建立任務鉤子程序
- OS_ENTER_CRITICAL();
- OSTCBPrioTbl[prio] = ptcb;
- ptcb->OSTCBNext = OSTCBList; //鏈接到任務控制塊鏈接串
- ptcb->OSTCBPrev = (OS_TCB *)0;
- if (OSTCBList != (OS_TCB *)0) {
- OSTCBList->OSTCBPrev = ptcb;
- }
- OSTCBList = ptcb; //讓該任務進入就緒表
- OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */
- OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- OS_EXIT_CRITICAL(); //打開中斷
- return (OS_NO_ERR); //調用成功,最後讓此函數返回到調用函數[OSTaskCreate()或OSTaskCreateExt()函數],
- //返回值表示分配到任務控塊,並初始化了
- }
- OS_EXIT_CRITICAL(); //打開中斷
- return (OS_NO_MORE_TCB); //沒有更多的任務控制塊被分配,將無法創建新的任務
- }
5.INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio);
- //建立一個新任務
- #if OS_TASK_CREATE_EN > 0 //允許生成OSTaskCreate()函數
- INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
- {
- #if OS_CRITICAL_METHOD == 3 //中斷函數被設定爲模式3
- OS_CPU_SR cpu_sr;
- #endif
- OS_STK *psp; //初始化任務堆棧指針變量,返回新的棧頂指針
- INT8U err; //定義(獲得並定義初始化任務控制塊)是否成功
- #if OS_ARG_CHK_EN > 0 //所有參數必須在指定的參數內
- if (prio > OS_LOWEST_PRIO) { //檢查任務優先級是否合法
- return (OS_PRIO_INVALID); //參數指定的優先級大於OS_LOWEST_PRIO
- }
- #endif
- OS_ENTER_CRITICAL(); //關閉中斷
- if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //確認優先級未被使用,即就緒態爲0
- OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留這個優先級,將就緒態設爲1
- OS_EXIT_CRITICAL(); //打開中斷
- psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); //初始化任務堆棧
- err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); //獲得並初始化任務控制塊
- if (err == OS_NO_ERR) { //任務控制初始化成功
- OS_ENTER_CRITICAL(); //關閉中斷
- OSTaskCtr++; //任務計數器加1
- OS_EXIT_CRITICAL(); //打開中斷
- if (OSRunning == TRUE) { //檢查是否有(某個)任務在運行
- OS_Sched(); //任務調度,最高任務優先級運行
- }
- } else { //否則,任務初始化失敗
- OS_ENTER_CRITICAL(); //關閉中斷
- OSTCBPrioTbl[prio] = (OS_TCB *)0; //放棄任務,設此任務就緒態爲0
- OS_EXIT_CRITICAL(); //打開中斷
- }
- return (err); //返回(獲得並定義初始化任務控制塊是否成功)
- }
- OS_EXIT_CRITICAL(); //打開中斷
- return (OS_PRIO_EXIST); //返回(具有該優先級的任務已經存在)
- }
- #endif
6.static void OS_InitTaskStat (void) ;
- //創建統計任務
- #if OS_TASK_STAT_EN > 0
- static void OS_InitTaskStat (void)
- {
- #if OS_TASK_CREATE_EXT_EN > 0 //允許生成OSTaskCreateExt()函數
- #if OS_STK_GROWTH == 1 //堆棧生長方向向下
- (void)OSTaskCreateExt(OS_TaskStat, //建立擴展任務;產生一個統計任務
- (void *)0, //沒有(傳遞參數指針)
- &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], //分配任務堆棧棧頂指針
- OS_STAT_PRIO, //分配任務優先級
- OS_TASK_STAT_ID, //(未來的)優先級標識(與優先級相同)
- &OSTaskStatStk[0], //分配任務堆棧棧底指針
- OS_TASK_STAT_STK_SIZE, //指定堆棧的容量(檢驗用)
- (void *)0, //沒有(指向用戶附加的數據域的指針)
- OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear */
- #else //建立擴展任務;堆棧生長方向向上
- (void)OSTaskCreateExt(OS_TaskStat, //產生一個統計任務
- (void *)0, //沒有(傳遞參數指針)
- &OSTaskStatStk[0], //分配任務堆棧棧底指針
- OS_STAT_PRIO, //分配任務優先級
- OS_TASK_STAT_ID, //(未來的)優先級標識(與優先級相同)
- &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], //分配任務堆棧棧頂指針
- OS_TASK_STAT_STK_SIZE, //指定堆棧的容量(檢驗用)
- (void *)0, //沒有(指向用戶附加的數據域的指針)
- OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear */
- #endif
- #else //否則只能生成OSTaskCreate()函數
- #if OS_STK_GROWTH == 1 //堆棧生長方向向下
- (void)OSTaskCreate(OS_TaskStat, //產生一個統計任務
- (void *)0, //沒有(傳遞參數指針)
- &OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], //分配任務堆棧棧頂指針
- OS_STAT_PRIO); //分配任務優先級
- #else //否則堆棧生長方向向上
- (void)OSTaskCreate(OS_TaskStat, //產生一個統計任務
- (void *)0, //沒有(傳遞參數指針)
- &OSTaskStatStk[0], //分配任務堆棧棧底指針
- OS_STAT_PRIO); //分配任務優先級
- #endif
- #endif
- }
- #endif
7.static void OS_InitTCBList (void);
- //初始化空閒TCB鏈表
- static void OS_InitTCBList (void)
- {
- INT8U i;
- OS_TCB *ptcb1;
- OS_TCB *ptcb2;
- OSTCBList = (OS_TCB *)0; //任務控制塊鏈接表的指針清0
- for (i = 0; i < (OS_LOWEST_PRIO + 1); i++) {
- OSTCBPrioTbl[i] = (OS_TCB *)0; //清除所有的優先級控制塊優先級列表
- }
- ptcb1 = &OSTCBTbl[0]; //查找任務控制塊列表(0)的對應地址
- ptcb2 = &OSTCBTbl[1]; //查找任務控制塊列表(1)的對應地址
- for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) {
- ptcb1->OSTCBNext = ptcb2;//釋放所有的任務控制塊列表
- ptcb1++;
- ptcb2++;
- }
- ptcb1->OSTCBNext = (OS_TCB *)0; //將最後的任務塊雙向鏈接表的後鏈接爲0
- OSTCBFreeList = &OSTCBTbl[0]; //空任務控制塊地址爲當前任務控制塊列表的首地址
- }