μC/OS-II的多任務系統實時性分析與優先級分配
從產品研發的角度,針對小資源系統中使用μC/OS-II的實時性和優先級關系進行了分析,提出了可刪除任務的靈活應用和可變大小任務棧的實現方法,對于并行任務使用共享資源的幾種情況給出了實用解決方案。這些措施獲得了良好的任務并行性和實時響應,節約了代碼存儲空間。
關鍵詞 μC/OS-II 實時性 可變任務堆棧 優先級
引言
μC/OS-II作為一種輕量級的嵌入式實時操作系統,正隨著嵌入式微處理器性能的不斷提高和外圍資源(主要是存儲器資源)的不斷增加,得到越來越多的應用。例如,原來的51系列單片機,限于6~12 MHz的主頻、12個Clock的機器周期以及有限的存儲器資源,使用μC/OS-II會大大加重系統負擔,使應用程序的運行受到影響,特別在快速A/D轉換等實時性較強的場合,無法得到及時的響應,于是才有了更輕量級的Small RTOS等操作系統的出現。
但目前更強勁的51內核版本微處理器的大量出現,從根本上改變了這種情況。40 MHz以上的主頻,單周期指令的微處理器,加上64 KB的程序空間和8 KB以上的數據空間,這樣的系統已經可以流暢地運行μC/OS-II[1]。μC/OS-II的移植版本很多,選擇一個適合系統CPU的版本,然后進行正確的配置和優化是非常重要的。
1? 系統實時性分析
本系統工作原理是在恒定溫度條件下,任意啟動4個測試通道來進行多個項目的并行分析,每個測試通道的工作流程完全相同,如圖1所示。
C8051F120集成了8路12位高速A/D轉換器(ADC0)和8路8位高速A/D轉換器(ADC2)。系統要求對4個光學傳感器輸出進行采樣,ADC0可以構成4個差分測試通道以滿足需求。系統還要求能對2路溫度實現實時控制,用于監控2個外部溫度傳感器的輸出電壓: 一個保證測試部分的溫度恒定在37±0.2 ℃,通過對加熱組件的PWM控制來完成;另一個用于監測機箱溫度,在32 ℃以上時啟動風扇散熱,30 ℃以下關閉風扇。
從圖1中可以看出,完整的流程包括信息輸入、樣本預溫、通道啟動、試劑添加、微分測量、結果處理6個階段。其中前4個屬于操作階段,操作者通過每個通道的進度條、轉動條和狀態標志塊,在LCD界面上獲得明確的操作指示,確保每個通道的正確操作。
要求在通道啟動后,能精確地每隔0.1 s完成一次采樣并處理數據,所以每個通道的最長處理時間不能超過25 ms,且軟件微分法需要較高的A/D轉換精度和穩定性。C8051F120中的A/D最高采樣速率可達100 ksps,約10 μs/次,因此可采用過采樣后的高平滑,同時提高精度和穩定性。簡單地計算,如果每個通道采樣1 024次后平均計算,則4個通道的A/D總速率為:ADMAX=1 024×4×10=40 ksps。
理論上來說,即使把采樣次數再加倍,仍然略小于100 ksps,但考慮到每次A/D中斷后,中斷服務程序都要簡單地處理采樣數據,然后才能啟動下一次A/D轉換,所以實際轉換速度是不能達到100 ksps的。通過調試,合理的選擇為每個采樣點取1 024次平滑濾波。實際處理中,把A/D轉換精度從12位擴展到了16位,以滿足0~2 000 mV范圍內0.1 mV的精度和穩定性,這可以簡單地通過改變求均值時的右移次數和擴大滿量程基數來完成[2]。
除了實時性的要求必須得到嚴格滿足外,有很多因素需要一并考慮。例如每個通道測試過程中的圖形動態顯示,通道測試過程中的鍵值交叉處理,獨立于測試之外的實時溫度控制,耗時較多的測試結果傳送和打印等,這些人為操作和功能處理均不能中斷,或影響正在測試的通道每0.1 s一次的數據采樣。另外,還必須提供一項強制結束功能:在任何測試階段按Exit鍵,確認后可退出所有測試。
總體上看,系統在各個通道共用1個鍵盤、1個串口、1個打印機、1個LCD顯示器、1個A/D轉換器的條件下,能進行獨立控制,互不干擾地進行各自的測試、計算、顯示、傳送和輸出,滿足實時性和并行性要求。
2? 內存分配
μC/OS-II最多有64個任務優先級,根據版本的不同可供用戶使用的優先級有56~62個。每個任務優先級不能相同,最大優先級數即用戶的最大任務數[1]。
每個任務必須有自己的任務棧,任務棧由系統物理棧拷貝區和模擬棧兩部分組成,是μC/OS-II移植的核心內容[3-4],因此任務的多少直接影響數據RAM的需求。在本系統中,物理棧拷貝區為64字節,模擬棧可以安排16~64字節,這種可變大小任務棧稍后分析。
C8051F120微處理器帶有8 KB的RAM,系統沒有擴展外部數據存儲器。首先分析一下系統數據內存的需求情況:
①? 系統顯示部分使用了240×128點陣的LCD模塊和圖形GUI,如果建立完整的顯示緩沖區,需要240/8×128=3 840字節,約4 KB的RAM空間;
②? Flash除了用作程序存儲器外,剩下的部分作為非易失性數據存儲器。每個Flash塊為1 KB,故需要1 KB的RAM作為Flash的讀寫緩沖區;
③? GUI自身約占去了1 KB內存;
④? 傳感器響應曲線需打印,其點坐標數據(對應打印機384個點行)約占1 KB。
以上共占用7 KB,最終僅剩下1 KB的RAM留給操作系統以及用戶函數,這顯然不夠。可通過優化GUI的驅動,去掉LCD的顯示緩沖區,增加4 KB的RAM,以滿足系統需要。
3? 可變任務棧和任務劃分
3.1? 可變大小任務棧
一般來說,一個嵌入式系統中不會建立60個以上的任務。從簡單的角度考慮,應用μC/OS-II時,建立的所有任務均駐留不刪除,使用足夠大并且同樣大小的堆棧。這種處理任務的方法會對內存數量提出較高要求。例如50個任務,每個任務棧均為128字節,則需要6 KB的RAM。
本著這樣一個原則來改進任務劃分:不需要駐留的任務運行完畢即刪除,可以自身刪除,也可以在別的任務里刪除。這種任務處理不僅可以重用任務優先級,還可以重用任務堆棧,并且減少同時運行的任務數量。
刪除任務的辦法不僅可獲得共享的任務棧資源,而且也是一個方便中止某些應用程序的手段,前面提及的任何測試階段按Exit鍵退出所有測試的動作,就可以依靠刪除任務來實現。
把任務看作有大小的,這里的“大小”指需要“重入”到任務堆棧的變量的數量。如果每一個任務都使用相同大小的任務棧,對小任務而言顯然是在浪費寶貴的RAM,大小可變的任務棧才是經濟合理的。
首先,在os_cfg.h頭文件中增加大、小兩個宏參數,如果需要更多不同的棧大小,還可以繼續增加參數。
#define MaxStkSize128//大任務棧
#define MinStkSize80//小任務棧
然后定義任務棧時使用它們:
OS_STK TaskDelStk1[MinStkSize];
OS_STK TaskDelStk2[MaxStkSize];
TaskDelStk1和TaskDelStk2是兩個可刪除任務所使用的任務棧,一個80字節,另一個128字節。
接下來是關鍵,要在任務堆棧初始化函數OSTaskStkInit中進行處理:定義一個全局整型變量STK_SIZE,創建任務前給它賦值,任務創建時執行的OSTaskStkInit函數用它來初始化模擬棧的長度。
修改前,OSTaskStkInit中的?C_XBP仿真堆棧指針(即模擬棧指針)的初始化語句如下:
*stk++ = (INT16U) (ptos + MaxStkSize) >> 8;//MaxStkSize是固定的棧長度
*stk++ = (INT16U) (ptos + MaxStkSize) & 0xFF;
注意:ptos是任務棧棧底,模擬棧從任務堆棧的另一頭開始。
修改后變為:
*stk++ = (INT16U) (ptos + STK_SIZE) >> 8;//指針高8位
*stk++ = (INT16U) (ptos + STK_SIZE) & 0xFF;//指針低8位
創建任務前要給STK_SIZE賦予堆棧定義匹配的棧長度值,否則,會因為堆棧不能正確初始化導致任務崩潰。不同大小的任務棧結構如圖2所示,可以看出區別在于模擬棧不同。
利用可變大小任務棧創建一個小堆棧任務,示例如下:
STK_SIZE=MinStkSize;//提供堆棧大小值
/*創建帶TimeLimit參數的,分配有任務棧TaskDelStk1,優先級為10的任務OverTime*/
OSTaskCreate(OverTime,(void*)&TimeLimit, &TaskDelStk1[0],10);
3.2? 系統任務劃分
用戶任務分為兩類: 一類任務是常駐任務,即創建后不用刪除的任務;另一類是可刪除任務,運行時建立,運行完刪除,該任務資源又可用來創建新的任務。
常駐任務有以下幾個:
① ?主任務。用于控制程序流程,使用大任務棧,相當于主函數。
②? 溫度檢測任務。使用小任務棧,系統初始化后創建,并一直運行;每秒檢測一次溫度,根據兩個溫度傳感器的狀況調整加熱時間占空比和啟停散熱風扇,維持37 ℃恒溫。
③? 鍵盤掃描任務:使用小任務棧,自檢完畢后創建。等待接受鍵盤中斷程序發出的信號量,進行處理后發出鍵值到消息郵箱,供其他任務使用。需要這個鍵盤任務處理鍵值,而不是直接在鍵盤中斷服務程序中處理的原因是: 要盡可能縮短中斷服務時間。
④ ?旋轉光標指示器任務: 使用小任務棧。該任務在自檢和通道測試時起過程指示作用,當過程進行時,光標旋轉,過程結束則光標停止。因為在主任務的自檢和通道測試程序中均使用它,故采取常駐任務的形式,通過定時判斷4個標志位來決定是否旋轉1~4個光標。
常駐任務的堆棧共使用了128+80×3=368字節RAM。
可刪除任務根據任務函數的復雜性,也使用了大堆棧和小堆棧兩種結構,共8個任務。
①? 超時檢測任務:使用小任務棧,用于檢驗某一過程是否超時。
②? 日期時間顯示:使用小任務棧,在主菜單中定時顯示日期時間。離開主菜單后即可刪除,回到主菜單再重新建立。
③? ADC0任務:使用小任務棧,每隔100 ms掃描4個測試通道的A/D值,并發送至相應通道的消息郵箱,通道接收消息指針,獲得此A/D值。 這3個小堆棧任務不會同時運行,因此共享同一個任務堆棧。
④~⑦? 通道1~4的測試任務:使用大任務棧,4個任務對應4個通道的并行測試。
⑧ ?數據打印和傳送任務:使用大任務棧,因為涉及較多的局部變量。如果直接在通道測試任務中進行打印和傳送,那么數據打印和串口傳送的時間之和可能會超過100 ms;特別是圖形點陣打印,有較多的數據發往打印機。這種情況違背了每次100 ms的精確采樣時間要求,丟失了數據,所以單獨安排為一個任務在后臺運行。
可刪除任務棧共使用80+128×5=720字節RAM。
總的任務共有12個,使用的任務棧空間只有大約1 KB。
4? 任務優先級分配
優先級的合理分配圍繞實時性要求進行,因為可用優先級較多,所以任務優先級之間可取較大間隔。這樣當有更多的任務加入時,能安排在這些間隔中,不用改變已有任務的優先級。本系統中優先級關系可以按由高到低順序依次排列: 鍵盤掃描任務,超時檢測任務, A/D掃描轉換任務,主任務,各通道測試任務,數據打印和傳送任務,溫度檢測任務,日期時間顯示任務,如圖3所示。
常駐任務一般是固定優先級,而可刪除任務每一次創建時卻能夠對應不同的任務函數和優先級,且使用同一個任務棧。
一個任務函數可用于多個任務,這種“重用”的特性在獲得任務并行性的同時,最大限度地節約了代碼。本系統只有一個測試函數,卻構成了4個并行的通道任務。這些任務都是進入測試菜單后隨著各自通道鍵被按下后在主任務中創建的,復用的4個測試函數接受任務創建時主任務傳遞過來的參數,為本通道的計算、顯示、數據存儲等一系列工作服務。
5? 資源共享的處理
ADC0、LCD、打印機和串口等資源被4個測試任務所共享。資源共享有一些經典的方法(如信號量、全局變量等),需要根據實際需求靈活運用。本系統的處理如下:
①? 對于ADC0,在A/D掃描轉換任務中每0.1 s輪流掃描4個通道一次,產生4個郵箱消息發往各自通道任務,以讀取對應的轉換結果。0.1 s的精確定時由定時器中斷獲得,中斷服務發出信號量啟動AD任務。一次掃描完成后A/D掃描轉換任務掛起,直至下一次信號量到來。
②? 對于LCD,情況要復雜一些,每個測試任務都要在LCD的各自區域顯示,但是LCD不能實現2個以上位置同時進行顯示處理,所以當涉及顯示過程時需要禁止任務切換,否則會造成顯示混亂。例如,當一個低優先級任務的顯示工作還沒有完成時,若發生了任務切換,則高優先級任務去進行另一個顯示。當重新切換回低優先級任務后就沒有辦法繼續未完的顯示,因為顯示位置已經被高優先級任務所改變。
③? 對于打印機和串口,也有類似的問題,不允許一個結果尚未打印完成又去打印另一個結果。禁止任務切換的辦法不適合這里,因為打印和傳送耗時比LCD顯示長很多,禁止任務切換會影響到測試的實時性,它們單獨建立后臺任務的原因也在于此。
數據打印和傳送任務循環掃描各個通道的請求服務標志,當標志有效時即為該通道服務,服務完畢清除該標志,因數據打印和傳送任務的優先級較低而不會對其他測試任務造成任何影響。被服務的通道測試任務循環檢測請求服務標志,檢測到標志被清除后才可以繼續下次測試,表示此次數據已經輸出。其他高優先級測試任務不會影響打印過程,因為先檢測到標志的通道獨占資源,直至傳送和打印完成后,打印任務才去檢測下一個標志;高優先級任務的輸出請求要等低優先級輸出完畢才能得到響應,優先級反轉在這里是正確的。
6??結論
本文從嵌入式系統的并行程序出發,結合實時性的要求,討論了μC/OS-II操作系統環境下的任務劃分和優先級確定的相關問題,提出了一些在μC/OS-II中用于減少資源耗用和同時運行的任務數量的改進措施。實踐證明,這些措施可以充分發揮μC/OS-II小巧精悍的特點,提高程序代碼的重用性,節約寶貴的RAM資源。本系統與采用雙通道測試、沒有RTOS、采用前后臺方式解決并行問題的方法比較[5],后者占用了54 KB代碼,在人機界面和并行度上均不及前者。前者在加入了μC/OS-II和GUI,并能進行四通道測試的情況下,僅有59 KB代碼;排除更大的漢字庫容量后,實際代碼大小幾乎與原來相同,性能卻有了很大的提高。
評論
查看更多