《uCOOS-II原理與ARM應(yīng)用程序設(shè)計(jì)》課件第5章_第1頁
《uCOOS-II原理與ARM應(yīng)用程序設(shè)計(jì)》課件第5章_第2頁
《uCOOS-II原理與ARM應(yīng)用程序設(shè)計(jì)》課件第5章_第3頁
《uCOOS-II原理與ARM應(yīng)用程序設(shè)計(jì)》課件第5章_第4頁
《uCOOS-II原理與ARM應(yīng)用程序設(shè)計(jì)》課件第5章_第5頁
已閱讀5頁,還剩158頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第五章任務(wù)協(xié)作與通信

5.1信號(hào)量OS_SEM.C5.2互斥型信號(hào)量OS_MUTEX.C5.3消息郵箱OS_MBOX.C5.4消息隊(duì)列OS_Q.C5.5事件標(biāo)志OS_FLAG.C5.6多事件請(qǐng)求處理5.7μC/OS-Ⅱ組件配置OS_CFG.H5.8本章小結(jié)信號(hào)量本質(zhì)上是一個(gè)全局指針變量,定義為一個(gè)任務(wù)(或中斷服務(wù)程序)通知另一個(gè)任務(wù)可以執(zhí)行的事件量,如果任務(wù)中使用OSSemPend函數(shù)請(qǐng)求信號(hào)量,當(dāng)請(qǐng)求到信號(hào)量(即信號(hào)量的值大于0)時(shí),則該任務(wù)可以執(zhí)行,否則等待(即進(jìn)入等待該信號(hào)量就緒的等待事件列表中)。發(fā)送信號(hào)量的任務(wù)中使用OSSemPost,每調(diào)用一次該函數(shù),信號(hào)量的值加1。這樣,發(fā)送信號(hào)量的任務(wù)可以通過定時(shí)發(fā)送信號(hào)量(或稱釋放信號(hào)量)控制請(qǐng)求信號(hào)量的任務(wù)的運(yùn)行與否。5.1信號(hào)量OS_SEM.C當(dāng)任務(wù)使用OSSemAccept請(qǐng)求信號(hào)量時(shí),如果請(qǐng)求到信號(hào)量,即信號(hào)量的值大于0,則返回該信號(hào)量的值;如果沒有請(qǐng)求到信號(hào)量,則返回0值。無論信號(hào)量請(qǐng)求到與否,使用OSSemAccept的任務(wù)都不會(huì)等待該信號(hào)量,而是繼續(xù)執(zhí)行。因此,OSSemAccept一般用于中斷服務(wù)程序中。

信號(hào)量在使用前,應(yīng)調(diào)用OSSemCreate創(chuàng)建信號(hào)量;如果信號(hào)量不再使用了,可調(diào)用OSSemDel刪除信號(hào)量;調(diào)用OSSemQuery可查詢信號(hào)量的狀態(tài);調(diào)用OSSemPendAbort使等待該信號(hào)量的所有任務(wù)就緒,如果沒有任務(wù)在請(qǐng)求該信號(hào)量,可以調(diào)用OSSemSet設(shè)置信號(hào)量的值。

由上述分析可知,與信號(hào)量相關(guān)的函數(shù)有8個(gè),列于第一章表1-7中。下面的實(shí)例ex5_1演示了這八個(gè)函數(shù)的使用方法。5.1.1工程ex5_1

在第四章工程ex4_3的基礎(chǔ)上,新建工程ex5_1,保存目錄為D:\ZYUCOSII\ex5_1(此時(shí)的工程ex5_1與工程ex4_3完全相同,只是工程文件名改為ex5_1),如圖5-1所示。在工程ex5_1中,修改文件app.h、appfun.c即得完整的工程ex5_1。

在app.h中添加一行定義語句“MY_APPOS_EVENT*LedSem;”,可以添加在任何位置,建議放在文件中的第56行處。信號(hào)量使用OS_EVENT結(jié)構(gòu)體類型定義。圖5-1工程ex5-1的最初版本在文件appfun.c中的AppTaskStart函數(shù)中添加兩行語句:

LedSem=OSSemCreate(3);

OSEventNameSet(LedSem,"Led_Sem",&err);

建議將上述兩行語句插入到第138行處。OSSemCreate用于創(chuàng)建信號(hào)量,只有一個(gè)參數(shù),即信號(hào)量的初始值。OSEventNameSet函數(shù)位于第一章表1-3中,表示為事件命名,這里為信號(hào)量LedSem命名為L(zhǎng)ed_Sem。然后,再修改appfun.c中的AppTask_1、AppTask_2和AppTask_3函數(shù),這三個(gè)函數(shù)在第5.1.2節(jié)中給出了完整的代碼,并給出了原理解釋。

此時(shí)編譯鏈接工程ex5_1,仿真運(yùn)行它,串口調(diào)試助手界面如圖5-2所示。圖中的TimeTickCur為時(shí)鐘節(jié)拍值,除以100后的單位為秒,LedSemCnt為信號(hào)量的值。工程ex5_1中只創(chuàng)建了一個(gè)信號(hào)量,μC/OS-Ⅱ支持創(chuàng)建多個(gè)信號(hào)量。

觀察UP-Star板上的LED燈,可以看到這種現(xiàn)象:運(yùn)行后前10秒內(nèi),三個(gè)LED燈每1秒閃一次;從第10秒至第30秒,LED不再閃爍;第30~50秒時(shí)又開始每1秒閃一次;第50秒后,每3秒閃一次。圖5-2工程ex5_2的串口調(diào)試助手界面5.1.2工程ex5_1代碼與注解

文件appfun.c中的函數(shù)AppTask_1、AppTask_2和AppTask_3的代碼羅列如下:

1voidAppTask_1(void*pdata)

