zstack 第一个例子
看了好長一段時間的原理,終于手癢了,開動了第一個例子,感謝大家來敢看我的博客!!
1、? ? ? ? 協(xié)議棧構(gòu)架
首先打開程序代碼,找到IAR工程 ,打開后可以看到TI ZStack的大體框架,如下圖所示:
§ App:應用層目錄,這也是用戶創(chuàng)建各種不同工程的區(qū)域;
§ HAL:硬件層目錄,包括著與硬件相關(guān)的配置及操作函數(shù);
§ MAC:MAC層目錄,包括著MAC層配置參數(shù)文件及MAC LIB庫的函數(shù)接口文件;
§ MT:包括基于AF層的調(diào)試函數(shù)文件,主要包括串口等通信函數(shù);§ NWK:網(wǎng)絡層目錄,包括著網(wǎng)絡層配置參數(shù)文件及MAC LIB庫的函數(shù)接口文件;
§ OSAL:系統(tǒng)目錄,包括協(xié)議棧系統(tǒng)文檔;
§ Profile:AF層目錄,包括AF層處理函數(shù)文件;
§ Security:安全層目錄,安全層處理函數(shù),比如加密函數(shù)等;
§ Services:地址處理函數(shù)目錄,包括著地址模式的定義及地址處理函數(shù)文檔;Tools:工程配置目錄,包括協(xié)議棧等配置文檔;
§ ZDO ZDO ZDO ZDO:層目錄,包括層處理函數(shù)文檔;
§ ZMac:MAC層目錄,包括MAC層參數(shù)配置及MAC層LIB庫函數(shù)回調(diào)處理函數(shù)
§ ZMain:主函數(shù)目錄,包括入口函數(shù)及硬件配置文件;
§ Output:輸出文件目錄,這是EW8051IDE自動生成的;
2、? ? ? ? 程序的編譯和下載
(1)? ? ? ? 項目屬性設置
選擇菜單Project->Options、右擊菜單options或者通過熱鍵(ALT+F7)打開工程屬性設置。
也可以鼠標右擊workspace中的工程名,如下圖:
打開屬性設置后如圖:
一般來說,如果是在TI的協(xié)議棧的進行修改,里面的設置就不用修改。如果要具體了解各參數(shù),請參照IAR文檔。
這里值得注意的是chipcon下的Download的標簽,如果第一次用建議像如圖那樣選擇,這樣是將整個FALSH擦除后再Download,寫完后最好用
軟件來更改芯片的IEEE地址,否則可能帶來你的程序無法運行。
具體見Zmain.c函數(shù)中的如下程序段:
led = HAL_LED_MODE_OFF;
??
??while ( HAL_KEY_SW_5 == HalKeyRead() )
??{
? ? MicroWait( 62500 );
? ? HalLedSet( HAL_LED_1, led^=HAL_LED_MODE_ON );??// Toggle the LED
? ? MicroWait( 62500 );
??}
??HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );
如果你使用的硬件平臺沒有對這個按鍵5進行設置,或者就沒有這個按鍵5,這段將過不去,LED1燈將一直閃。
如果你的系統(tǒng)沒有按鍵,建議將上面的語句注釋掉。
(2)? ? ? ? 編譯與燒寫
選擇Project->Debug或者熱鍵(Ctrl+D)給開發(fā)板上的Zigbee模塊下載程序。
也可以直接點IAR的如下圖標來編譯和下載程序 ,最后一個是編譯并下載;
同時也可以在workspace中的工程名上點擊鼠標右鍵來選擇編譯。
下圖顯示為DEBUG時的選項:
在調(diào)試程序時,DEBUG還是非常有用的,它能告訴你程序運行到哪了,程序為什么沒有出現(xiàn)你預期的結(jié)果等,因此,選擇一個仿真器還是有用的,并且有些仿真器加上一個節(jié)點就可以充當packet sniffer工具,對空中的包能進行實時跟蹤。下圖是在寧波中科仿真器抓到的本例子的數(shù)據(jù)包,以后會對這些包結(jié)構(gòu)做一定解析,如果也可以參考ZigBee協(xié)議棧文檔,上面對這些包結(jié)構(gòu)有詳細的說明。
從圖中的RSSI中可以看到節(jié)點的性能,負數(shù)越接近0表明節(jié)點性能越好,通信距離越長,并且協(xié)調(diào)器已經(jīng)給一個終端節(jié)點分配了短地址0x796F(該地址可以通過計算得到,見IEEE 802.15.4文檔)。
3、? ? ? ? 實驗程序簡單分析
在本實驗中用戶涉及的程序主要有OSAL_SendTest.c,SendTest.c,SendTest.h。其他程序協(xié)議棧程序只做簡單修改就行。比如我使用的是GAINST-CC2430需要修改一下串口函數(shù)等。因為硬件平臺的差異性,大家可以根據(jù)實際進行修改。下面主要介紹上面提到的三個函數(shù)。
OSAL_SendTest.c函數(shù)是協(xié)議棧操作系統(tǒng)處理函數(shù),這個函數(shù)實現(xiàn)對本實驗中需要的任務的添加,具體函數(shù)如下:
osalTaskAdd( nwk_init, nwk_event_loop, OSAL_TASK_PRIORITY_MED );
osalTaskAdd( APS_Init, APS_event_loop, OSAL_TASK_PRIORITY_LOW );
osalTaskAdd( ZDApp_Init, ZDApp_event_loop, OSAL_TASK_PRIORITY_LOW );
osalTaskAdd( SendTest_Init, SendTest_ProcessEvent, OSAL_TASK_PRIORITY_LOW );
最后一條語句是添加本實驗任務的。osalTaskAdd()函數(shù)的參數(shù)請參照OSAL API_F8W-2003-0002_.PDF文檔。
SendTest.c是本實驗用戶程序的具體實現(xiàn)。下面來分析一下該程序。
首先,本程序不考慮協(xié)議棧綁定等相關(guān)內(nèi)容,在程序中屏蔽了綁定,實驗數(shù)據(jù)只是從終端節(jié)點傳送到協(xié)調(diào)器節(jié)點,對于ZIGBEE網(wǎng)絡協(xié)調(diào)器節(jié)點的短地址始終為0x0000,因此在用發(fā)送函數(shù)時,目的地址寫上0x0000就能傳到協(xié)調(diào)器。
其次,兩個設備的 endPoint要保持一致,否則將不能通信。在程序中將SendTest_DstAddr.endPoint = SendTest_ENDPOINT;(SendTest_ENDPOINT=10)。
程序?qū)崿F(xiàn)結(jié)果是:協(xié)調(diào)器的串口上輸出如圖內(nèi)容:
注意,要使用該串口助手才能顯示中文,其他的串口可能不支持。
只有在終端節(jié)點加入網(wǎng)絡后才能發(fā)送數(shù)據(jù)給協(xié)調(diào)器,一旦網(wǎng)絡中斷數(shù)據(jù)就不再發(fā),這個機制是通過判斷網(wǎng)絡狀態(tài)來實現(xiàn)的,代碼如下:
if ( (SendTest_NwkState == DEV_END_DEVICE) ) //只在設備為終端節(jié)點時,才發(fā)送數(shù)據(jù)
? ?? ?? ? {
? ?? ?? ?? ?// Start sending "the" message in a regular interval.
? ?? ?? ?? ?osal_start_timer( SendTest_SEND_MSG_EVT,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?SendTest_SEND_MSG_TIMEOUT );
? ?? ?? ? }
上面語句中SendTest_SEND_MSG_EVT是一個事件,只在定時器時間到才觸發(fā)該事件,在程序中設置
#define SendTest_SEND_MSG_TIMEOUT? ?1000
也就是在網(wǎng)絡建成后每一秒向協(xié)調(diào)器發(fā)送數(shù)據(jù)。
對于操作系統(tǒng)的介紹請參考文檔,以后我也會就這個做些介紹。
SendTest_ProcessEvent函數(shù)為操作系統(tǒng)的一任務(上面已經(jīng)介紹了怎么加入任務),總是被周期性輪詢。當檢測到一個event就執(zhí)行相關(guān)程序。
在一個任務中有16個事件,用16位來表示,每一位代表一個事件,其中0x8000為系統(tǒng)事件SYS_EVENT_MSG,任務還和task_id有關(guān)。
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SendTest_TaskID );
程序段是將收到的消息存放到MSGpkt指定的區(qū)域中。
while ( MSGpkt )//消息不為空
{ switch ( MSGpkt->hdr.event )
? ?? ?{
? ?? ???case KEY_CHANGE://按鍵狀態(tài)改(本實驗不涉及)
? ?? ?? ? SendTest_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
? ?? ?? ? break;
? ?? ???case AF_DATA_CONFIRM_CMD://AF層數(shù)據(jù)發(fā)送完成后確認報告
? ?? ?? ? // This message is received as a confirmation of a data packet sent.
? ?? ?? ? // The status is of ZStatus_t type [defined in ZComDef.h]
? ?? ?? ? // The message fields are defined in AF.h
? ?? ?? ? afDataConfirm = (afDataConfirm_t *)MSGpkt;
? ?? ?? ? sentEP = afDataConfirm->endpoint;
? ?? ?? ? sentStatus = afDataConfirm->hdr.status;
? ?? ?? ? sentTransID = afDataConfirm->transID;
? ?? ?? ? (void)sentEP;
? ?? ?? ? (void)sentTransID;
? ?? ?? ? HAL_TOGGLE_LED1();//加入LED1來指示數(shù)據(jù)發(fā)送出
? ?? ?? ? // Action taken when confirmation is received.
? ?? ?? ? if ( sentStatus != ZSuccess )
? ?? ?? ? {
? ?? ?? ?? ?// The data wasn't delivered -- Do something
? ?? ?? ? }
? ?? ?? ? break;
? ?? ???case AF_INCOMING_MSG_CMD://新的報文來
? ?? ?? ? HAL_TOGGLE_LED1();//加入LED1來指示新報文來
? ?? ?? ? SendTest_MessageMSGCB( MSGpkt );//新報文回調(diào)函數(shù)
? ?? ?? ? break;
? ?? ???case ZDO_NEW_DSTADDR://ZDO終端地址改變,這個是在加入綁定后引起的,本實驗不涉及
? ?? ?? ? ZDO_NewDstAddr = (ZDO_NewDstAddr_t *)MSGpkt;
? ?? ?? ? dstEP = ZDO_NewDstAddr->dstAddrDstEP;
? ?? ?? ? dstAddr = &ZDO_NewDstAddr->dstAddr;
? ?? ?? ? SendTest_DstAddr.addrMode = (afAddrMode_t)dstAddr->addrMode;
? ?? ?? ? SendTest_DstAddr.endPoint = dstEP;
? ?? ?? ? SendTest_DstAddr.addr.shortAddr = dstAddr->addr.shortAddr;
? ?? ?? ? break;
? ?? ???case ZDO_STATE_CHANGE://網(wǎng)絡狀態(tài)改變,在這里啟動第一次數(shù)據(jù)傳輸
? ?? ?? ? SendTest_NwkState = (devStates_t)(MSGpkt->hdr.status);
? ?? ?? ? if ( (SendTest_NwkState == DEV_END_DEVICE) ) //只在設備為終端節(jié)點時,才發(fā)送數(shù)據(jù)
? ?? ?? ? {
? ?? ?? ?? ?// Start sending "the" message in a regular interval.
? ?? ?? ?? ?osal_start_timer( SendTest_SEND_MSG_EVT,
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?SendTest_SEND_MSG_TIMEOUT );
? ?? ?? ? }//這個在上面已經(jīng)有介紹
? ?? ?? ? break;
? ?? ???default:
? ?? ?? ? break;
? ?? ?}
? ?? ?// Release the memory
? ?? ?osal_msg_deallocate( (uint8 *)MSGpkt );
? ?? ?// Next
? ?? ?MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SendTest_TaskID );
}
if ( events & SendTest_SEND_MSG_EVT )//如果事件為消息傳送事件
??{
? ? // Send "the" message
? ? SendTest_SendTheMessage();//調(diào)用消息發(fā)送函數(shù)
? ? // Setup to send message again
? ? if ( (SendTest_NwkState == DEV_END_DEVICE) )//解釋同前
? ? osal_start_timer( SendTest_SEND_MSG_EVT,
? ?? ?? ?? ?? ?? ?? ? SendTest_SEND_MSG_TIMEOUT );
? ? // return unprocessed events
? ? return (events ^ SendTest_SEND_MSG_EVT);
??}
消息回調(diào)函數(shù)實現(xiàn):
void SendTest_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
??switch ( pkt->clusterId )
??{
? ? case SendTest_CLUSTERID:
? ?? ?// "the" message
#if defined( LCD_SUPPORTED )
? ?? ?HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
? ?? ?WPRINTSTR( pkt->cmd.Data );
#endif
? ?? ?HalUARTWrite( HAL_UART_PORT_1,(pkt->cmd).Data, (pkt->cmd).DataLength);//將接收到的數(shù)打印到串口上
? ?? ?break;
??}
}
對于串口的初始化在SendTest_Init函數(shù)中,上面的紅色顯示函數(shù)就是將收到的數(shù)據(jù)信息打印在串口終端上。
下面介紹一下,發(fā)送函數(shù)AF_DataRequest
該函數(shù)用于發(fā)送數(shù)據(jù)
函數(shù)聲明:
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
uint8 options, uint8 radius );
具體參數(shù):
dstAddr:目的地址指針,其中的地址模式是:afAddrNotPresent(用于綁定)、afAddrGroup(傳送到一組目的節(jié)點)afAddrBroadcast(廣播發(fā)送)、afAddr16Bit(直接發(fā)送),在本實驗中afAddr16Bit地址模式,在SendTest_Init初始化中將SendTest_DstAddr.addrMode 設置為(afAddrMode_t)Addr16Bit;
srcEP:發(fā)送的endpoint的Endpoint描述的指針
cID:Cluster ID,實驗中使用SendTest_CLUSTERID
len:發(fā)送數(shù)據(jù)包長度,該長度不包括ZIGBEE包中的幀頭和幀尾,只是用戶數(shù)據(jù)的長度
buf:用戶發(fā)送數(shù)據(jù)區(qū)指針
transID:傳輸序號指針,該序號將隨發(fā)送的次數(shù)增加而增加
options:具體參數(shù)參照下表:
Radius:最大跳數(shù),協(xié)議棧默認值為10,可以根據(jù)實際情況修改,見nwk.h文件中
// the default network radius set twice the value of <nwkMaxDepth>
#define DEF_NWK_RADIUS 10
終于寫完了,呵呵呵有點辛苦但是有收獲哦
轉(zhuǎn)載于:https://www.cnblogs.com/yqh2007/archive/2011/04/27/2030046.html
總結(jié)
以上是生活随笔為你收集整理的zstack 第一个例子的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 和平精英名字大全霸气四个字 四个字好听霸
- 下一篇: iPhone如何打开免扰模式?免扰模式开