欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 24433|回復: 0
打印 上一主題 下一主題
收起左側

uC/OS-II學習筆記—任務的調度和多任務的啟動

[復制鏈接]
跳轉到指定樓層
樓主
  uC/OS-II操作系統是實時操作系統,而且是基于優先級調度的實時操作系統,因此在啟動多任務以后,每個時鐘中斷都要執行任務的調度。至于如何實現時鐘中斷,對于不同硬件環境是不同的。如果時間片是20ms,那么每20ms執行一次任務調度。這個任務調度的函數就是OSTimeTick。OSTimeTick是與硬件無關的,代碼如下所示:






從操作系統的初始化函數OSInit來看,我們創建的第一個任務是空閑任務。然后每次創建的新任務都是將該任務的TCB插入到就緒鏈表的表頭,而空閑任務不允許被刪除。因此,在就緒鏈表中,最后一個TCB永遠是空閑任務的。所以,while循環從就緒鏈表的表頭開始,一直到空閑任務為止,遍歷了除空閑任務之外的所有任務。
OSTCBStat中的各個位的意義如下所示:


在這里,看到了我們熟悉的掛起,在從低到高的第4位,如果從0位開始算,是位3。
相關的宏定義如下所示:


因此


很明顯,只要任務在等待任何一個事件發生,那么OS_STAT_PEND_ANY的值都不會是OS_STAT_RDY。因此,這個條件判斷語句的含義就是,如果任務在等待任何一個事件的發生(信號量、郵箱、隊列、互斥信號量、標志),就執行下面的操作,判斷是否延遲結束等。 任務可能因為等待事件而處于阻塞態,但是阻塞態的任務的控制塊仍然在就緒鏈表中,而并非由一個阻塞鏈表。任務等待事件發生的時候,可以設定或不設定超時時間。如果設定了超時時間,那么時間到了就算事件仍沒有發生,也不再等待了,這樣可以避免死等。
因此,結合帶啊,調度器遍歷每個任務,如果任務被設置了時間延時,那么就將延時時間減1.不論是等待事件發生的任務,還是單純等待一段時間的任務,只要不是被掛起的任務,延時時間到了就要使任務進入就緒態。使任務進入就緒態的方法也就是就緒組和就緒表的操作。
OSTimeTick在每個時間片開始的時候有規律地被操作系統調用,將對延時的任務修改延時時間,然后設置哪些任務就緒,但是還沒有真正進入任務的切換。
就緒的任務獲得CPU才能運行。任務切換函數就是執行這樣的操作系統服務功能:如果正在運行的任務不是優先級最高的或即將被阻塞,需要選擇一個優先級最高的就緒的任務運行。該過程中非常重要的一點是,要保留正在運行的上下文,也就是運行環境,如cPU寄存器的值,以便在任務重新開始運行之前能恢復CPU寄存器的值。當然還要將要運行任務的上下文恢復到CPU寄存器。
因此,任務切換函數式設計硬件操作,是和CPU類型密切相關的,因此對不同的系統,實現的代碼必然不同。任務切換函數是OS_Sched,在OS_Sched中還要調用與CPU無關的函數OS_SchedNew和與CPU密切相關的代碼OS_TASK_SW。OS_Sched與OS_SchedNew寫在os_core.c中,與CPU密切相關的代碼OS_TASK_SW則寫在os_cpu.c中。
首先來看一下OS_SchedNew,這個函數被其他uC/OS-II系統服務調用,用來確定最高優先級的就緒任務。該函數運行的結果就是給全局變量OSPrioHighRdy賦值。顯然,OSPrioHighRdy是最高的優先級任務。
代碼如下所示:

代碼很簡單,找到優先級最高的就緒任務,將該任務的優先級賦值給OSPrioHighRdy。
在OS_Sched代碼中將調用OS_SchedNew來找到最高優先級的任務。
代碼如下所示:


可見,OS_Sched首先判斷是否可以進行任務切換,如果中斷服務程序沒有完成,或者是調度器被上鎖,或當前運行的任務正是優先級最高的,那么都不會進行任務切換。當需要進行任務切換時,OS_Sched首先增加將要被換入CPU的任務的被調用次數OSTCBCtxSwCtr,然后是整個操作系統的任務切換的次數OSCtxSwCtr。最后調用OS_TASK_SW完成任務切換。從中可以看出,OS_TASK_SW應該是真正進行任務切換的地方。
一切都準備好了,將進行任務的最終切換,OS_TASK_SW首先將CPU寄存器中的內容壓入被換出的任務的堆棧中,然后將被換入的任務的堆棧中的內容彈出到CPU寄存器。需要知道的是,這些寄存器是任務運行的環境,在任務被換出,再換回繼續執行的時候,寄存器的值不能發生變化,否則程序的運行會產生錯誤的結果,有些結果甚至是災難性的。
OS_TASK_SW的代碼實現如下所示:


可以看到OS_TASK_SW()等同于OSCtxSw()。OSCtxSw的定義如下所示:


可以看出這是一段匯編代碼,執行的主要操作是觸發PendSV中斷,那接下來看一下PendSV中斷的服務程序:


PendSV中首先關閉中斷,然后判斷PSP的值是不是0,如不是0就將沒有自動保存的寄存器r4~r11壓入到堆棧中,然后將PSP的值更新到OSTCBCur->OSTCBStkPtr中。如果是0就說明之前沒有任務運行,所以不要保存。然后調用OSTaskSwHook()。然后執行OSPrioCur = OSPrioHighRdy;然后執行OSTCBCur  = OSTCBHighRdy; 然后取得最高優先級任務的TCB,進而得到它的堆棧地址。然后把R4~R11的值從堆棧中恢復。然后,更新PSP的值。然后將LR的bit3置位,然后使能中斷,最后中斷返回。
uC/OS-II作為實時多任務操作系統,在每個時鐘滴答進入時鐘中斷服務程序,如果有比目前運行的任務更高優先級的任務就緒,在需要的時候進行一次任務調度。這個任務調度函數并不是前面的OS_Sched,而是OSIntExit。
在時鐘中斷的時候,緊接著OSTimeTick,操作系統調用OSIntExit實現任務的切換,程序如下所示:


可見,OSIntCtxSw()才是真正在中斷程序中進行實際的任務切換的地方,OSIntExit與OSSched類似,進行了全局變量的配置,決定是否進行任務切換。那么OSIntCtxSw很明顯也將在os_cpu.c中實現,原因是也要進行與CPU密切相關的操作,相關程序如下所示:


可見,在中斷處理過程中的任務切換和普通的任務切換時相同的。
多任務啟動的代碼是內核中的OSStart函數,在運行OSStart之前,必須已經執行了操作系統初始化函數OSInit,并且至少創建了1個以上的任務。OSStart的代碼如下所示:


可見,OSStart先找到優先級最高的就緒任務,然后對OSPrioCur賦值為該任務的優先級,將OSTCBHighRdy及OSTCBCur賦值為該任務的TCB地址,之后就調用OSStartHighRdy來啟動多任務。因此,核心的代碼還在OSStartHighRdy。OSStartHighRdy啟動多任務又是和硬件有關的,因此該代碼在os_cpu.c中,對于不同的硬件平臺,該代碼必然不同。


匯編的代碼和恢復任務的時候如初一輒,從堆棧中取出任務的地址運行任務!而任務的地址在創建任務時的堆棧初始化的時候已經準備好了。啟動任務就是先將設置PendSV,然后將PSP清零,然后將OSRunning設置為真表示進入多任務,然后觸發PendSV,然后由PendSV中斷服務程序來執行相關的任務切換。

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表