2{

3INT8Uerr;

4INT8Ss[80];

5INT32UtickCur; //Timetick'scurrentval

6

7OS_SEM_DATAsem_data;

8

在AppTask_1中定義了一個(gè)信號(hào)量數(shù)據(jù)類型(OS_SEM_DATA)的變量sem_data(第7行)。進(jìn)入循環(huán)體后,第16~19行判斷當(dāng)時(shí)鐘節(jié)拍值小于1000時(shí),每隔1秒釋放一次信號(hào)量。每隔1秒的操作體現(xiàn)在第44行,釋放信號(hào)量即使信號(hào)量LedSem的計(jì)數(shù)值加1。在AppTask_3中,第76~81行判斷信號(hào)量是否存在,如果存在,不斷申請(qǐng)信號(hào)量LedSem,由于任務(wù)3沒有延時(shí),因此,只要LedSem的計(jì)數(shù)值大于0,則任務(wù)3將不斷地執(zhí)行。因此,程序開始執(zhí)行后,任務(wù)3按任務(wù)1釋放信號(hào)量的時(shí)間間隔(即1秒)運(yùn)行,這里3個(gè)LED燈每隔1秒閃動(dòng)一次。第20行,當(dāng)時(shí)鐘節(jié)拍經(jīng)過了10秒,還沒有達(dá)到30秒時(shí),將任務(wù)3掛起,這時(shí)LED不再閃爍;然后,調(diào)用OSSemPendAbort將等待信號(hào)量LedSem的任務(wù)釋放掉,第24行判斷如果沒有任務(wù)請(qǐng)求信號(hào)量LedSem,則第26行調(diào)用OSSemSet將信號(hào)量的計(jì)數(shù)值設(shè)為10;第27行調(diào)用OSSemQuery查詢信號(hào)量LedSem的數(shù)據(jù),查詢結(jié)果存入sem_data中;第28~29行把信號(hào)量LedSem的計(jì)數(shù)值輸出到串口調(diào)試助手。

第32~36行,當(dāng)時(shí)鐘節(jié)拍經(jīng)過了30秒,還沒有到達(dá)50秒時(shí),恢復(fù)任務(wù)3的運(yùn)行,同時(shí)每隔1秒釋放信號(hào)量一次,此時(shí)三個(gè)LED燈又每隔1秒閃動(dòng)一次。第37~43行,當(dāng)時(shí)鐘節(jié)拍經(jīng)過了60秒,還沒有達(dá)到70秒時(shí),判斷信號(hào)量是否存在,如果存在,則調(diào)用OSSemDel刪除該信號(hào)量。OSSemDel有三個(gè)參數(shù),依次為信號(hào)量指針、刪除方式選項(xiàng)(這里使用了OS_DEL_ALWAYS)和返回信息。因此,過了50秒后,信號(hào)量LedSem不存在了。第76行判斷為假,將執(zhí)行第83~86行的代碼,即每隔3秒三個(gè)LED閃動(dòng)一次。

顯然,當(dāng)過了70秒以后,任務(wù)1幾乎什么都不做了,只是簡(jiǎn)單地延時(shí)1秒輸出時(shí)鐘節(jié)拍的值。這時(shí),任務(wù)3就一直每隔3秒使三個(gè)LED燈閃動(dòng)一次地工作下去?,F(xiàn)在,看一下任務(wù)2,即AppTask_2函數(shù),第62行調(diào)用OSSemAccept函數(shù)請(qǐng)求信號(hào)量LedSem,這個(gè)函數(shù)的返回值為信號(hào)量的計(jì)數(shù)值,從圖5-2中可以看出,運(yùn)行第一次時(shí)返回的值為4,以后的值都為0。這是因?yàn)椋贏ppTaskStart函數(shù)初始化信號(hào)量LedSem的計(jì)數(shù)值為3,而后在AppTask_1中釋放該信號(hào)量時(shí),它的計(jì)數(shù)值又加了1,由于任務(wù)2的優(yōu)先級(jí)比任務(wù)3的優(yōu)先級(jí)要高,所以執(zhí)行完任務(wù)1后執(zhí)行任務(wù)2,將顯示此時(shí)的信號(hào)量計(jì)數(shù)值為4。但是由于任務(wù)3沒有延時(shí),只要信號(hào)量LedSem存在且它的計(jì)數(shù)值大于0,任務(wù)3就一直運(yùn)行,直到信號(hào)量LedSem的計(jì)數(shù)值為0為止。所以,直到任務(wù)3開始運(yùn)行后,信號(hào)量的值將為0,故圖5-2上顯示后續(xù)的信號(hào)量計(jì)數(shù)值為0。由于OSSemAccept函數(shù)請(qǐng)求信號(hào)量并不等待,但是,如果申請(qǐng)到了信號(hào)量,信號(hào)量的計(jì)數(shù)值也要減1。所以,從第62~65行可看出任務(wù)2每隔3秒執(zhí)行一次,即每隔3秒將信號(hào)量的計(jì)數(shù)值輸出到串口調(diào)試助手上。經(jīng)過分析可知,任務(wù)2在第一次運(yùn)行后,再也申請(qǐng)不到信號(hào)量了。

在第六章中還將把信號(hào)量用于中斷處理上。本節(jié)把信號(hào)量相關(guān)的8個(gè)函數(shù)都使用了,但這絕不是推薦讀者也這樣做。實(shí)際上,常用的信號(hào)量函數(shù)只有創(chuàng)建OSSemCreate、釋放OSSemPost和請(qǐng)求OSSemPend等三個(gè)而已,作者為了使用全部的8個(gè)函數(shù),顯然使得程序有些畫蛇添足。讀者需要針對(duì)自己的應(yīng)用需要來決定是否使用信號(hào)量、用幾個(gè)信號(hào)量以及用多少個(gè)與信號(hào)量相關(guān)的函數(shù)。本章后續(xù)章節(jié)中也存在著類似的現(xiàn)象。全局變量可以被多個(gè)任務(wù)同時(shí)訪問,稱之為共享資源?;コ庑托盘?hào)量可以實(shí)現(xiàn)一個(gè)任務(wù)對(duì)共享資源的獨(dú)占式訪問,即當(dāng)一個(gè)任務(wù)訪問共享資源時(shí),其他要訪問該共享資源的任務(wù)需等到該任務(wù)使用完共享資源后再進(jìn)行訪問。假設(shè)兩個(gè)任務(wù)需要訪問同一個(gè)共享資源,當(dāng)?shù)蛢?yōu)先級(jí)的任務(wù)A正在使用共享資源時(shí),優(yōu)先級(jí)高的任務(wù)B就緒了,由于其優(yōu)先級(jí)高,所以B任務(wù)取得了CPU使用權(quán),但是由于共享資源仍被A占用著,所以B處于等待狀態(tài),而A由于丟失了CPU使用權(quán),也處于等待狀態(tài),這就是眾所周知的“死鎖”。5.2互斥型信號(hào)量OS_MUTEX.C

μC/OS-Ⅱ中處理這種現(xiàn)象的方法是提高A的優(yōu)先級(jí),使之高于任務(wù)B,這樣任務(wù)A會(huì)先于任務(wù)B執(zhí)行完,并釋放共享資源,然后再恢復(fù)任務(wù)A的優(yōu)先級(jí),這種處理稱為優(yōu)先級(jí)反轉(zhuǎn),任務(wù)A提高的優(yōu)先級(jí)稱為優(yōu)先級(jí)繼承優(yōu)先級(jí)(PIP,PriorityInheritancePriority)。

