μC/OS-II的任務(wù)之間的通訊與同步
程序清單L6.26清空消息隊(duì)列
INT8UOSQFlush(OS_EVENT*pevent)
{
OS_Q*pq;
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_Q){(1)
OS_EXIT_CRITICAL();
return(OS_ERR_EVENT_TYPE);
}
pq=pevent->OSEventPtr;
pq->OSQIn=pq->OSQStart;(2)
pq->OSQOut=pq->OSQStart;
pq->OSQEntries=0;
OS_EXIT_CRITICAL();
return(OS_NO_ERR);
}
6.8.7 查詢一個(gè)消息隊(duì)列的狀態(tài),OSQQuery()
OSQQuery()函數(shù)使用戶可以查詢一個(gè)消息隊(duì)列的當(dāng)前狀態(tài)。 程序清單L6.27是該函數(shù)的源代碼。OSQQuery()需要兩個(gè)參數(shù):一個(gè)是指向消息隊(duì)列的指針pevent。它是在建立一個(gè)消息隊(duì)列時(shí),由OSQCreate()函數(shù)返回的;另一個(gè)是指向OS_Q_DATA(見uCOS_II.H)數(shù)據(jù)結(jié)構(gòu)的指針pdata。該結(jié)構(gòu)包含了有關(guān)消息隊(duì)列的信息。在調(diào)用OSQQuery()函數(shù)之前,必須先定義該數(shù)據(jù)結(jié)構(gòu)變量。OS_Q_DATA結(jié)構(gòu)包含下面的幾個(gè)域:
.OSMsg 如果消息隊(duì)列中有消息,它包含指針.OSQOut所指向的隊(duì)列單元中的內(nèi)容。如果隊(duì)列是空的,.OSMsg包含一個(gè)NULL指針。
.OSNMsgs是消息隊(duì)列中的消息數(shù)(.OSQEntries的拷貝)。
.OSQSize 是消息隊(duì)列的總的容量
.OSEventTbl[]和.OSEventGrp是消息隊(duì)列的等待任務(wù)列表。通過它們,OSQQuery()的調(diào)用函數(shù)可以得到等待該消息隊(duì)列中的消息的任務(wù)總數(shù)。
OSQQuery()函數(shù)首先檢查pevent指針指向的事件控制塊是一個(gè)消息隊(duì)列[L6.27(1)],然后復(fù)制等待任務(wù)列表[L6.27(2)]。如果消息隊(duì)列中有消息[L6.27(3)],.OSQOut指向的隊(duì)列單元中的內(nèi)容被復(fù)制到OS_Q_DATA結(jié)構(gòu)中[L6.27(4)], 否則的話, 就復(fù)制一個(gè)NULL指針[L6.27(5)]。
最后,復(fù)制消息隊(duì)列中的消息數(shù)和消息隊(duì)列的容量大小[L6.27(6)]。
程序清單L6.27程序消息隊(duì)列的狀態(tài)
INT8UOSQQuery(OS_EVENT*pevent,OS_Q_DATA*pdata)
{
OS_Q*pq;
INT8Ui;
INT8U*psrc;
INT8U*pdest;
OS_ENTER_CRITICAL();
if(pevent->OSEventType!=OS_EVENT_TYPE_Q){(1)
OS_EXIT_CRITICAL();
return(OS_ERR_EVENT_TYPE);
}
pdata->OSEventGrp=pevent->OSEventGrp;(2)
psrc=pevent->OSEventTbl[0];
pdest=pdata->OSEventTbl[0];
for(i=0;i
*pdest++=*psrc++;
}
pq=(OS_Q*)pevent->OSEventPtr;
if(pq->OSQEntries>0){(3)
pdata->OSMsg=pq->OSQOut;(4)
}else{
pdata->OSMsg=(void*)0;(5)
}
pdata->OSNMsgs=pq->OSQEntries;(6)
pdata->OSQSize=pq->OSQSize;
OS_EXIT_CRITICAL();
return(OS_NO_ERR);
}
6.8.8 使用消息隊(duì)列讀取模擬量的值
在控制系統(tǒng)中,經(jīng)常要頻繁地讀取模擬量的值。這時(shí),可以先建立一個(gè)定時(shí)任務(wù)OSTimeDly()[見5.00節(jié),延時(shí)一個(gè)任務(wù),OSTimeDly()],并且給出希望的抽樣周期。然后,如圖F6.11所示,讓A/D采樣的任務(wù)從一個(gè)消息隊(duì)列中等待消息。該程序最長的等待時(shí)間就是抽樣周期。當(dāng)沒有其它任務(wù)向該消息隊(duì)列中發(fā)送消息時(shí),A/D采樣任務(wù)因?yàn)榈却瑫r(shí)而退出等待狀態(tài)并進(jìn)行執(zhí)行。這就模仿了OSTimeDly()函數(shù)的功能。
也許,讀者會(huì)提出疑問,既然OSTimeDly()函數(shù)能完成這項(xiàng)工作,為什么還要使用消息隊(duì)列呢?這是因?yàn)?,借助消息?duì)列,我們可以讓其它的任務(wù)向消息隊(duì)列發(fā)送消息來終止A/D采樣任務(wù)等待消息,使其馬上執(zhí)行一次A/D采樣。此外,我們還可以通過消息隊(duì)列來通知A/D采樣程序具體對(duì)哪個(gè)通道進(jìn)行采樣,告訴它增加采樣頻率等等,從而使得我們的應(yīng)用更智能化。換句話說,我們可以告訴A/D采樣程序,“現(xiàn)在馬上讀取通道3的輸入值!”之后,該采樣任務(wù)將重新開始在消息隊(duì)列中等待消息,準(zhǔn)備開始一次新的掃描過程。
圖F6.11讀模擬量輸入——Figure6.11
6.8.9 使用一個(gè)消息隊(duì)列作為計(jì)數(shù)信號(hào)量
在消息隊(duì)列初始化時(shí),可以將消息隊(duì)列中的多個(gè)指針設(shè)為非NULL值(如void*1),來實(shí)現(xiàn)計(jì)數(shù)信號(hào)量的功能。這里,初始化為非NULL值的指針數(shù)就是可用的資源數(shù)。系統(tǒng)中的任務(wù)可以通過OSQPend()來請(qǐng)求“信號(hào)量”,然后通過調(diào)用OSQPost()來釋放“信號(hào)量”,如程序清單L6.28。如果系統(tǒng)中只使用了計(jì)數(shù)信號(hào)量和消息隊(duì)列,使用這種方法可以有效地節(jié)省代碼空間。
這時(shí)將OS_SEM_EN設(shè)為0,就可以不使用信號(hào)量,而只使用消息隊(duì)列。值得注意的是,這種方法
為共享資源引入了大量的指針變量。也就是說,為了節(jié)省代碼空間,犧牲了RAM空間。另外,
對(duì)消息隊(duì)列的操作要比對(duì)信號(hào)量的操作慢,因此,當(dāng)用計(jì)數(shù)信號(hào)量同步的信號(hào)量很多時(shí),這種
方法的效率是非常低的。
程序清單L6.28使用消息隊(duì)列作為一個(gè)計(jì)數(shù)信號(hào)量
OS_EVENT*QSem;
void*QMsgTbl[N_RESOURCES]
voidmain(void)
{
OSInit();
.
QSem=OSQCreate(QMsgTbl[0],N_RESOURCES);
for(i=0;i
OSQPost(Qsem,(void*)1);
}
.
.
OSTaskCreate(Task1,..,..,..);
.
.
OSStart();
}
voidTask1(void*pdata)
{
INT8Uerr;
for(;;){
OSQPend(QSem,0,err);/*得到對(duì)資源的訪問權(quán)*/
.
./*任務(wù)獲得信號(hào)量,對(duì)資源進(jìn)行訪問*/
.
OSMQPost(QSem,(void*)1);/*釋放對(duì)資源的訪問權(quán)*/
}
}
評(píng)論