張玲麗
摘 要:文中研究分析了ZigBee協(xié)議棧的OSAL運(yùn)行機(jī)理,并在此基礎(chǔ)之上,通過規(guī)范的編程流程,設(shè)計(jì)了一個行之有效的測試系統(tǒng),很好地演示了OSAL如何實(shí)現(xiàn)多任務(wù)切換和處理機(jī)制,對后期基于協(xié)議棧的編程提供了技術(shù)支持。
關(guān)鍵詞:ZigBee協(xié)議棧;OSAL;任務(wù)事件;技術(shù)支持
中圖分類號:TP39;TN92 文獻(xiàn)標(biāo)識碼:A 文章編號:2095-1302(2017)08-00-02
0 引 言
從ZigBee 2006協(xié)議棧開始,ZigBee協(xié)議棧內(nèi)加入了實(shí)時操作系統(tǒng),主要制定了一個實(shí)現(xiàn)任務(wù)間切換、同步與互斥等的機(jī)制,而這就是操作系統(tǒng)表象層OSAL (Operating System Abstraction Layer,OSAL)產(chǎn)生的根源。OSAL與標(biāo)準(zhǔn)的操作系統(tǒng)存在一定區(qū)別,它只實(shí)現(xiàn)了類似操作系統(tǒng)的某些功能,如任務(wù)切換、內(nèi)存管理等,還不能稱為真正意義上的操作系統(tǒng)[1]。OSAL專門分配了存放所有任務(wù)事件的tasksEvents[]數(shù)組,每一個單元對應(yīng)存放著每一個任務(wù)的所有事件,在這個函數(shù)中首先通過一個do—while循環(huán)來遍歷tasksEvents[],找到一個具有待處理事件的優(yōu)先級最高的任務(wù),序號低的任務(wù)優(yōu)先級高,然后跳出循環(huán),此時,就得到了最高優(yōu)先級任務(wù)的序號idx,然后通過events=tasksEvents[idx]語句將當(dāng)前具有最高優(yōu)先級的任務(wù)事件取出,接著調(diào)用(tasksArr[idx])(inx,events)函數(shù)來執(zhí)行具體的處理。taskArr[]是一個函數(shù)指針數(shù)組,根據(jù)不同的idx可以執(zhí)行不同的函數(shù)[2],其程序流程圖如圖1所示。
打開一個ZigBee工程文件,在左側(cè)通常可以看到三個文件,分別為“Coordinator.c”、“Coordinator.h”、“OSAL_GenericApp.c”。整個程序所實(shí)現(xiàn)的功能都包含在這三個文件中。首先打開Coordinator.c 文件,可以看到兩個比較重要的函數(shù)GenericApp_Init 和 GenericApp_ProcessEvent。GenericApp_Init是任務(wù)的初始化函數(shù),GenericApp_ProcessEvent則負(fù)責(zé)判斷由參數(shù)傳遞的事件類型,然后執(zhí)行相應(yīng)的事件處理函數(shù)[3]。我們的設(shè)計(jì)同樣需要遵循該流程,既要進(jìn)行任務(wù)初始化也需要完成開中斷執(zhí)行操作系統(tǒng)實(shí)體的功能??梢詫⒃摴ぷ骷?xì)化為初始化工作、事件的設(shè)置和響應(yīng)、編寫任務(wù)事件處理函數(shù)。本文設(shè)計(jì)了一個驗(yàn)證該運(yùn)行機(jī)理的演示代碼,展示了不同優(yōu)先級的任務(wù)是如何按先后順序被初始化及跳轉(zhuǎn)到相應(yīng)的任務(wù)事件處理函數(shù)來執(zhí)行的效果。
1 初始化工作
在Zmain.c中首先應(yīng)啟動系統(tǒng),即需要完成初始化功能,包括硬件平臺和軟件架構(gòu)所需的各個模塊,為操作系統(tǒng)的運(yùn)行做好準(zhǔn)備。由于大部分初始化工作協(xié)議棧已設(shè)置好,此處我們只需特別設(shè)置的初始化工作包括初始化工作時鐘、初始化串口、初始化定時器、設(shè)置串口、使能中斷等,同時用戶自定義的事件也都需要放到任務(wù)初始化函數(shù)中進(jìn)行初始化,此過程分為兩步:
(1)將所有任務(wù)對應(yīng)的事件表清空,任務(wù)事件表保存在TaskEvents結(jié)構(gòu)當(dāng)中,該結(jié)構(gòu)是一個uint16類型的數(shù)組,數(shù)組的每一個元素對應(yīng)一個任務(wù)所有的事件,16位對應(yīng)了16個事件。其中最高位表示是否為系統(tǒng)事件,最高位為1,則表示為系統(tǒng)事件;最高位為0,則表示為非系統(tǒng)事件。
(2)為每個任務(wù)分配任務(wù)ID并初始化具體任務(wù),任務(wù)ID決定了任務(wù)的優(yōu)先級,ID越小響應(yīng)的優(yōu)先級越高,在任務(wù)初始化函數(shù)中,最新初始化的任務(wù)ID最小,優(yōu)先級最高,ID依次遞增,最小ID為0,最大ID為TaskCont-1。其具體代碼如下:
void OS_IntTasks( void )
{
uint8 i,taskId = 0;
for( i = 0; i < TaskCont; i ++ )
{
TaskEvents[i] = 0;
}
testOsInt( taskId++ ); //增加任務(wù)初始化,確定任務(wù)ID
}
倘若需要增加更多任務(wù),只需在testOsInt( taskId++ )注冊新任務(wù)即可。
2 事件的設(shè)置和響應(yīng)
任務(wù)事件的設(shè)置有兩種方式[4]:一種直接使用uint8osal_set_event( uint8 task_id, uint16 event_flag )函數(shù)來設(shè)置事件,該函數(shù)包含了兩個參數(shù),即任務(wù)ID和事件標(biāo)志;另一種方法是設(shè)置一個超時事件。設(shè)置超時事件與直接設(shè)置事件的區(qū)別在于,超時事件不會立刻將事件加入到相應(yīng)任務(wù)的事件列表中,而是需要等待一定時間后才會加入,這個事件是通過設(shè)置函數(shù)的第三個參數(shù)來決定。
OSAL_STATE osal_start_timerEx( uint8 taskID,uint16 event_flag,uint16 timeout_value ){ }
從參數(shù)來看,該函數(shù)與osal_set_event函數(shù)相比,多了一個time_out_value參數(shù),該參數(shù)用來設(shè)置超時值。該超時值的度量單位就是前面初始化timer1時設(shè)置的中斷節(jié)拍。
響應(yīng)任務(wù)事件首先需要得到準(zhǔn)備就緒任務(wù)的ID,得到就緒任務(wù)ID后就可以通過該ID號得到相應(yīng)的任務(wù)事件處理函數(shù):events = (TasksFn[idx])(idx, events),其中TasksFn為任務(wù)事件處理函數(shù)表,表中的函數(shù)與任務(wù)ID號相對應(yīng)。本設(shè)計(jì)只定義了一個任務(wù)響應(yīng)函數(shù):const OSEventHandle TasksFn[] = {testOsProcess;},其可將任務(wù)進(jìn)程注冊到任務(wù)函數(shù)指針列表中。endprint
在該設(shè)計(jì)中增加了一個超時事件,即在osal_start_timerEx函數(shù)中調(diào)用了osalAddTimer函數(shù)[5],將事件加入到系統(tǒng)時鐘資源當(dāng)中。該系統(tǒng)時鐘資源由一個結(jié)構(gòu)體數(shù)據(jù)定義,其原型如下:
typedef struct
{
void *next;//指向下一個節(jié)點(diǎn)
uint16 timeout;//超時事件中的超時值保存在此處,當(dāng)該值減到0時,將該時鐘資源記錄的任務(wù)事件增加到事件列表當(dāng)中
uint16 event_flag;//事件標(biāo)識
uint8 task_id;//任務(wù)ID
} osalTimerRec_t;
在系統(tǒng)輪詢時,除了對任務(wù)事件進(jìn)行查詢外,還增加了掃描事件查詢函數(shù)OS_Scan(),在該函數(shù)里對timer1的中斷服務(wù)函數(shù)進(jìn)行自增運(yùn)算,每次在OS_Scan中清零,而temp則記錄了mcuTimerCounterForOSAL的拷貝,即每次輪詢花費(fèi)的系統(tǒng)時間。但關(guān)鍵在于OSALTimerUpdate函數(shù)若導(dǎo)致超時,則會將設(shè)置有事件標(biāo)識的時鐘資源的超時值進(jìn)行自減,將運(yùn)行時間在timerout中減去,一旦判斷timerout值為0,便將相應(yīng)的事件進(jìn)行設(shè)置,同時取消該超時事件記錄。
本設(shè)計(jì)分別采用直接設(shè)置事件法和設(shè)置超時事件法來設(shè)置以下兩個事件:
(1)在任務(wù)號為testOSTaskID的任務(wù)中設(shè)置系統(tǒng)事件0x8000和非系統(tǒng)事件0x0001,osal_set_event(testOSTaskID,0x8001 );
(2)在任務(wù)號為testOSTaskID的任務(wù)中設(shè)置超時事件0x0002,打開定時器,并設(shè)置超時值為3 000 ms,osal_start_timerEx(testOSTaskID, 0x0002, 3000)。
3 編寫任務(wù)處理函數(shù)
本設(shè)計(jì)需要在Coordinator.c中增加對應(yīng)的任務(wù)處理函數(shù),在任務(wù)處理函數(shù)中實(shí)現(xiàn)對系統(tǒng)事件0x8000、非系統(tǒng)事件0x0001和超時事件0x0002的處理。對應(yīng)的任務(wù)處理函數(shù)如下:
uint16 testOsProcess( uint8 taskId, uint16 events )
{
//系統(tǒng)任務(wù)
if( events & 0x8000 )
{
uartsendstring((void *)”O(jiān)S SYS events\r\n”,15);
return events ^ 0x8000;
}
//串口信息任務(wù)
if( events & 0x0001 )
{
uartsendstring((void *)”O(jiān)S test events\r\n”,16);
return events ^ 0x0001;
}
if(events & 0x0002 )
{
uartsendstring((void *)”O(jiān)S Timer events\r\n”,17);
osal_start_timerEx(testOSTaskID, 0x0002, 3000);//打開超時定時器,3 s超時
return events ^ 0x0002;
}
return 0;
}
對于0x8000事件,通過串口發(fā)送”O(jiān)S SYS events\r\n”字符串;對于0x0001事件,通過串口發(fā)送”O(jiān)S test events\r\n”字符串;對于0x0002事件,通過串口發(fā)送”O(jiān)S Timer events\r\n”字符串,并周期性設(shè)置該事件。
4 結(jié) 語
為了驗(yàn)證OSAL是如何按照處理事件的優(yōu)先級順序來依次處理事件的,將上述編寫好的代碼組織形成工程文件,并下載到相關(guān)硬件開發(fā)板或平臺上,采用串口通信線把網(wǎng)關(guān)底板和計(jì)算機(jī)連接起來。打開串口調(diào)試助手并正確設(shè)置后,從串口輸出數(shù)據(jù),其視圖如圖2所示,先顯示OS SYS events,然后顯示OS test events,之后每間隔3 s顯示一次OS Timer events。
由此可見,操作系統(tǒng)是優(yōu)先處理系統(tǒng)強(qiáng)制事件,然后處理用戶自定義事件。由于本設(shè)計(jì)中事件1和事件2的優(yōu)先級一樣,因此優(yōu)先處理先準(zhǔn)備好的事件,由于設(shè)置定時器事件時設(shè)置了3 s的超時,因此交換兩事件的任務(wù)ID號后處理和顯示的順序不變。如果有多個同時準(zhǔn)備好的時間,系統(tǒng)會按照任務(wù)ID號從小到大的順序依次處理。本設(shè)計(jì)為展示ZigBee協(xié)議棧里所包含的精簡OS系統(tǒng)如何進(jìn)入任務(wù)輪詢狀態(tài)并按照一定的任務(wù)優(yōu)先級進(jìn)入任務(wù)事件處理,提供了行之有效的測試方案。
參考文獻(xiàn)
[1]王小強(qiáng),歐陽駿,黃寧淋.ZigBee無線傳感器網(wǎng)絡(luò)設(shè)計(jì)與實(shí)現(xiàn)[M].北京:化學(xué)工業(yè)出版社,2012.
[2]鄭海杰,宋開新.綜合OSAL的ZigBee協(xié)議棧設(shè)計(jì)[J].杭州電子科技大學(xué)學(xué)報(bào)(自然科學(xué)版),2015(6):32-35.
[3]陳亞琳.Zigbee協(xié)議棧消息事件處理分析[J].南京工業(yè)職業(yè)技術(shù)學(xué)院學(xué)報(bào),2014(4):44-48.
[4]李戰(zhàn)明,劉寶,駱東松.ZigBee技術(shù)規(guī)范與協(xié)議棧分析[J].微型機(jī)與應(yīng)用,2009,28(5):45-48.
[5]章偉聰,俞新武,李忠成.基于CC2530及ZigBee協(xié)議棧設(shè)計(jì)無線網(wǎng)絡(luò)傳感器節(jié)點(diǎn)[J].計(jì)算機(jī)系統(tǒng)應(yīng)用,2011,20(7):184-187,120.
[6]李志瑞,程萬里,杜永章.基于CC2530無線MEMS加速度傳感器設(shè)計(jì)與驗(yàn)證[J].物聯(lián)網(wǎng)技術(shù),2015,5(6):6-8.
[7]潘軍.基于ZigBee的無線傳感器網(wǎng)絡(luò)的研究與應(yīng)用[D].大連:大連海事大學(xué),2012.
[8]宋國青. ZigBee自動抄表系統(tǒng)的研究與實(shí)現(xiàn)[D].桂林:桂林電子科技大學(xué),2010.endprint