互斥信號(hào)量是二值信號(hào)量,只有0和1兩個(gè)狀態(tài),其相關(guān)的函數(shù)有6個(gè),即OSMutexCreate、OSMutexPend、OSMutexPost、OSMutexDel、OSMutexQuery和OSMutexAccept,列于第一章表1-8中。使用互斥型信號(hào)量時(shí),需用OSMutexCreate創(chuàng)建一個(gè)互斥型信號(hào)量;在任務(wù)要使用共享資源前,調(diào)用函數(shù)OSMutexPend保護(hù)共享資源,在使用完共享資源后,調(diào)用OSMutexPost釋放互斥型信號(hào)量;每個(gè)需要訪問共享資源的任務(wù)使用共享資源的方法都是如此。當(dāng)互斥型信號(hào)量不再需要時(shí),可以調(diào)用OSMutexDel刪除它,刪除時(shí)要十分小心,必須同時(shí)要求它所管理的共享資源也不再使用了??梢哉{(diào)用OSMutexQuery查詢互斥信號(hào)量的信息。函數(shù)OSMutexAccept與OSMutexPend的作用相似,都是請(qǐng)求互斥信號(hào)量,但是,OSMutexAccept在請(qǐng)求不到互斥信號(hào)量時(shí)不會(huì)等待,而是繼續(xù)運(yùn)行,但是如果獲得了互斥信號(hào)量,必須在使用完共享資源后,調(diào)用OSMutexPost釋放互斥型信號(hào)量。5.2.1工程ex5_2

在工程ex5_1的基礎(chǔ)上新建工程ex5_2,保存目錄為D:\ZYUCOSII\ex5_2,此時(shí)的工程ex5_2與工程ex5_1完全相同,只是工程文件名改為ex5_1。需要修改的文件有app.h和appfun.c。工程ex5_2如圖5-3所示。圖5-3工程ex5_2在app.h中原來定義信號(hào)量的語句“MY_APPOS_EVENT*LedSem;”處,替換為如圖5-3中圈住的兩行語句,即

MY_APPOS_EVENT*LedMutex;

MY_APPFP32x0;

上述語句定義了一個(gè)互斥信號(hào)量LedMutex和一個(gè)浮點(diǎn)數(shù)全局變量x0。同時(shí),在app.h文件的末尾添加對(duì)自定義函數(shù)myRand3的聲明,即

INT8UmyRand3(void);//Generaterand1~3

這個(gè)函數(shù)體位于appfun.c中。文件appfun.c中需要修改函數(shù)AppTaskStart、AppTask_1、AppTask_2和AppTask_3,并添加函數(shù)myRand3。

將AppTaskStart函數(shù)中原來創(chuàng)建信號(hào)量的語句

LedSem=OSSemCreate(3);

OSEventNameSet(LedSem,"Led_Sem",&err);

替換為以下語句:

1LedMutex=OSMutexCreate(4,&err);

2if(err==OS_ERR_NONE)

3{

4OSEventNameSet(LedMutex,"Led_Mutex",&err);

5}

6x0=0.412;第1行創(chuàng)建一個(gè)互斥信號(hào)量,變量名為L(zhǎng)edMutex,優(yōu)先級(jí)繼承優(yōu)先級(jí)為4。第2行判斷創(chuàng)建互斥信號(hào)量是否成功,如果成功,則第4行將互斥信號(hào)量命名為字符串Led_Mutex,這個(gè)名稱一般用作調(diào)試。當(dāng)調(diào)試工程ex5_2時(shí),在80秒內(nèi)暫停運(yùn)行,如圖5-4所示,可以打開C-SPY查看互斥信號(hào)量LedMutex。圖5-4工程ex5_2調(diào)試窗口任務(wù)AppTask_1、AppTask_2和AppTask_3以及新添加的函數(shù)myRand3的代碼列于第5.2.2節(jié)中,并在那里對(duì)其工作原理進(jìn)行解釋。

仿真運(yùn)行工程ex5_2,觀察計(jì)算機(jī)顯示的串口調(diào)試助手,如圖5-5所示。當(dāng)運(yùn)行時(shí)間低于80秒時(shí),依次顯示三個(gè)任務(wù)中的隨機(jī)數(shù)值,并顯示互斥信號(hào)量LedMutex的PIP;當(dāng)超過80秒后,顯示LedMutex被刪除。表現(xiàn)在三個(gè)LED燈上,在80秒之前呈隨機(jī)閃爍狀態(tài);80秒以后,每隔3秒三個(gè)LED燈閃動(dòng)一次。圖5-5串口調(diào)試助手輸出結(jié)果5.2.2工程ex5_2代碼與注解

以下為任務(wù)AppTask_1、AppTask_2、AppTask_3以及myRand3的代碼(這些函數(shù)位于appfun.c中):

1voidAppTask_1(void*pdata)

2{

3INT8Uerr;

4INT8Ss[80];上述代碼第111~119行為自定義的產(chǎn)生1~3隨機(jī)數(shù)的函數(shù),其中x0是全局變量,這個(gè)函數(shù)是不可重入型的。因此,如果有多個(gè)任務(wù)需要使用這個(gè)函數(shù),需要使用互斥信號(hào)量保護(hù),即不能讓多個(gè)任務(wù)同時(shí)訪問該函數(shù)。產(chǎn)生1~3隨機(jī)數(shù)的算法很簡(jiǎn)單,這里不贅述。在工程ex5_2中,任務(wù)1、2和3均調(diào)用了該函數(shù)?;氐饺蝿?wù)1的代碼,第8行定義了互斥信號(hào)量結(jié)構(gòu)體變量,用于保存互斥信號(hào)量的信息,其定義位于ucos_ii.h中第505~525行,請(qǐng)讀者自己查閱,其中的成員OSMutexPIP表示相應(yīng)互斥信號(hào)量的PIP。第17行判斷時(shí)鐘節(jié)拍小于6000,即運(yùn)行時(shí)間小于60秒時(shí),第19行請(qǐng)求互斥信號(hào)量(這里顯然能請(qǐng)求到),然后,運(yùn)行第20行,產(chǎn)生一個(gè)1~3的隨機(jī)數(shù)存入局部變量rnd中,之后第21行釋放LedMutex。第22行將根據(jù)產(chǎn)生的隨機(jī)數(shù)的值使相應(yīng)的LED燈閃動(dòng)。第23~24行輸出這個(gè)隨機(jī)數(shù)。因此,在60秒以內(nèi)時(shí)任務(wù)1使三個(gè)LED燈每隔1秒其中一個(gè)隨機(jī)閃動(dòng)一次。第27行判斷時(shí)間是否大于60秒且小于80秒,在這段時(shí)間里,查詢LedMutex的信息,如果查詢正確,則輸出它的PIP值。第38~46行是當(dāng)時(shí)間超過80秒且小于90秒時(shí),任務(wù)1將刪除互斥信號(hào)量LedMutex,如果刪除成功,第41行為真,將執(zhí)行第43~44行,輸出“Mutexhasbeendeleted!”。注意,這句話僅會(huì)輸出一次,如圖5-5所示,因?yàn)榈?1行只可能有一次為真。當(dāng)然,在90秒以后,任務(wù)1只是簡(jiǎn)單地處理第13~15行,即輸出時(shí)鐘節(jié)拍值,然后延時(shí)1秒?,F(xiàn)在,到任務(wù)2中,第66行調(diào)用OSMutexAccept函數(shù),這個(gè)函數(shù)與OSMutexPend的作用相似,只是OSMutexAccept申請(qǐng)到互斥信號(hào)量時(shí),返回OS_TRUE,并且要在使用完共享資源,即調(diào)用完myRand3后再調(diào)用一次OSMutexPost;申請(qǐng)不到時(shí),也不掛起任務(wù)。由任務(wù)1的解釋,可知80秒以前,任務(wù)2執(zhí)行第69~72行,即輸出隨機(jī)數(shù)的值;80秒以后執(zhí)行第76~77行的代碼,即輸出“Mutexdeleted!”。任務(wù)2每3秒運(yùn)行一次。任務(wù)3中第93行首先判斷互斥信號(hào)量是否存在,如果存在,則申請(qǐng)互斥信號(hào)量LedMutex,然后第96行使用myRand3函數(shù),第97行釋放LedMutex,第98行根據(jù)隨機(jī)數(shù)的值閃動(dòng)LED燈,第99~100行輸出隨機(jī)數(shù)的值,第101行延時(shí)2秒。如果第103行互斥信號(hào)量LedMutex不存在了,則第105~106行第3秒三個(gè)LED同時(shí)閃動(dòng)一次。

