如何構(gòu)造一個(gè)51單片機(jī)的實(shí)時(shí)操作系統(tǒng)
2 實(shí)時(shí)操作系統(tǒng)要不要占先
由上面的分析,如果要保持一個(gè)函數(shù)可重人,就得使用靜態(tài)變量,系統(tǒng)的RAM資源將是一個(gè)嚴(yán)峻的考驗(yàn);如果使用臨界區(qū)來保護(hù)運(yùn)行環(huán)境,系統(tǒng)的實(shí)時(shí)性又得不到保證,而且有將占先式任務(wù)調(diào)度轉(zhuǎn)為非占先任務(wù)調(diào)度之虞。顯然,使用靜態(tài)變量簡單,但有更多的不適用性,對(duì)將來功能的調(diào)整也是一個(gè)阻礙,一般不被采用。那么,就只能從環(huán)境保護(hù)上來下功夫了,但是果真只能以進(jìn)入臨界區(qū)犧牲系統(tǒng)的實(shí)時(shí)性來保證任務(wù)不被占先?下面看看臨界保護(hù)這一方法的基本思路:
①在一個(gè)任務(wù)中,如果局部變量在其作用域內(nèi)不被占先切換,則這些變量在任務(wù)被剝奪了CPU控制權(quán)后,不關(guān)心其值也不會(huì)影響任務(wù)的正確執(zhí)行;
②使用臨界區(qū)保護(hù),可以達(dá)到上面所提到的要求;
③由此導(dǎo)致的實(shí)時(shí)性能與占先切換的減弱可以接受。由此可知,不被占先是任務(wù)保護(hù)局部變量的關(guān)鍵。既然如此,何不舍棄占先式的任務(wù)調(diào)度?這不失為一個(gè)好的出發(fā)點(diǎn)。針對(duì)Keil C51,非占先式任務(wù)調(diào)度,可能是一種更好的方法,更能協(xié)調(diào)51系列單片機(jī)的既定資源。下面編寫這樣一個(gè)系統(tǒng):
①使用非占先式任務(wù)調(diào)度;
②可以在小容量的芯片中使用,開發(fā)目標(biāo)是,即使是8051這樣小的芯片,也可使用這個(gè)實(shí)時(shí)操作系統(tǒng);
③支持優(yōu)先級(jí)調(diào)度,盡可能保證其實(shí)時(shí)性。
3 實(shí)時(shí)操作系統(tǒng)的實(shí)現(xiàn)
基于以上的分析與目的,近日完成了這個(gè)操作系統(tǒng)。在堆棧上借用RTx的管理方法,即當(dāng)前任務(wù)使用全部的堆空間
3.1 堆棧的初始化與任務(wù)的創(chuàng)建
堆棧的初始化實(shí)際是初始化0STaskStackBotton數(shù)組,并將當(dāng)前任務(wù)指定為空閑任務(wù),下一個(gè)運(yùn)行任務(wù)指定為最高優(yōu)先級(jí)任務(wù),即優(yōu)先級(jí)為零的任務(wù)。初始化時(shí),將SP的值存人OSTaslkStackBotton[O],SP+2的值存入OSTaskStacKBotton[1],依此類推。而任務(wù)是調(diào)用0STa-skCreate函數(shù)建立的。實(shí)際上只是將任務(wù)(假設(shè)為n號(hào)任務(wù))的地址填人到對(duì)應(yīng)OSTaskStackBotton[n]所指向的位置,并將SP向后移動(dòng)2個(gè)字節(jié),
為什么要以這樣一種規(guī)律而不是其他的方式呢?這是由于在任務(wù)建立后,還未進(jìn)行任務(wù)調(diào)度之前,各任務(wù)的堆棧實(shí)際上是它們自身的地址,因而其堆棧深度為2,為了程序的簡便而直接填入。
void main(void){
OSInit(); /*初始化OSTaskStackBcBotton隊(duì)列*/
TMOD=(TMOD0XFO)│ 0XOl;
TL0=0xBF;
TH0=0xFC;
TRO=1;
ETO=1;
TFO=O:
OSTaskCreate(TaskA,NULL,0);
OSTaskCreate(TaskB.NULL,1);
OSTaskCreate(TaskC,NULL,2);
OSStart();
上面這段代碼中,所有任務(wù)建立后,便調(diào)用OSStart()開始任務(wù)調(diào)度。OSStart()是一個(gè)宏定義,如下所示:
#deflne OSStart() d0{\
OSTaskCreate(TaskIdle,NULL,OS_MAX_TASKS);\
EA=l:\
return;\
}while(O)
首先,它創(chuàng)建了一個(gè)空閑任務(wù)并打開中斷,然后便返回。返回到哪里了呢?我們知道,空閑任務(wù)是優(yōu)先級(jí)最低的任務(wù),當(dāng)調(diào)OSTaskCreate建立時(shí),會(huì)將其地址填人到SP的位置,并把SP向后移動(dòng)2個(gè)字節(jié)(見圖2及說明),因而此時(shí)處在堆棧頂端的,一定是空閑任務(wù)Taslddle。這就使得這里的return一定會(huì)返回到空閑任務(wù)。至此,系統(tǒng)進(jìn)入正常運(yùn)行狀態(tài)。
3.2 任務(wù)的切換
任務(wù)的切換分兩種情況,在當(dāng)前任務(wù)優(yōu)先級(jí)低于下一個(gè)取得CPU控制權(quán)的任務(wù)時(shí),將下一個(gè)取得CPU控制權(quán)的任務(wù)的棧頂?shù)疆?dāng)前任務(wù)的棧頂之間的內(nèi)容向RAM空間的高端搬移,以空出全部的RAM空間作下一個(gè)任務(wù)的堆空間,同時(shí)更新對(duì)應(yīng)的OSTaskStackBotton,使其指向新的正確任務(wù)的堆棧棧底。如果當(dāng)前任務(wù)的優(yōu)先級(jí)高于下一個(gè)任務(wù)的優(yōu)先級(jí),則作相反的搬移,
所有任務(wù)必須主動(dòng)調(diào)用OSSleep,放棄CPU的控制權(quán)。任務(wù)調(diào)用OSSleep后,將選擇優(yōu)先級(jí)最高的就緒任務(wù)運(yùn)行。
結(jié) 語
系統(tǒng)完成后,內(nèi)核的代碼量在400多個(gè)字節(jié)左右,占用1個(gè)定時(shí)器中斷及小量的內(nèi)存空間。系統(tǒng)設(shè)置容量為8個(gè)任務(wù),用戶實(shí)際可用任務(wù)為7個(gè),能夠滿足一般需求,也達(dá)到了在小容量芯片中應(yīng)用的開發(fā)要求。由于沒有采用占先式的任務(wù)調(diào)度,除開全程相關(guān)的個(gè)別任務(wù)的一些局部變量外,其他局部變量已經(jīng)不存在覆蓋關(guān)系,由于是任務(wù)主動(dòng)放棄CPU控制權(quán),對(duì)于個(gè)別需要保護(hù)的變量單獨(dú)進(jìn)行處理也變得容易。在系統(tǒng)中,全程不需要反復(fù)地開關(guān)中斷,實(shí)時(shí)性能也很好。對(duì)個(gè)別時(shí)序要求嚴(yán)格的外設(shè)(如DSl8820)除外。
評(píng)論