<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 微型搶占式多任務(wù)實(shí)時(shí)內核設計

微型搶占式多任務(wù)實(shí)時(shí)內核設計

作者: 時(shí)間:2004-12-11 來(lái)源:網(wǎng)絡(luò ) 收藏
摘要:介紹引入事件驅動(dòng)觀(guān)念的式多――MicroStar的與實(shí)現;提出基于事件的優(yōu)先級這一新概念。

關(guān)鍵詞:事件驅動(dòng) 優(yōu)先級 管理 消息 信號 同步

市面上有很多優(yōu)秀的嵌入式操作系統(RTOS),但在中低端微控制器(MCU)上運行性能良好的RTOS并不多。在高檔機下,功能強大、運行極好的嵌入式操作系統,移植到中低端機上時(shí)性能很可能大幅度下降。一個(gè)很重要的原因就是它的大部分功能對中低檔系統來(lái)說(shuō)是不需要的,反而成為制約性能的累贅。中低檔微控制器與高檔機相比,一方面,尋址能力有限,處理速度慢,在相同的實(shí)時(shí)性能要求下,對的代碼效率的要求更為嚴格;另一方面,中低檔機完成的相對簡(jiǎn)單,減少了對內核的功能需求,比如可以不需要內存管理。從嵌入式系統的共性來(lái)說(shuō),大多數情況下用戶(hù)程序和系統內核是緊密結合在一起的,運行時(shí)存儲器容量消耗、任務(wù)的數量、執行時(shí)間和結果都是可以預計的,這可進(jìn)一步縮小對內核的功能需求。

??事件驅動(dòng)的觀(guān)點(diǎn)認為,任務(wù)應該是被動(dòng)地響應外界發(fā)生的各種事件,而不是主動(dòng)地去“查詢(xún)”,浪費處理器時(shí)間。采用事件驅動(dòng)編程的方法,不僅提高了運行效率,而且降低了事件處理之間的耦合,使程序流程非常清晰,從而可大大提高開(kāi)發(fā)效率。

??充分考慮中低端微控制器的硬件特點(diǎn)和嵌入式系統軟件的需求,引入“事件驅動(dòng)”的觀(guān)念,筆者開(kāi)發(fā)了一個(gè)式多任務(wù)RTOS內核――MicroStar。支持任務(wù)的動(dòng)態(tài)創(chuàng )建、刪除、睡眠、掛起和恢復,提供消息(message)和信號(signal)兩種任務(wù)間的通信方案、完善的定時(shí)器服務(wù)和功能齊全的任務(wù)同步函數庫。限于篇幅,著(zhù)重論述幾個(gè)與眾不同的思路和實(shí)現難點(diǎn)。

1 調度策略

1.1 基于事件的優(yōu)先級

??對內核的實(shí)時(shí)性能來(lái)說(shuō),調度策略是關(guān)鍵。好的調度策略,既要體現各任務(wù)因所處理的事件對實(shí)時(shí)性的不同要求而帶來(lái)的優(yōu)先級差異,又要保證一定的公平性,避免出現低優(yōu)先級任務(wù)長(cháng)時(shí)間得不到執行的極端情形。常用的調度策略有兩種:一種是按時(shí)間片輪轉(round robin)調度,如RTX51;另一種是嚴格按優(yōu)先級的占先式調度,如μC/OS。

??按時(shí)間片輪轉調度能很好地保證公平,但優(yōu)先級的差異是通過(guò)對處理器的占用時(shí)間的多少來(lái)體現的。如果各個(gè)任務(wù)都不主動(dòng)放棄執行,高優(yōu)先級的任務(wù)能夠比低優(yōu)先級任務(wù)獲得更多的處理器時(shí)間;但在嵌入式系統中,某個(gè)事件要求實(shí)時(shí)處理,并不意味著(zhù)該處理需要較長(cháng)的時(shí)間,而往往是要求盡快響應。因此,采用按時(shí)間片輪轉調度,實(shí)時(shí)性不會(huì )太好。