工程ex5_2使用了互斥信號(hào)量的全部6個(gè)函數(shù),這樣做是為了介紹互斥信號(hào)量的用法,讀者自己的程序中應(yīng)視需要進(jìn)行函數(shù)的選用。這里也僅創(chuàng)建了一個(gè)互斥型信號(hào)量,μC/OS-Ⅱ允許創(chuàng)建多個(gè)互斥型信號(hào)量。任務(wù)之間可以通過用戶定義的擴(kuò)展數(shù)據(jù)結(jié)構(gòu)進(jìn)行數(shù)據(jù)通信,在使用OSTaskCreateExt函數(shù)創(chuàng)建任務(wù)時(shí),指定其倒數(shù)第2個(gè)參數(shù)即可,這種任務(wù)間的數(shù)據(jù)通信本質(zhì)上依靠全局變量來實(shí)現(xiàn)。而通過消息郵箱同樣可以實(shí)現(xiàn)任務(wù)間的數(shù)據(jù)交換,消息郵箱是很重要的一類事件,這種類型的任務(wù)間數(shù)據(jù)通信是通過局部變量和函數(shù)傳遞來實(shí)現(xiàn)的。5.3消息郵箱OS_MBOX.C消息郵箱相關(guān)的函數(shù)有8個(gè),即OSMboxCreate、OSMboxPend、OSMboxPost、OSMboxPostOpt、OSMboxDel、OSMboxPendAbort、OSMboxAccept和OSMboxQuery,羅列在第一章表1-9中。使用消息郵箱時(shí),必須調(diào)用OSMboxCreate函數(shù)創(chuàng)建一個(gè)消息郵箱,創(chuàng)建時(shí)可以給郵箱賦予字符串值,也可以通過賦NULL,生成一個(gè)空郵箱;任務(wù)在請(qǐng)求郵箱中的消息時(shí),使用OSMboxPend和OSMboxAccept,后者在申請(qǐng)不到消息時(shí),任務(wù)不會(huì)被掛起;通過調(diào)用OSMboxPost和OSMboxPostOpt向郵箱發(fā)送一則消息,OSMboxPostOpt可以向請(qǐng)求該郵箱的所有任務(wù)發(fā)送消息,也可僅向請(qǐng)求該郵箱的最高優(yōu)先級(jí)任務(wù)發(fā)送消息,比OSMboxPost更靈活;當(dāng)郵箱不再使用時(shí),通過調(diào)用OSMboxDel刪除郵箱,刪除郵箱時(shí)要十分小心,應(yīng)把請(qǐng)求該郵箱的任務(wù)都取消后再刪除,以免程序不工作;可以調(diào)用OSMboxQuery查詢消息郵箱的信息;而調(diào)用OSMboxPendAbort將使等待該郵箱的任務(wù)都放棄等待而進(jìn)入就緒態(tài)。

本節(jié)的工程ex5_3演示了這些函數(shù)的使用方法。5.3.1工程ex5_3

在工程ex5_1的基礎(chǔ)上新建工程ex5_3,存儲(chǔ)目錄為D:\ZYUCOSII\ex5_3(此時(shí)的工程ex5_3與ex5_1完全相同,只是工程文件名更改為ex5_3)。需要修改的文件有app.h和appfun.c。

將文件app.h中的代碼“MY_APPOS_EVENT*LedSem;”替換為以下語句:

MY_APPOS_EVENT*LedMbox;

表示定義消息郵箱事件,這里只是變量名不同,變量類型都是OS_EVENT*,參見圖5-6中部被圈住的語句。圖5-6工程ex5_3調(diào)試窗口將文件appfun.c內(nèi)AppTaskStart函數(shù)中的兩行代碼

LedSem=OSSemCreate(3);

OSEventNameSet(LedSem,"Led_Sem",&err);

替換為以下兩行語句:

LedMbox=OSMboxCreate(NULL);

OSEventNameSet(LedMbox,"Led_Mbox",&err);表示創(chuàng)建一個(gè)空的消息郵箱,并為它命名為L(zhǎng)ed_Mbox,這個(gè)名稱主要用于調(diào)試。如果調(diào)試工程ex5_3,在調(diào)試窗口中打開C-SPY窗口,如圖5-6所示,可看到這個(gè)消息郵箱的名稱。

文件appfun.c中的AppTask_1、AppTask_2和AppTask_3修改的地方比較多,它們的代碼列于第5.3.2節(jié)。

當(dāng)仿真運(yùn)行工程ex5_3時(shí),在串口調(diào)試助手上可以看到如圖5-7所示的界面。圖5-7僅給出了運(yùn)行開始4秒時(shí)的界面,讀者需要自己運(yùn)行更長(zhǎng)的時(shí)間以觀察工程ex5_3的輸出

規(guī)律。圖5-7工程ex5_3運(yùn)行時(shí)串口調(diào)試助手界面情況5.3.2工程ex5_3功能注解

