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