??如果嚴格按任務(wù)的優(yōu)先級來(lái)調度,可極大地提升系統的實(shí)時(shí)性,但卻欠缺公平。如果高優(yōu)先級任務(wù)是個(gè)無(wú)等待的死循環(huán),低優(yōu)先級任務(wù)就無(wú)法獲得執行機會(huì )。

??一個(gè)好的辦法是兩者的結合,即可由任務(wù)的優(yōu)先級產(chǎn)生調度,也可以由時(shí)間片到產(chǎn)生新的任務(wù)調度,如VxWorks;但是實(shí)現起來(lái)較為復雜,不一定適合中低檔MCU。為此,基于以下事實(shí),提出“基于事件的優(yōu)先級(events based priority)”這一新觀(guān)念。

??① 一個(gè)任務(wù)往往處理多個(gè)事件,各個(gè)事件對實(shí)時(shí)性的要求不盡相同。一般的RTOS下,任務(wù)的優(yōu)先級是根據這些事件中對實(shí)時(shí)性要求最高的一個(gè)來(lái)確定的。因此,高優(yōu)先級任務(wù)在處理對實(shí)時(shí)性要求不高的事件時(shí),完全可能會(huì )妨礙低優(yōu)先級任務(wù)處理具有一定實(shí)時(shí)性要求的事件。

??② 有些情況下,對同一事件的處理可分為前臺處理和后臺處理:前臺處理所需時(shí)間短,對實(shí)時(shí)性有較高的要求;后臺處理花費時(shí)間長(cháng),對實(shí)時(shí)性則無(wú)多大要求。

??如果根據正在處理和等待處理的事件對實(shí)時(shí)性的不同要求,更細致地按事件處理的前后臺階段,動(dòng)態(tài)地調整任務(wù)的優(yōu)先級,采用優(yōu)先級調度策略,既可發(fā)揮實(shí)時(shí)性好的優(yōu)點(diǎn),又可在一定限度內保證公平。這種情況下,任務(wù)的優(yōu)先級不再是一成不變的,而是動(dòng)態(tài)地取決于所處理的事件和處理階段,這就是所謂的“基于事件的優(yōu)先級”。

1.2 在MicroStar中的實(shí)現

??MicroStar中任務(wù)的優(yōu)先級是由靜態(tài)優(yōu)先級和動(dòng)態(tài)優(yōu)先級共同決定的。靜態(tài)優(yōu)先級等同于其它RTOS中的優(yōu)先級;動(dòng)態(tài)優(yōu)先級為基于事件的優(yōu)先級――由內核根據任務(wù)正在處理和等待處理的事件動(dòng)態(tài)調整。靜態(tài)優(yōu)先等級限定為0~15級,不允許創(chuàng )建靜態(tài)優(yōu)先級相同的任務(wù)。動(dòng)態(tài)優(yōu)先等級目前只有0(亦稱(chēng)緊急級)、1(亦稱(chēng)普通級)兩級。任務(wù)的實(shí)際優(yōu)先等級可由下式來(lái)計算:

??優(yōu)先等級=動(dòng)態(tài)優(yōu)先等級16 + 靜態(tài)優(yōu)先等級。

??優(yōu)先等級值越大,優(yōu)先級越低??梢钥闯?,動(dòng)態(tài)優(yōu)先級起決定作用。

??怎樣實(shí)現優(yōu)先級動(dòng)態(tài)可調呢?首先簡(jiǎn)要介紹MacroStar中任務(wù)的四個(gè)狀態(tài):

??休眠(dormant)――任務(wù)因調用睡眠函數、掛起函數或者等待內核同步對象而進(jìn)入休眠態(tài);

??等待(waiting)――任務(wù)因等待消息或者信號(勿與“信標”、“信號量”相混淆)而進(jìn)入等待態(tài);

??就緒(ready)――任務(wù)運行的條件都已俱備,只等被調度,稱(chēng)為就緒態(tài),亦稱(chēng)可調度態(tài);

??運行(running)――任務(wù)正在使用處理器的資源,稱(chēng)為運行態(tài)。