文件appfun.c中的AppTask_1、AppTask_2和AppTask_3函數(shù)的代碼如下:在任務(wù)1中,第7行定義字符串(即字符數(shù)組)myMessage;第16~20行,當(dāng)時(shí)鐘節(jié)拍小于2000時(shí),即執(zhí)行時(shí)間小于20秒時(shí),給myMessage賦字符串“1-Led1Flash”,然后第19行將該字符串通過郵箱LedMbox釋放出去。現(xiàn)在跳到任務(wù)3的第112行,這里判斷事件類型是否為消息郵箱,然后,第114行調(diào)用OSMboxPend請(qǐng)求該郵箱中的消息,其中第2個(gè)參數(shù)賦為OS_TICKS_PER_SEC表示請(qǐng)求超時(shí)為1秒,如果1秒內(nèi)請(qǐng)求不到郵箱,則放棄等待,而繼續(xù)運(yùn)行。顯然,這里可以請(qǐng)求到消息郵箱LedMbox,返回值pmsg為myMessage的內(nèi)容;第115行,提取消息字符串的第一個(gè)字符,這里應(yīng)為1,則執(zhí)行第117~119行,即LED1燈閃動(dòng)一次,并輸出字符串“1-Led1Flash”到串口調(diào)試助手。再到任務(wù)2,任務(wù)2在第67行定義了OS_MBOX_DATA類型的變量mbox_dat,用于存放消息郵箱的信息,其中的OSMsg成員即為郵箱中的消息字符串。工程ex5_3開始運(yùn)行時(shí),由于任務(wù)1的優(yōu)先級(jí)最高,所以任務(wù)1將先于任務(wù)2和3運(yùn)行,釋放一個(gè)消息郵箱;然后由于任務(wù)2優(yōu)先級(jí)高于優(yōu)務(wù)3,所以,任務(wù)2得到運(yùn)行,即第76行得到執(zhí)行,于是,第79~81行輸出消息郵箱中的消息字符串,如圖5-7中最上方圈住的字符串“Task2Query:1-Led1Flash!”。然后,任務(wù)2繼續(xù)運(yùn)行第82行及其以后的代碼,此時(shí),pmsg的第一個(gè)字符應(yīng)為1,所以第85行代碼為假,故第87~90行代碼得不到運(yùn)行。除了第一次運(yùn)行工程ex5_3,任務(wù)2中的第76行OSMboxAccept能請(qǐng)求到消息郵箱外,以后的每次運(yùn)行,OSMboxAccept均請(qǐng)求不到消息郵箱LedMbox,主要是因?yàn)槿蝿?wù)3處于無延時(shí)請(qǐng)求狀態(tài),即只要郵箱中包含消息,任務(wù)3就可以啟動(dòng),把消息取走。所以,圖5-7中第8行開始均顯示“Task2failedtoAskMbox”。再回到任務(wù)1中,在20秒以前,LED1燈會(huì)每隔1秒閃動(dòng)一次;第21~25行說明程序運(yùn)行20~40秒間,任務(wù)1釋放消息為“2-Led2Flash!”。再跳至任務(wù)3,此時(shí),第121行判斷為真,于是第123~125行運(yùn)行,LED燈2閃動(dòng),并且輸出“2-Led2Flash!”至串口調(diào)試助手。仍回到任務(wù)1中,在第26~30行,任務(wù)1釋放消息“3-Led3Flash!”,于是導(dǎo)致任務(wù)3的第127~133行執(zhí)行,即LED燈3閃動(dòng),并且輸出“3-Led3Flash!”至串口調(diào)試助手。任務(wù)1的第31~35行,使用OSMboxPostOpt釋放消息,由于使用了參數(shù)OS_POST_OPT_BROADCAST,這時(shí),如果有多個(gè)任務(wù)請(qǐng)求該消息郵箱,則每個(gè)任務(wù)都將得到消息“3-Led3Flash!”。在工程ex5_3中,卻只有任務(wù)3得到消息,這里需要注意,任務(wù)2是得不到消息的,因?yàn)槿蝿?wù)2中使用OSMboxAccept函數(shù),這個(gè)函數(shù)不會(huì)導(dǎo)致任務(wù)2進(jìn)入該消息郵箱的等待列表中;而OSMboxPostOpt當(dāng)使用參數(shù)OS_POST_OPT_

BROADCAST時(shí),將使所有進(jìn)入等待列表中的任務(wù)得到郵箱中的消息。請(qǐng)讀者將任務(wù)2中的OSMboxAccept修改為OSMboxPend后,自行試驗(yàn)一下,修改后將使得60~80秒間任務(wù)2和3都能收到消息“3-Led3Flash!”。第36~48行的代碼意義不大,這里僅是為了演示OSMboxPendAbort函數(shù)的使用而寫了一段代碼,使得80~100秒時(shí)等待消息郵箱的事件跳出等待而斷續(xù)運(yùn)行。在串口調(diào)試助手中將顯示“NoMessageinLedMbox!”。

第49~56行調(diào)用OSMboxDel刪除消息郵箱,由于刪除成功后,第52行語句只可能有一次為真,故僅能執(zhí)行一次第54行代碼。由上述解釋可知,通過消息郵箱可以在任務(wù)間傳遞數(shù)據(jù)。此外,Labrosse先生的書中還指出郵箱可用作二值信號(hào)量、計(jì)數(shù)用信號(hào)量以及延時(shí)處理等。常用的消息郵箱函數(shù)主要是創(chuàng)建郵箱OSMboxCreate、釋放郵箱OSMboxPost和OSMboxPostOpt以及請(qǐng)求郵箱OSMboxPend三種。消息隊(duì)列可以看做消息郵箱的數(shù)組形式,消息郵箱一次只能傳遞一則消息,而消息隊(duì)列可以一次傳遞多則消息。使用消息隊(duì)列前,調(diào)用函數(shù)OSQCreate創(chuàng)建消息隊(duì)列;發(fā)送消息方通過函數(shù)OSQPost、OSQPostFront和OSQPostOpt釋放消息至消息隊(duì)列中,OSQPost是先進(jìn)先出(FIFO)工作方法,OSQPostFront是后進(jìn)先出(LIFO)方式,OSQPostOpt可以根據(jù)選項(xiàng)參數(shù)設(shè)置工作方式;5.4消息隊(duì)列OS_Q.C接收消息方通過OSQPend或OSQAccept請(qǐng)求消息,OSQAccept無論請(qǐng)求到消息與否,均不掛起任務(wù)等待;調(diào)用函數(shù)OSQFlush可以清空消息隊(duì)列中的消息;調(diào)用OSQQuery查詢消息隊(duì)列的信息;當(dāng)消息隊(duì)列不再使用時(shí),可調(diào)用OSQDel刪除消息隊(duì)列;可調(diào)用函數(shù)OSQPendAbort取消請(qǐng)求消息隊(duì)列的任務(wù)的等待狀態(tài),使這些任務(wù)就緒。

消息隊(duì)列相關(guān)的函數(shù)即為上述的10個(gè)函數(shù),列于第一章表1-10中,本節(jié)實(shí)例工程ex5_4演示了這些函數(shù)的使用方法。5.4.1工程ex5_4

在工程ex5_1的基礎(chǔ)上新建工程ex5_4,保存目錄為D:\ZYUCOSII\ex5_4(此時(shí)的工程ex5_4與工程ex5_1完全相同,只是工程文件名更改為ex5_4)。需要修改的文件有app.h和appfun.c。

將文件app.h中原來定義信號(hào)量的語句“MY_APPOS_EVENT*LedSem;”替換為以下兩行語句:

MY_APPOS_EVENT*LedQ;

MY_APPvoid*myQMessage[10];

即定義消息隊(duì)列LedQ和具有10個(gè)成員的void*型數(shù)組用于存儲(chǔ)消息。文件appfun.c需要修改四個(gè)函數(shù),即AppTaskStart、AppTask_1、AppTask_2和AppTask_3。其中將AppTaskStart函數(shù)中原來創(chuàng)建信號(hào)量的語句

LedSem=OSSemCreate(3);

OSEventNameSet(LedSem,"Led_Sem",&err);

替換為以下語句:

LedQ=OSQCreate(&myQMessage[0],10);

OSEventNameSet(LedQ,"Led_Q",&err);

即創(chuàng)建消息隊(duì)列LedQ,最多可容納的消息數(shù)為10,把消息隊(duì)列命名為L(zhǎng)ed_Q,這個(gè)名稱一般用于調(diào)試。

AppTask_1、AppTask_2和AppTask_3的內(nèi)容將在第5.4.2節(jié)列出并解釋其工作原理。

仿真運(yùn)行ex5_4,界面如圖5-8所示,在C-SPY中可以查看消息隊(duì)列的狀態(tài),如圖中被圈住的部分。串口調(diào)試助手的輸出界面如圖5-9所示。圖5-8工程ex5_4仿真運(yùn)行界面圖5-9串口調(diào)試助手界面5.4.2工程ex5_4功能注解

