一、前 言
無論是學習、研究、測試和移植RTOS,隻要是想達到掌握RTOS程式設計的熟練水準,都應該深入研究一個或一組基礎的測試程式。就像要取得駕照,就要通過精心設計的N個科目的考試。
在uC/OS-II中有兩個途徑進行任務排程,一種是在中斷過程中進行的,這時調用“OSIntExit()”函數來執行排程任務(稱系統級排程),另一種是在實時任務中進行,這時調用“OS_Sched()”函數來執行排程任務(稱任務級排程)。是以基礎測試程式必須包括這兩任務排程方法程式設計。
根據RTOS工作原理,在有中斷嵌套時進行任務切換時十分不安全的,被高優先級中斷嵌套的中斷服務程式(簡稱ISR)現場在被中斷的目前任務系統堆棧中,如果這時目前任務被切換走,則被嵌套的ISR就得不到繼續執行了,隻有下次目前任務再獲得CPU執行權時該ISR才會被等到執行。這就帶來兩個不安全因素,首先如果遲遲不釋出“RETI”指令,該中斷以及比該中斷優先級低的中斷就被阻塞了,其次如果ISR沒有執行完前,程式意外地先釋出了“RETI”指令(比如在目前移植到STC8的uC/OS-II使用序列槽中斷的情況),則再次發生該中斷時ISR就被重入,将會産生不可預料的錯誤。
是以在STC單片機RTOS程式設計中,如何規範地進行中斷服務程式十分重要,RTOS測試程式除了系統中斷外,還應該包括其他使用者中斷程式。
本文結合将uC/OS-II移植到STC單片機上的過程,介紹一個ROTS的基礎測試程式,該程式包括了實時任務的系統級排程和任務級排程,包括了系統中斷和使用者中斷服務程式。該程式是開源的,相信讀者可以從中學習到許多RTOS的知識和RTOS的規範程式設計方法。
二、端口初始化和軟體延時函數
在STC單片機RTOS程式設計中,端口初始化和軟體延時是最基本和最重要的方法,下圖是本測試程式采用的端口初始化和軟體延時函數(在OS_CPU_C.c程式檔案中):
(1)對于STC8H等系列STC單片機,單片機加電時為防止端口電平處于不期望的狀态,除P3.0和P3.1外所有端口都處于高阻輸入狀态,由使用者根據具體的電路要求進行初始化。在端口的4種工作模式中,準雙向口模式與傳統的8051端口模式最相像,可以直接驅動下拉的LED燈和數位管等。另外在許多情況下,需要将端口内部的資料寄存器置為高電平才能進行正确的數字輸入輸出操作。是以在沒有特别要求的情況下,STC單片機端口初始化程式(第297到316行程式)将所有的端口都設定為準雙向口和高電平。
(2)同一段用C語言編寫的軟體延時函數程式的延時時間不但與燒錄的主頻有關,還與編譯器的優化等級和記憶體模式有關,尤其在RTOS程式中還與該函數是否可以重入有關。是以通用空循環延時程式中内循環的次數都要根據同一類程式具體調試。
上面的程式中第291行是計算每毫秒的内循環次數,其中的系數“34000”是筆者采用下面測試程式具體調試的結果。
其中第32行到第42行是軟體延時測試程式。如果注釋掉第37行,打開第36行程式(如圖)它是一個無限循環程式結構,測試時程式就在這一段中重複執行,後面的程式不會得到執行。
測試完成後将注釋掉第36行,打開第37行程式這段測試程式就成了一個LED閃三次的系統啟動LOGO程式。這個LOGO對于RTOS基礎測試程式很有用,如果系統跑飛(比如通路了一個未定義的函數)造成單片機系統從0000H位址重新開機,你就可以這個閃爍的LOGO,知道系統重新開機了。
下圖是用邏輯分析儀對P2端口的測試結果:
下面是本軟體延時測試時的效果視訊:
視訊加載中...
三、系統級排程的程式設計方法
(3)系統級排程方法。在本測試程式中任務A是采用了系統級排程方法,下圖是測試該任務的程式:
在上面任務A程式中第77行程式中使用者任務函數“OSTimeDly”是進行系統級排程程式的典型接口函數,該函數設定了要延時的Tick數後,就挂起任務自己,等待延時完成後被喚醒。
在上面“main”函數中第57行和58行程式被注釋後,隻建立了任務A,下面的視訊顯示了任務A單獨運作的情況:
視訊加載中...
(4)在uC/OS-II中每次系統中斷發生時,會調用系統時鐘函數“OSTimeTick” (OS_CORE.C檔案第889行到第958行程式)将所有等待延時的任務的延時Tick數減一,減到0的時候,就将該任務狀态設定為就緒狀态。
(5)系統級排程是指在各種中斷中(不限于系統中斷),調用系統排程(中斷中任務切換)函數“OSIntExit”(OS_CORE.C檔案第663行到第691行程式)進行任務排程。下圖是該函數程式:
該函數首先将中斷嵌套計數減1(第674行),如果還有中斷嵌套,則退出該函數,不進行任務排程,如果沒有中斷嵌套則進行任務排程,先找出目前就緒任務中優先級最高的任務(第678行),然後将CPU控制權切換給該任務(第685行)。
(6)按照uC/OS-II系統級排程程式設計規範,隻會在每次發生中斷時才會檢測目前就緒的最高優先級任務并進行任務排程,是以即使實時任務條件滿足了,也要等到下次中斷發生時才會進行任務切換。這樣系統級排程的實時任務響應時間平均為各種定時周期中斷中最小的周期間隔的二分之一。
比如RTOS包含一個異步序列槽中斷(字元間的周期可能很長)和一個系統中斷,系統中斷的周期為20毫秒,則系統級排程的平均實時任務的響應時間為10毫秒。
四、任務級排程的程式設計方法
(7)uC/OS-II RTOS可以在沒有系統中斷的情況下進行任務排程,實作多個任務的切換,這時實時任務的響應時間甚至可以比在系統中斷中進行系統級排程還要快。
比如極端情況下程式可以用循環的方式不停地檢測實時任務的切換條件,如果條件成立就立即進行任務排程,不需等待,這種情況下實時任務的響應時間可以小到微秒量級。
(8)本測試程式的任務B和任務C之間就是采用了任務級排程。首先注釋掉所有中斷設定語句和任務A,這樣就不會有任何中斷發生了,任務排程隻能是任務級排程了,注釋程式見下圖:
(9)任務B和任務C的程式見下圖:
上面程式中使用者任務函數 “OSTaskSuspend(優先級數)”和“OSTaskResume(優先級數)”是典型的任務級排程接口函數。
(10)在任務B中,第88行到93行将連接配接在P1端口的8個LED分兩半左右閃爍3次。
第94行“OSTaskResume(4)”是将任務C(優先級為4)設定為就緒狀态,然後進行任務級排程函數,由于目前任務B(優先級為4)的優先級比任務C高,是以繼續執行下一行程式。
第95行程式“OSTaskSuspend(OS_PRIO_SELF);”将任務B自己挂起(任務狀态為延時非就緒),将程式控制權交給目前就緒任務中優先級最高的任務執行。由于上一行已經将任務C設定為就緒了,是以任務C繼續執行。
(11)任務C第106行到第111行是将連接配接在P32到P37上的6個LED燈依次點亮。
任務C的第112行程式使得任務B就緒,然後進行任務級排程。由于任務B的優先級比任務C高,是以這時任務C被挂起在第112行,而控制權交給任務B,開始執行任務B上次挂起點的下一行第96行程式,重新執行P1燈閃爍。
(12)等待任務C再次獲得執行權後,就從挂起點的下一行第113行繼續執行程式,然後又在第112行挂起,最終形成任務B和任務C輪流執行的情況。
下面是任務B和任務C在沒有任何中斷的情況下依靠任務級排程輪流執行的效果視訊:
視訊加載中...
(12)uCOS-II是一個可裁剪的開源程式,要進行任務級排程,首先要設定系統配置頭檔案“OS_CFG.H”中的任務挂起允許标志“OS_TASK_SUSPEND_EN”為1。見下圖:
五、uC/OS-II中斷服務程式的規範程式設計方法
(13)作為RTOS測試程式,中斷的設定程式也要可以根據研究的目的進行多種模式的設定。對于使用者中斷,本測試程式選擇的定時器3中斷,這樣做的理由是定時器中斷是自動準确定時産生的,可以友善進行測試和研究。下圖是系統中斷定時器0和定時器3的設定程式:
其中主頻的定義“MAIN_Fosc”是33.1776MHz,定時器0有兩種模式可以選擇,如圖打開第324行,則其工作在模式3——不可屏蔽模式(意思是隻有ET0被打開後,則定時器0的中斷就與總中斷控制EA和ET0無關了,即使将EA關閉EA=0和ET0=0,定時器0的中斷照樣産生。在這個模式下,想要控制定時器0的中斷,隻能用計數允許TR0來控制了),如果注釋掉第324行,則定時器0工作在模式0——16位自動重裝模式。總中斷允許EA可以控制定時器0的中斷發生。
(14)第331行到334行是定時器3的中斷頻率定義,此處圖中選擇的是10KHz——每100微秒産生一次中斷。
(15)按照uC/OS的不在中斷嵌套時進行任務排程的要求,每個中斷服務程式都有進行進入和退出中斷登記,使用者自己定義的中斷也不例外,是以uC/OS-II的中斷不能使用C語言用中斷矢量關鍵字來定義,必須在彙編語言中逐個定義。下面是本測試程式的ISR:
其中第428行到第439行是定時器3的ISR,該中斷什麼也不做,隻是是uC/OS-II規範的ISR架構。
第430行與第438行是用P20端口電平顯示進入和退出該中斷。第432行與第436行是中斷是目前任務的寄存器現場儲存與恢複。第433行與第435行是在核心中進行中斷嵌入等級。
下圖是第433行通路的中斷核心進入函數:
其中第638行的條件對于STC目前的單片機是多餘的,任何程式中斷最大的嵌套層次為單片機中斷的總數,肯定沒有255個。中斷嵌入層數計數“OSIntNesting”會在系統排程函數“OSIntExit”中作為是否進行排程的判斷标志用。
使用者中斷的第435行調用不但會進行中斷嵌套退出,也同樣會進行系統級排程。是以對于本測試程式,系統級任務排程的響應時間為50微秒。
(16)第400行到第425行是定時器0的ISR,其用P21端口電平顯示進入和退出中斷。而第416行與第418行是用來保護時間節拍系統程式得到完整的執行。
下面是完整測試程式運作的視訊效果:
視訊加載中...
從中可以看到任務B和任務C是交替執行的,而任務A的優先級最高,優先得到執行,由于任務A的休眠的時間較長,在其休眠時時,任務B和任務C能夠得到執行,是以整體視訊效果是任務A與任務B和任務C同時進行。
如果将任務A的任務休眠函數“OSTimeDly”換成軟體延時“Delay_MS”,延遲期間不放棄程式執行權,那麼視訊的效果将是任務A獨自執行了,有興趣的讀者可以自行試試。
六、結束語
本開源測試程式包括uC/OS-II的基本過程,可以作為使用者實際RTOS程式的架構範例參考。本文程式也可以作為測試RTOS性能和研究用,筆者将在下一篇文章中介紹。