??這些狀態(tài)都是用標志位來(lái)實(shí)現的。16個(gè)靜態(tài)優(yōu)先級對應的任務(wù)的某一狀態(tài)剛好可用一個(gè)16位的二進(jìn)制數來(lái)標識。休眠態(tài)用os_slpState來(lái)表示,從高位算起,第N位為0表示靜態(tài)優(yōu)先級為N的任務(wù)處于休眠態(tài)。等待態(tài)是依據“事件驅動(dòng)”觀(guān)念而專(zhuān)為消息和信號而的,用os_rdyhState和os_rdyState兩個(gè)16位的變量來(lái)記錄。只有當os_rdyhState和os_rdyState的第N位均為0時(shí),才表示靜態(tài)優(yōu)先級為N的任務(wù)處于等待態(tài)。如果任務(wù)處于非等待狀態(tài),意味著(zhù)任務(wù)已在處理事件或者有事件要處理(可以認為任務(wù)一開(kāi)始就處理“啟動(dòng)”這個(gè)“虛擬事件”),這時(shí),才有動(dòng)態(tài)優(yōu)先級的概念。如果os_rdyhState中的第N位為1,表示靜態(tài)優(yōu)先級為N的任務(wù)的動(dòng)態(tài)優(yōu)先級為緊急級;如果os_rdyhState第N位為0,則表示靜態(tài)優(yōu)先級為N的任務(wù)的動(dòng)態(tài)優(yōu)先級為普通級。要求實(shí)時(shí)處理的事件發(fā)生后,內核簡(jiǎn)單將os_rdyhState相應位置1,提升任務(wù)的動(dòng)態(tài)優(yōu)先級;當前事件處理完畢后,如果已無(wú)實(shí)時(shí)性要求較高的事件等待處理,簡(jiǎn)單地將os_rdyhState相應位清0,降低任務(wù)的動(dòng)態(tài)優(yōu)先級。由此,即可實(shí)現優(yōu)先級的動(dòng)態(tài)可調。只有當任務(wù)既不處在休眠態(tài)也不處在等待態(tài)時(shí),任務(wù)才是可以調度的。

2 任務(wù)管理

2.1 任務(wù)控制塊

??多任務(wù)系統中用任務(wù)控制塊(TCB)來(lái)記錄任務(wù)的各種屬性。在這些屬性中,最重要的是任務(wù)堆棧棧頂地址。進(jìn)行上下文切換(context switch)時(shí),被停止執行的任務(wù)的所有寄存器狀態(tài)、下一條代碼的地址都要入棧保護,因而這個(gè)屬性是必需的。如果允許修改任務(wù)的優(yōu)先級,優(yōu)先級屬性也是必需的。所以,將任務(wù)控制塊簡(jiǎn)化如下:

typedef struct{

uint_16 msg[2]; /*消息接收區*/

int * sp; /*堆棧棧頂指針*/

uchar priority; /*靜態(tài)優(yōu)先級*/

uchar reserved; /*保留 */

}TCB,*PTCB;

TCB os_tcbs[ USER_TASK_NUM +1 ];

/*用戶(hù)任務(wù)數最多為15個(gè)*/

??msg用來(lái)存儲發(fā)送給任務(wù)的消息,兩個(gè)16位的二進(jìn)制可按位存放32個(gè)消息。sp指向任務(wù)堆棧棧頂。priority記錄任務(wù)的靜態(tài)優(yōu)先級。數組os_tcbs用來(lái)記錄系統所有任務(wù)的信息,其下標與任務(wù)的ID號相對應,即ID號為N的任務(wù)的控制塊為os_tcbs[N]。

2.2 任務(wù)的創(chuàng )建

os_CreateTask函數用來(lái)創(chuàng )建一個(gè)任務(wù):

void os_CreateTask(

TASKPROC task, //任務(wù)函數的指針

uchar taskId, //任務(wù)的ID號

uchar priority, //優(yōu)先級

int  * pStack, //任務(wù)堆棧棧底地址

void * param //任務(wù)函數的入口參數

);

typedef void (*TASKPROC)( void * param);