文件appfun.c中任務(wù)AppTask_1、AppTask_2和AppTask_3的代碼如下:第8行定義了一個(gè)二維數(shù)組myMessage,能存放20個(gè)長(zhǎng)度不超過80的消息(注意,第5.4.1節(jié)創(chuàng)建了只能存放10個(gè)消息的隊(duì)列)。第10~13行初始化myMessage數(shù)組。第21~25行,當(dāng)執(zhí)行時(shí)間低于20秒時(shí),任務(wù)1調(diào)用OSQPost函數(shù)向隊(duì)列LedQ中添加10個(gè)消息,即myMessage[0]至myMessage[9];如果程序第一次運(yùn)行,則跳至任務(wù)2,第74行查詢消息隊(duì)列LedQ,此時(shí),查得的信息存入q_dat變量中,顯然,此時(shí)的第77~82行輸出查到的消息Mymessage1。第84行OSQAccept將請(qǐng)求到第一條消息,任務(wù)2進(jìn)入延時(shí)(第91行)。由于任務(wù)3的優(yōu)先級(jí)較任務(wù)2低,任務(wù)2執(zhí)行完后,任務(wù)3得到執(zhí)行,第105行任務(wù)3調(diào)用OSQPend請(qǐng)求消息隊(duì)列,由于其中的“Mymessage1”被任務(wù)2請(qǐng)求了,故剩下的9則消息將被任務(wù)3請(qǐng)求到,并通過串口調(diào)試助手顯示出來(第109~110行)。這里任務(wù)3沒有延時(shí)OSTimeDly等,不斷執(zhí)行第105行請(qǐng)求消息隊(duì)列(第105行的OSQPend函數(shù)的超時(shí)選項(xiàng)設(shè)為OS_TICKS_PER_SEC,即請(qǐng)求等待1秒后任務(wù)3繼續(xù)執(zhí)行,又重回到第105行),導(dǎo)致在以后的運(yùn)行過程中任務(wù)2很難請(qǐng)求到消息(只有任務(wù)3在請(qǐng)求到消息1至消息10的過程中,任務(wù)2就緒了才能請(qǐng)求到)。第26~32行說明執(zhí)行時(shí)間小于40秒而大于20秒時(shí),第28行調(diào)用OSQFlush清空隊(duì)列中的所有消息;第30~31行使用OSQPostFront函數(shù)向隊(duì)列釋放10個(gè)消息,OSQPostFront采用插入消息的方式,即滿足先進(jìn)后出(LIFO)的工作方式。這樣,任務(wù)3第105行不斷請(qǐng)求消息隊(duì)列后的輸出應(yīng)如圖5-9所示,即先輸出Mymessage1后,其余消息按LIFO的方式輸出,即依次輸出Mymessage10、Mymessage9直到最后輸出Mymessage2。這里需要說明一下,由于任務(wù)3始終處于請(qǐng)求隊(duì)列狀態(tài),Mymessage1直接送到任務(wù)3中了,所以,Mymessage1先送出來。因此,按這種工作方法,雖然隊(duì)列只能裝下10個(gè)消息,但實(shí)際上第30行的循環(huán)終止條件可以設(shè)為i<=10。

第33~37行與第26~32行的作用完全相同,這里使用的OSQPostOpt函數(shù)釋放消息,選項(xiàng)為OS_POST_OPT_FRONT,表示消息入隊(duì)方式是LIFO方式。如果選項(xiàng)為OS_POST_OPT_NONE,則為FIFO方式,即與OSQPost作用相同;如果選項(xiàng)為OS_POST_OPT_BROADCAST,則表示隊(duì)列中的消息將發(fā)送到所有等待隊(duì)列的任務(wù)中(這類任務(wù)不包括OSQAccept請(qǐng)求的任務(wù));還有幾個(gè)選項(xiàng)請(qǐng)參考“μC/OS-ⅡReferenceManual”手冊(cè)。第38~41行介紹OSQPendAbort函數(shù)的用法,這里使用選項(xiàng)OS_PEND_OPT_BROADCAST將取消所有請(qǐng)求消息隊(duì)列LedQ的任務(wù)的等待狀態(tài),使它們就緒。

第42~46行,即執(zhí)行到80秒至100秒之間時(shí),再次使用OSQPostOpt發(fā)送消息到隊(duì)列中,這里發(fā)送的消息是Mymessage11至Mymessage20,任務(wù)3將每3秒(第55行)把這些消息發(fā)送到串口調(diào)試助手上。第47~54行說明第100秒的時(shí)候,將調(diào)用OSQDel函數(shù)刪除消息隊(duì)列LedQ,由于第50行僅可能有一次為真,所以第52行僅輸出一次“LedQhasbeendeleted!”

第55行表示每3秒任務(wù)1運(yùn)行一次;第91行表示每5秒任務(wù)2運(yùn)行一次;當(dāng)100秒過后,LedQ被刪除了,任務(wù)3將執(zhí)行第114~117行的代碼,即每3秒三個(gè)LED燈閃動(dòng)一次。事件標(biāo)志可以理解為一種更加靈活的“位”信號(hào)量,基本原理為釋放事件標(biāo)志時(shí),使一個(gè)OS_FLAGS變量(默認(rèn)配置下為16位無符號(hào)整型)的某些位為1,另一些位為0;請(qǐng)求事件標(biāo)志時(shí),可以設(shè)計(jì)請(qǐng)求規(guī)則,即OS_FLAGS變量的某些位滿足特定條件時(shí),才執(zhí)行請(qǐng)求事件標(biāo)志的任務(wù)。5.5事件標(biāo)志OS_FLAG.C事件標(biāo)志相關(guān)的函數(shù)有9個(gè),列于第一章表1-11中。使用事件標(biāo)志時(shí),應(yīng)調(diào)用OSFlagCreate創(chuàng)建一個(gè)OS_FLAG_GRP*類型的事件標(biāo)志變量(這里不是OS_EVENT*類型);使用OSFlagPost釋放事件標(biāo)志;使用OSFlagPend請(qǐng)求事件標(biāo)志,請(qǐng)求到事件標(biāo)志后,可通過調(diào)用函數(shù)OSFlagPendGetFlagsRdy獲知事件標(biāo)志滿足的條件;查詢一個(gè)事件標(biāo)志的信息函數(shù)為OSFlagQuery;當(dāng)不使用事件標(biāo)志時(shí),調(diào)用函數(shù)OSFlagDel刪除它;在中斷處理函數(shù)或要求不被掛起的任務(wù)中可使用OSFlagAccept請(qǐng)求事件標(biāo)志;為事件標(biāo)志命名使用函數(shù)OSFlagNameSet;取得事件標(biāo)志的名稱使用函數(shù)OSFlagNameGet,這個(gè)名稱主要用于調(diào)試。下面詳細(xì)介紹OSFlagCreate、OSFlagPost和OSFlagPend的用法。

OS_FLAG_GRP*OSFlagCreate(OS_FLAGSflags,INT8U*perr);

其中,在os_cfg.h中定義OS_FLAGS_NBITS為16,這里OS_FLAGS相當(dāng)于INT16U,flags即為事件標(biāo)志的變量,其16個(gè)位即為事件標(biāo)志位。perr為OS_ERR_NONE時(shí)創(chuàng)建事件標(biāo)志成功。OSFlagCreate返回值為指向OS_FLAG_GRP結(jié)構(gòu)體類型的指針變量,簡(jiǎn)稱為事件標(biāo)志,這個(gè)結(jié)構(gòu)體定義位于ucos_ii.h文件的第429~436行,請(qǐng)讀者自己查閱。OS_FLAGSOSFlagPost(OS_FLAG_GRP*pgrp,

OS_FLAGSflags,

INT8Uopt,

INT8U*perr);其中,pgrp即為OSFlagCreate函數(shù)創(chuàng)建的事件標(biāo)志。flags即事件標(biāo)志的變量,這里為16位,如果想使其第13、11、8和3位為1,則flags取為0x2908,且此時(shí)opt必須取為OS_FLAG_SET;如果想其第13、11、8和3位為0,則flags仍取為0x2908,且此時(shí)opt必須取為OS_FLAG_CLR。opt取OS_FLAG_SET或OS_FLAG_CLR之一。perr為OS_ERR_NONE時(shí)釋放事件標(biāo)志成功。OSFlagPost返回新的事件標(biāo)志值。OS_FLAGSOSFlagPend(OS_FLAG_GRP*pgrp,

OS_FLAGSflags,

INT8Uwait_type,

INT16Utimeout,

INT8U*perr);其中,pgrp即為OSFlagCreate函數(shù)創(chuàng)建的事件標(biāo)志。flags為請(qǐng)求事件標(biāo)志的位模式,例如想請(qǐng)求第13位和第8位,則flags設(shè)為0x2100。wait_type為請(qǐng)求flags中選定位的方式,共有四種類型:OS_FLAG_WAIT_CLR_ALL要求請(qǐng)求的標(biāo)志位全為0;OS_FLAG_WAIT_CLR_ANY要求請(qǐng)求的標(biāo)志位至少有一位為0;OS_FLAG_WAIT_SET_ALL要求請(qǐng)求的標(biāo)志位全為1;OS_FLAG_WAIT_SET_ANY要求請(qǐng)求的標(biāo)志位至少有一位為1。滿足請(qǐng)求方式的任務(wù)得到CPU使用權(quán)。如果wait_type條件滿足后,想清除該事件標(biāo)志,則設(shè)置wait_type為上述四種方式的一種與OS_FLAG_CONSUME取或。timeout用于指定等待超時(shí)時(shí)間,超時(shí)1秒設(shè)為OS_TICKS_PER_SEC。perr為OS_ERR_NONE時(shí)表示調(diào)用OSFlagPend請(qǐng)求事件成功。

其他函數(shù)這里不再贅述。下面的工程ex5_5使用了事件標(biāo)志相關(guān)的所有9個(gè)函數(shù),將以實(shí)例的形式介紹這些函數(shù)的使用方法。5.5.1工程ex5_5

在工程ex5_1的基礎(chǔ)上新建工程ex5_5,保存目錄為D:\ZYUCOSII\ex5_5,此時(shí)的工程ex5_5與工程ex5_1完全相同,只是工程文件名更改為ex5_5。需要修改的文件有app.h和appfun.c,其中將文件app.h中原來定義信號(hào)量的語句“MY_APPOS_EVENT*LedSem;”替換為“MY_APPOS_FLAG_GRP*LedFlag;”,這里定義事件標(biāo)志使用OS_FLAGS_GRP*,而不是OS_EVENT*。文件appfun.c中需要修改的函數(shù)有AppTaskStart、AppTask_1、AppTask_2和AppTask_3,其中將AppTaskStart函數(shù)中原來創(chuàng)建信號(hào)量的語句

LedSem=OSSemCreate(3);

OSEventNameSet(LedSem,"Led_Sem",&err);

替換為以下語句:

LedFlag=OSFlagCreate(0x0000,&err);//CreateFlag

OSFlagNameSet(LedFlag,"Led_Flag",&err);即創(chuàng)建一個(gè)事件標(biāo)志LedFlag,并命名為L(zhǎng)ed_Flag,給事件標(biāo)志命名使用OSFlagNameSet,而不是OSEventNameSet。

函數(shù)AppTask_1、AppTask_2和AppTask_3由于修改較大,將在第5.5.2節(jié)中給出完整的代碼和注解。

工程ex5_5調(diào)試時(shí)的窗口如圖5-10所示,串口調(diào)試助手顯示界面如圖5-11所示。圖5-10工程ex5_5調(diào)試界面圖5-11串口調(diào)試助手顯示界面5.5.2工程ex5_5功能注解

文件appfun.c中函數(shù)AppTask_1、AppTask_2和AppTask_3的代碼如下:任務(wù)1中第16行~20行說明當(dāng)執(zhí)行時(shí)間小于20秒時(shí),每隔1秒(第33行)釋放一個(gè)事件標(biāo)志LedFlag,設(shè)置LedFlag標(biāo)志值的第1、3、5、7位為1。當(dāng)程序剛開始執(zhí)行時(shí),任務(wù)1釋放LedFlag后,進(jìn)入任務(wù)2(由于任務(wù)2的優(yōu)先級(jí)低于任務(wù)1而高于任務(wù)3),執(zhí)行第52~57行,查詢LedFlag的信息,并輸出它的值,此時(shí)輸出的值為圖5-11上部圈住的值,即0x00AA。然后,第58行使用不掛起等待的OSFlagAccept函數(shù)請(qǐng)求LedFlag,請(qǐng)求的方式為事件標(biāo)志值的第5、7位為1,申請(qǐng)到后并不清除事件標(biāo)志。第59~66行輸出申請(qǐng)到的事件標(biāo)志值,即0x00A0。第67行說明任務(wù)2延時(shí)3秒后再次請(qǐng)求事件標(biāo)志。然后,進(jìn)入任務(wù)3,任務(wù)3第81行判斷事件標(biāo)志還存在否,如果存在,則第83~87行使用OSFlagPend請(qǐng)求事件標(biāo)志LedFlag,請(qǐng)求方式為事件標(biāo)志的第1、3位為1,請(qǐng)求成功后清除事件標(biāo)志的第1、3位,請(qǐng)求超時(shí)為2秒。如果請(qǐng)求成功,則第88~96行輸出請(qǐng)求到的標(biāo)志位,即0x000A。注意第89~96行和第61~65行的不同點(diǎn),由于OSFlagPend請(qǐng)求事件標(biāo)志時(shí)當(dāng)前任務(wù)會(huì)進(jìn)入就緒事件列表中,所以,可以調(diào)用OSFlagPendGetFlagsRdy函數(shù)獲得請(qǐng)求成功的事件標(biāo)志值,而任務(wù)2中使用OSFlagAccept函數(shù)請(qǐng)求事件標(biāo)志,所以任務(wù)2中不能使用OSFlagPendGetFlagsRdy函數(shù)?;氐饺蝿?wù)1第16~20行,由于每1秒釋放事件標(biāo)志一次,并且任務(wù)3不斷請(qǐng)求,請(qǐng)求成功后還要清除相應(yīng)的事件標(biāo)志位,所以,在前20秒內(nèi),任務(wù)3每1秒請(qǐng)求到事件標(biāo)志一次。由于任務(wù)2請(qǐng)求事件標(biāo)志不清除相應(yīng)的事件標(biāo)志位,所以,任務(wù)2每3秒能請(qǐng)求到事件標(biāo)志一次。但是第52行查詢事件標(biāo)志信息時(shí),由于0x000A被任務(wù)3請(qǐng)求并清除了,所以在隨后的執(zhí)行過程中,查詢到的值為0x00A0。第21~23行,當(dāng)執(zhí)行時(shí)間大于20秒小于60秒時(shí),沒有釋放事件標(biāo)志。由于任務(wù)2的申請(qǐng)并不清除事件標(biāo)志,所以任務(wù)2在這段時(shí)間內(nèi)仍然每3秒申請(qǐng)到事件標(biāo)志一次。由于任務(wù)3每次申請(qǐng)到后,要清除相應(yīng)的事件標(biāo)志,所以這段時(shí)間內(nèi)任務(wù)3申請(qǐng)不到事件標(biāo)志,每2秒超時(shí)一次。第24~31行,當(dāng)執(zhí)行時(shí)間大于60秒而小于80秒時(shí),將刪除事件標(biāo)志。由于第27行僅有一次為真,故第29行僅執(zhí)行一次,即僅輸出一次事件標(biāo)志刪除信息到串口調(diào)試助手。事件標(biāo)志被刪除后,任務(wù)2幾乎什么都不做了。任務(wù)3第81行為假,故執(zhí)行第100~103行代碼,每3秒三個(gè)LED燈同時(shí)閃爍一下。