??創(chuàng )建任務(wù)時(shí),內核要做以下幾方面的工作:① 初始化任務(wù)控制塊;② 初始化任務(wù)堆棧,使其如同被其它任務(wù)搶斷時(shí)的情形;③ 將任務(wù)狀態(tài)置為就緒態(tài)。該函數是依賴(lài)于處理器的,圖1是較為通用的描述。

??中斷程序中,在高優(yōu)先級任務(wù)剝奪低優(yōu)先級任務(wù)之前,內核將斷點(diǎn)時(shí)的各寄存器狀態(tài)入棧保護,這部分區域即為寄存器映像區。將任務(wù)退出函數os_Exit的地址先于任務(wù)函數MyTask入棧,以使MyTask函數退出后返回到os_Exit中去,由此來(lái)實(shí)現任務(wù)的自動(dòng)刪除。

2.3 任務(wù)切換

??與任務(wù)創(chuàng )建一樣,任務(wù)切換代碼與硬件相關(guān)。在PC機上,代碼和步驟如下:

 void interrupt os_Schedule( )  …………(1)

{

if( os_nLayers )return;

os_nLayers++;   …………(2)

_DX = (int)os_pCurTCB;

/*os_pCurTCB指向當前任務(wù)的控制塊*/

  *(int*)(_DX+4) = _SP;

  *(int*)(_DX+6) = _SS; …………(3)

  os_GetReadyTask( ); …………(4)

  _DX = (int)os_pCurTCB;

  _SP = *(int*)(_DX+4);

  _DX = *(int*)(_DX+6);

  _SS = _DX;   …………(5)

  os_nLayers--;?   …………(6)

  UNLOCK_INT( );

}   …………(7)

(1)利用C語(yǔ)言interrupt關(guān)鍵字使各寄存器入棧保護。(2)鎖定調度器,不允許重調度。(3)將當前任務(wù)的棧頂地址(由堆棧段寄存器SS和棧指針寄存器SP組成)保存在os_pCurTCB->sp中(PC機下,TCB中的sp定義為遠指針類(lèi)型)。(4)選出優(yōu)先級最高的就緒任務(wù)(方法類(lèi)似于μC/OS),并將os_pCurTCB指向新任務(wù)的控制塊。(5)棧寄存器指向新任務(wù)的棧頂地址。(6)解鎖調度器。(7)各寄存器出棧,恢復到上次被中斷時(shí)的情形。

3 消息與信號

??為很好地支持事件驅動(dòng)編程,MicroStar借鑒了Windows的“基于消息,事件驅動(dòng)”觀(guān)念,并加以擴展。在MicroStar中,事件不僅可以觸發(fā)消息、信號,而且由事件觸發(fā)的消息或信號是有優(yōu)先級的,這是因為不同事件對處理的實(shí)時(shí)性要求是不同的。內核正是根據消息、信號的優(yōu)先級來(lái)動(dòng)態(tài)調整任務(wù)的動(dòng)態(tài)優(yōu)先級的。

3.1 消 息

??消息是一種很友好的通信方式??紤]中低檔單片機的內存容量和需求,將消息簡(jiǎn)化為一個(gè)0~31的值。采用固定位圖存儲格式,將這32個(gè)值映射到任務(wù)控制塊的msg域,這大大減小了存儲空間??蓪sg域看作一個(gè)32位的二進(jìn)制變量,第i位為1,表示有值為i的消息,因此消息的存取只需通過(guò)簡(jiǎn)單的“與”、“或”運算。消息的優(yōu)先級依值而定,值越大,優(yōu)先級越低。在系統范圍內,消息優(yōu)先級又分為兩級:緊急級(值0~15)與普通級(值16~31)。當有緊急消息發(fā)送給任務(wù)時(shí),內核會(huì )提升任務(wù)的動(dòng)態(tài)優(yōu)先級,從而提高消息處理的實(shí)時(shí)性。當任務(wù)無(wú)緊急消息要處理時(shí),內核就降低它的動(dòng)態(tài)優(yōu)先級。發(fā)送消息的核心代碼如下:

/*const uint_16 os_maskTable[16] ={ 0x8000,0x4000, .....,0x0008,0x0004,0x0002,0x0001 */