80秒以后,任務(wù)1只是每1秒簡(jiǎn)單地執(zhí)行第12~14行代碼,任務(wù)2沒做什么,任務(wù)3每3秒三個(gè)LED燈同時(shí)閃爍一下。從第5.5節(jié)關(guān)于事件標(biāo)志的介紹可知,一個(gè)事件標(biāo)志可以管理多個(gè)任務(wù)的請(qǐng)求。雖然一個(gè)信號(hào)量也可以有多個(gè)任務(wù)請(qǐng)求,但是信號(hào)量只有一個(gè),請(qǐng)求一個(gè)信號(hào)量的任務(wù)之間互相關(guān)聯(lián)著(指按優(yōu)先級(jí)高低獲得執(zhí)行權(quán));而事件標(biāo)志可以相當(dāng)于多個(gè)信號(hào)量的組合,多個(gè)任務(wù)按不同的請(qǐng)求模式,可以相互間毫無關(guān)聯(lián)地工作著(請(qǐng)求不同事件標(biāo)志位模式的任務(wù)間按就緒先后獲得執(zhí)行權(quán))。因此,事件標(biāo)志可以看做“一事件多任務(wù)”的請(qǐng)求處理模式。5.6多事件請(qǐng)求處理

μC/OS-ⅡV2.86版也支持“多事件一任務(wù)”的請(qǐng)求處理模式,即一個(gè)任務(wù)同時(shí)請(qǐng)求多個(gè)事件(這里的事件是指信號(hào)量、消息郵箱或消息隊(duì)列),只要其中一個(gè)事件滿足要求,則任務(wù)即可運(yùn)行。這時(shí),可以有多個(gè)任務(wù)請(qǐng)求多個(gè)事件,但是在這種情況下,只有優(yōu)先級(jí)最高的就緒任務(wù)得到執(zhí)行權(quán)。

“多事件一任務(wù)”請(qǐng)求函數(shù)為OSEventPendMulti,列于第一章表1-3中,本節(jié)的工程ex5_6將介紹這一函數(shù)的用法,同時(shí)將介紹表1-3中的OSSchedLock和OSSchedUnlock函數(shù),這兩個(gè)函數(shù)用于給當(dāng)前任務(wù)加鎖和解鎖,加鎖后的任務(wù)在執(zhí)行過程中不能被調(diào)度,任務(wù)加鎖后不能使用能使任務(wù)掛起的函數(shù),否則程序會(huì)死鎖。一般地,這兩個(gè)函數(shù)配對(duì)使用。中斷服務(wù)程序中也不能使用具有掛起等待功能的函數(shù)。5.6.1工程ex5_6

在工程ex5_1的基礎(chǔ)上新建工程ex5_6,保存目錄為D:\ZYUCOSII\ex5_6,此時(shí)的工程ex5_6與工程ex5_1完全相同,只是工程文件名更改為ex5_6。需要修改的文件有app.h和appfun.c。其中,文件app.h中在原來定義信號(hào)量的語句“MY_APPOS_EVENT*LedSem;”下面,添加以下語句:

MY_APPOS_EVENT*LedMbox; //Mbox

MY_APPOS_EVENT*LedQ; //Q

MY_APPvoid*myQMessage[10];

即又定義了消息郵箱和消息隊(duì)列。

文件appfun.c中需要修改的函數(shù)有AppTaskStart、AppTask_1、AppTask_2和AppTask_3,其中AppTaskStart函數(shù)在原來創(chuàng)建信號(hào)量的語句(將OSSemCreate(3)中的3改為1)

LedSem=OSSemCreate(3);

OSEventNameSet(LedSem,"Led_Sem",&err);

的下面添加以下語句:

LedMbox=OSMboxCreate(NULL);//CreateMbox

OSEventNameSet(LedMbox,"Led_Mbox",&err);

LedQ=OSQCreate(&myQMessage[0],10); //CreateQ

OSEventNameSet(LedQ,"Led_Q",&err);

函數(shù)AppTask_1、AppTask_2和AppTask_3由于修改較大,將在第5.6.2節(jié)中給出完整的代碼和注解。

完整的工程ex5_6的調(diào)試窗口如圖5-12所示,程序開始運(yùn)行時(shí),串口調(diào)試助手的顯示界面如圖5-13所示。圖5-12工程ex5_6調(diào)試窗口圖5-13串口調(diào)試助手顯示界面5.6.2工程ex5_6功能注解

文件appfun.c中函數(shù)AppTask_1、AppTask_2和AppTask_3的代碼如下:第7~11行定義了10條消息的變量myMessage,并賦了值,后面程序僅使用了myMessage[0]~myMessage[5]。第20~23行,當(dāng)程序執(zhí)行時(shí)間小于10秒時(shí)釋放信號(hào)量LedSem;第24~28行,當(dāng)程序執(zhí)行時(shí)間大于10秒而小于20秒時(shí),釋放消息郵箱LedMbox;第29~34行,當(dāng)程序執(zhí)行時(shí)間大于20秒而小于30秒時(shí),釋放消息隊(duì)列LedQ;第35~44行,當(dāng)程序執(zhí)行時(shí)間大于30秒而小于40秒時(shí),依次釋放信號(hào)量LedSem、消息郵箱LedMbox和消息隊(duì)列LedQ;第45~53行,當(dāng)程序執(zhí)行時(shí)間大于40秒而小于50秒時(shí),依次釋放消息郵箱LedMbox、信號(hào)量LedSem和消息隊(duì)列

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論