if( msg0xF0 ) { /*普通級消息*/

pTCB->msg[1] |= os_maskTable[msg0x0F];

/*普通級消息存在msg[1]中*/

os_rdyState |= os_maskTable[pTCB->priority];

}

else { /*緊急級消息*/

pTCB->msg[0] |= os_maskTable[msg]; ;

/*緊急級消息存在msg[0]中*/

os_rdyhState |= os_maskTable[pTCB->priority];

/*提升動(dòng)態(tài)優(yōu)先級*/

}

??與先進(jìn)先出(FIFO)方式的消息隊列不同,內核總是取出優(yōu)先級最高的消息來(lái)交給任務(wù)處理。消息接收函數os_GetMessage設計思路如下:如果消息接收區中無(wú)緊急消息,則降低任務(wù)的動(dòng)態(tài)優(yōu)先級;如果消息接收區中有消息,則取出優(yōu)先級最高的消息;如果沒(méi)有消息,則將任務(wù)轉為等待態(tài)??紤]有時(shí)候不希望任務(wù)進(jìn)入等待態(tài),MicroStar還提供了非阻塞的os_PeekMessage消息接收函數。

3.2 信 號

??在嵌入式系統編程中,常利用標志位來(lái)實(shí)現前后臺程序或不同的任務(wù)間的通信。MicroStar也提供了類(lèi)似的任務(wù)間的通信方式――信號(signal)。它避免了用戶(hù)程序因不斷查詢(xún)標志位而帶來(lái)的時(shí)間浪費,而且支持信號間的“與”、“或”運算。通俗來(lái)說(shuō),信號就是標志位,用來(lái)標識某個(gè)事件的發(fā)生。同消息一樣,信號也有緊急級與普通級之分。與消息不同的是,信號完全由用戶(hù)程序創(chuàng )建和維護,內核只是幫助用戶(hù)程序等待信號,以避免低效率的標志位查詢(xún)。使用起來(lái)不如消息直觀(guān),但執行效率較高。實(shí)現起來(lái)非常簡(jiǎn)單,請參見(jiàn)源碼。

圖1

4 定時(shí)器

??定時(shí)器在嵌入式系統有著(zhù)大量的用途,如LED的定時(shí)刷新、串口通信中的超時(shí)檢查。對定時(shí)器的需求分為兩類(lèi),一種是周期性重復定時(shí),比如每隔10ms去刷新LED;另一種是僅需定時(shí)一次的一次性定時(shí)。定時(shí)時(shí)長(cháng)以系統時(shí)鐘節拍(tick,又譯作滴達)作為單位。兩次系統定時(shí)中斷之間的時(shí)間間隔為一個(gè)節拍。定時(shí)器結構體如下:

typedef struct{

uint_16 elapse; /*定時(shí)時(shí)長(cháng)的余值*/

uint_16 backTime; /*定時(shí)時(shí)長(cháng)的備份值*/

MSG timerId; /*定時(shí)器ID號*/

uchar taskId; /*擁有該定時(shí)器的任務(wù)的ID*/

TIMERPROC lpTimerFunc; /*定時(shí)調用的函數指針*/

}TIMER,*PTIMER;

TIMER os_timers[USER_TIMER_NUM]; /*最多為16個(gè)*/

??周期性定時(shí)和一次性定時(shí)是通過(guò)timerId來(lái)區分的。如果timeId為64,為一次性定時(shí);如果timerId不大于32,則為周期性定時(shí)。用os_timers數組記錄定時(shí)器信息,用16位的os_timerState表示定時(shí)器的狀態(tài)。如果os_timerState的二進(jìn)制數的第N位為1,則表示os_timers[N]空閑可用。

??對周期性定時(shí)器,每隔定時(shí)時(shí)長(cháng)的時(shí)間,內核就調用的lpTimerFunc指向的函數,并且將timerId以消息的方式發(fā)送給任務(wù),對任務(wù)的動(dòng)態(tài)優(yōu)先級的影響與普通消息一樣。因此,要想取得實(shí)時(shí)性較好的定時(shí)器,只需將timerId設在0~15之間。與一次性定時(shí)相關(guān)的是睡眠函數和限時(shí)等待同步對象的函數。任務(wù)使用這兩個(gè)函數而進(jìn)入休眠態(tài)后,在定時(shí)時(shí)間到時(shí),內核將其恢復為就緒態(tài),并自動(dòng)釋放定時(shí)器資源。系統定時(shí)處理的核心代碼如下:

if( !(--pTimer->elapse) ){ /*elapse減為零表示時(shí)間到*/

if( pTimer->lpTimerFunc)(*pTimer->lpTimerFunc)(pTimer->

taskId,pTimer->timerId);

switch( pTimer->timerId0xF0 ){

case SLEEP_ID: /*一次性定時(shí)*/

os_slpState |= taskMask; /*結束休眠態(tài)*/

os_timerState |= timerMask; /*釋放定時(shí)器*/

break;

case 0x00: /*發(fā)送緊急級定時(shí)器消息*/

pTCB->msg[0] |= os_maskTable[pTimer->timerId];

os_rdyhState |= os_maskTable[pTCB->priority ];;

break;

case 0x10: : /*發(fā)送普通級定時(shí)器消息*/

pTCB->msg[1] |= os_maskTable[pTimer->timerId0x0f];

os_rdyState |= os_maskTable[pTCB->priority ];;

}

}

5 同 步

??式多任務(wù)下,低優(yōu)先級的任務(wù)可以被高優(yōu)先級任務(wù)打斷執行。以常規方式訪(fǎng)問(wèn)共享變量或資源時(shí),會(huì )出現奇怪的結果。比如,一個(gè)任務(wù)調用printf(“12345”)試圖在輸出設備上輸出“12345”,但執行中被高優(yōu)先級任務(wù)打斷;而高優(yōu)先級任務(wù)也調用printf(“67890”)試圖輸出“67890”,最終的輸出結果可能是“1267890345”之類(lèi)。這就是多任務(wù)環(huán)境下的任務(wù)同步問(wèn)題?!?/P>

??同步方式有兩種,一種為用戶(hù)同步方式,不需要與內核打交道,具有速度快的優(yōu)點(diǎn),但只適合保護執行時(shí)間短的代碼;另一種是內核同步方式,需要通過(guò)內核來(lái)實(shí)現,速度相對較慢,但可保護執行時(shí)間長(cháng)的代碼。

5.1 用戶(hù)同步方式

??用戶(hù)方式下的同步是通過(guò)關(guān)鍵代碼段(critical section)保護來(lái)實(shí)現。關(guān)鍵代碼段是指這樣一小段代碼,它執行時(shí)必須獨占對某些共享資源的訪(fǎng)問(wèn)權,不允行被其它試圖訪(fǎng)問(wèn)該資源的代碼打斷。最簡(jiǎn)單的是得用關(guān)/開(kāi)中斷來(lái)實(shí)現,優(yōu)點(diǎn)是速度極快,缺點(diǎn)是帶來(lái)中斷延遲,只適合執行時(shí)間極短的代碼段。另一簡(jiǎn)單的方案是通過(guò)加鎖/解鎖調度器來(lái)實(shí)現,即在關(guān)鍵代碼段執行期間禁止內核進(jìn)行任務(wù)切換。采用這種方法,不會(huì )帶來(lái)中斷延遲,但帶來(lái)了調度延遲。在MicroStar中,對os_nLayers加1即可鎖定調度器,減1即可解鎖。但直接利用解鎖調度器來(lái)離開(kāi)關(guān)鍵代碼段并不合適。如果在關(guān)鍵代碼段執行中,發(fā)生了中斷,使更高優(yōu)先級任務(wù)就緒。但由于調度器被鎖定,中斷程序退出時(shí)不能進(jìn)行任務(wù)切換以使高優(yōu)先級任務(wù)執行。因此我們希望,最好一旦調度器解鎖,馬上就切換到高優(yōu)先級任務(wù)。為此,專(zhuān)門(mén)用變量os_flag的最低位作為標志位,中斷程序中調用任何可以使任務(wù)就緒的系統函數都會(huì )影響到該標志位,如os_PostMessage、os_SetEvent,os_Notity。退出關(guān)鍵代碼段時(shí)以此來(lái)判斷是否需要進(jìn)行任務(wù)調度。離開(kāi)臨界代碼段時(shí)的代碼如下:

if( (os_flag0x01) (!(--s_nLayers ) ) ) {--os_Schedule( ); }

5.2 內核同步對象

??如果要保護執行時(shí)間較長(cháng)的代碼,就要使用內核同步對象來(lái)同步。常用的內核同步對象有事件(event)、信標(semaphore,亦稱(chēng)信號量)和互斥量(mutex)。 事件對象用來(lái)通知事件或者操作已經(jīng)完成,它用一個(gè)布爾值來(lái)表示該事件處于通知還是未通知狀態(tài)。信標對象用于對資源進(jìn)行計數。它記錄了當前可用的資源數目。當用1來(lái)初始化信標對象的可用資源數目時(shí),信標對象實(shí)際上成為了互斥對象。MicroStar提供事件和信標兩種同步對象,支持查詢(xún)、限時(shí)等待或無(wú)限時(shí)等待操作。內核同步對象的結構如下:

typedef struct{

uint_16 waiter; /*等待列表*/

uchar num;  /*可用資源數目或者事件狀態(tài)*/

uchar type; /*同步對象類(lèi)型*/

}OBJECT,*POBJECT,*HOBJECT,*HEVENT,*HSEMAPHORE;

??當一個(gè)任務(wù)因等待同步對象而進(jìn)入休眠態(tài)時(shí),它的靜態(tài)優(yōu)先級按位存放在waiter域中。如果靜態(tài)優(yōu)先級為N的任務(wù)在等待某個(gè)同步對象,則waiter二進(jìn)制數中第N位置1,以示等待。當type為EVENT_OBJECT時(shí),表示事件對象,此時(shí)num為事件狀態(tài),1表示通知態(tài),0表示未通知態(tài);為SEMAPHORE_OBJECT時(shí),表示信標對象,對應的num為可用資源數。

??內核同步對象不是嵌入式多任務(wù)系統特有的,通用的多任務(wù)操作系統如Windows都提供齊全的同步函數,在此不作介紹。

6 運用和使用示例

??在MicroStar中,各個(gè)功能模塊是分開(kāi)的,因而可裁減度高。移植MicroStar也比較容易,只需改寫(xiě)與硬件相關(guān)的任務(wù)創(chuàng )建和調度函數。MicroStar1.0的PC機完全版本的代碼約為10KB,針對96單片機用匯編語(yǔ)言寫(xiě)成的版本為1.4KB。本文附帶的演示示例,都在TC2.0下編譯通過(guò),可直接在PC機上運行。第一個(gè)示例啟動(dòng)了三個(gè)用戶(hù)任務(wù):① WatchTask任務(wù)在屏幕中央顯示一個(gè)以10ms為計時(shí)單位的跑表。② KeyTask 任務(wù)每隔200ms讀一次鍵盤(pán),按“Q”鍵系統退出執行。③ MicroStar 任務(wù)顯示MicroStar相關(guān)信息,每隔1.5s更新一幀。

??演示程序及內核源碼見(jiàn)本刊網(wǎng)站(www.dpj.com.cn)。

結 語(yǔ)

??本文提出了基于事件的優(yōu)先級這一觀(guān)念,使任務(wù)優(yōu)先級的安排更為合理。介紹了多任務(wù)實(shí)時(shí)內核――MicroStar的設計與實(shí)現。消息和信號兩種通信方式的提供,使其對事件驅動(dòng)編程有很好的支持。較為完善的定時(shí)器服務(wù)和齊全的任務(wù)同步函數庫,給用戶(hù)提供了更多、更靈活的選擇。有限的功能,使其與其它實(shí)時(shí)操作系統相比,減小了從技術(shù)掌握上所花費的時(shí)間。加上較低的存儲器消耗,總體上說(shuō),MicroStar是比較適合在中低端MCU平臺上運行的。



評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>