Zigbee的由來
在藍牙技術的使用過程中,人們發現藍牙技術盡管有許多優點,但仍存在許多缺陷。對工業,家庭自動化控制和遙測遙控領域而言,藍牙技術顯得太復雜,功耗大,距離近,組網規模太小等,而工業自動化對無線通信的需求越來越強烈。正因此,經過人們長期努力,Zigbee協議在2003年中通過后,于2004正式問世了。
Zigbee是什么
Zigbee是一個由可多到65000個無線數傳模塊組成的一個無線數傳網絡平臺,十分類似現有的移動通信的CDMA網或GSM網,每一個Zigbee網絡數傳模塊類似移動網絡的一個基站,在整個網絡范圍內,它們之間可以進行相互通信;每個網絡節點間的距離可以從標準的75米,到擴展后的幾百米,甚至幾公里;另外整個Zigbee網絡還可以與現有的其它的各種網絡連接。例如,你可以通過互聯網在北京監控云南某地的一個Zigbee控制網絡。
不同的是,Zigbee網絡主要是為自動化控制數據傳輸而建立,而移動通信網主要是為語音通信而建立;每個移動基站價值一般都在百萬元人民幣以上,而每個Zigbee“基站”卻不到1000元人民幣;每個Zigbee 網絡節點不僅本身可以與監控對對象,例如傳感器連接直接進行數據采集和監控,它還可以自動中轉別的網絡節點傳過來的數據資料; 除此之外,每一個Zigbee網絡節點(FFD)還可在自己信號覆蓋的范圍內,和多個不承擔網絡信息中轉任務的孤立的子節點(RFD)無線連接。
每個Zigbee網絡節點(FFD和RFD)可以可支持多到31個的傳感器和受控設備,每一個傳感器和受控設備終可以有8種不同的接口方式??梢圆杉蛡鬏敂底至亢湍M量。
Zigbee技術的應用領域
Zigbee技術的目標就是針對工業,家庭自動化,遙測遙控,汽車自動化、農業自動化和醫療護理等,例如燈光自動化控制,傳感器的無線數據采集和監控,油田,電力,礦山和物流管理等應用領域。另外它還可以對局部區域內移動目標例如城市中的車輛進行定位.
通常,符合如下條件之一的應用,就可以考慮采用Zigbee技術做無線傳輸:
1.需要數據采集或監控的網點多;
2.要求傳輸的數據量不大,而要求設備成本低;
3.要求數據傳輸可性高,安全性高;
4.設備體積很小,不便放置較大的充電電池或者電源模塊;
5.電池供電;
6.地形復雜,監測點多,需要較大的網絡覆蓋;
7.現有移動網絡的覆蓋盲區;
8.使用現存移動網絡進行低數據量傳輸的遙測遙控系統。
9.使用GPS效果差,或成本太高的局部區域移動目標的定位應用。
Zigbee 技術的特點
省電:兩節五號電池支持長達6個月到2年左右的使用時間。
可靠:采用了碰撞避免機制,同時為需要固定帶寬的通信業務預留了專用時隙,避免了發送數據時的競爭和沖突;節點模塊之間具有自動動態組網的功能,信息在整個Zigbee網絡中通過自動路由的方式進行傳輸,從而保證了信息傳輸的可靠性。
時延短:針對時延敏感的應用做了優化,通信時延和從休眠狀態激活的時延都非常短。
網絡容量大:可支持達65000個節點。
安全:ZigBee提供了數據完整性檢查和鑒權功能,加密算法采用通用的AES-128。
高保密性:64位出廠編號和支持AES-128加密。
Zigbee的發展前景
Zigbee技術和RFID 技術在2004年就被列為當今世界發展最快,市場前景最廣闊的十大最新技術中的兩個。關于這方面的報道,你只需在百度,或GOOGLE搜索欄中鍵入“Zigbee”,你就會看到大量的有關報道??傊窈笕舾赡?,都將是Zigbee技術飛速發展的時期。
Zigbee技術在我國的應用情況
盡管,國內不少人已經開始關注Zigbee這們新技術,而且也有不少單位開始涉足Zigbee技術的開發工作,然而,由于Zigbee 本身是一種新的系統集成技術,應用軟件的開發必須和網絡傳輸,射頻技術和底層軟硬件控制技術結合在一起。因而深入理解這個來自國外的新技術,再組織一個在這幾個方面都有豐富經驗的配套的隊伍,本身就不是一件容易的事情,因而,到目前為止,國內目前除了成都西谷曙光數字技術有限公司,真正將Zigbee技術開發成產品,并成功地用于解決幾個領域的實際生產問題而外,尚未見到其它報道。
Zigbee 和現有移動網(GPRS,CDMA-1X)的比較
1.無網絡使用費:使用移動網需要長期支付網絡使用費,而且是按節點終端的數量計算的,而Zigbee沒有這筆費用;
2.設備投入低:使用移動網需要購買移動終端設備,每個終端的價格在人民幣1000元上下,而使用Zigbee 網絡,不僅Zigbee網絡節點模塊(相當于基站)費用每只人民幣不到1000元,而且,主要使用的網絡子節點(相當于手機)的價格還要低得多;
3.通信更可靠:由于現有移動網主要是為手機通信而設計的,盡管CDMA-1X和GPRS可以進行數據通信,但實踐發現,不僅通信數率比設計速率低很多,而且數據通信的可靠信也存在一定的問題。而Zigbee網絡則是專門為控制數據的傳輸而設計的,因而控制數據的傳輸具有相當的保證。
4.高度的靈活性和低成本:首先,通過使用覆蓋距離不同,功能不同的Zigbee網絡節點,以及其它非Zigbee系統的低成本的無線收發模塊,建立起一個Zigbee局部自動化控制網,(這個網絡可以是星型,樹狀,網狀及其共同組成的復合網結構)再通過互聯網或移動網與遠端的計算機相連,從而實現低成本,高效率的工業自動化遙測遙控;
5.比起現有的移動網來,盡管Zigbee僅僅只是一個局域網,覆蓋區域有限,但它卻可以與現有的移動網,互聯網和其它通信網絡相連接,將許多Zigbee局域網相互連成為一個整體。有效的解決移動網的盲區覆蓋問題:我們知道,現有移動網絡在許多地方存在盲區,特別是鐵路,公路,油田,礦山等野外,更是如此。而增加一個移動基站或直放站的費用是相當可觀的,此時使用Zigbee網絡進行盲區覆蓋不僅經濟有效,而且往往是現在唯一可行手段。
Zigbee與現有數傳電臺的比較
1.可靠性高:由于Zigbee模塊的集成度遠比一般數傳電臺高,分離元器件少,因而可靠性更高;
2.使用方便安全:因為集成度高,比起一般數傳電臺來,Zigbee收法模塊體積可以做得很小,而且功耗低,例如成都西谷公司遠距離傳輸模塊(2-5公里),最大發射電流比一個CDMA手機還要小許多,因而很容易集成或直接安放在到設備之中,不僅使用方便,而且在戶外使用時,不容易受到破壞;
3.抗干擾力強,保密性好,誤碼率低:Zigbee收發模塊使用的是2.4G直序擴頻技術,比起一般FSK, ASK和跳頻的數傳電臺來,具有更好的抗干擾能力,和更遠的傳輸距離;參閱我們網站中有關CDMA直序擴頻技術的優越性討論,和Cypress公司有關實驗報道。
4.免費頻段:Zigbee使用的是免費頻段,而許多數傳電臺所使用的頻段不僅需要申請,而且每年都需要向國家無委會交納相當的頻率使用費。
5.價格低: Zigbee數傳模塊的價格只有具有類似功能的數傳電臺的幾分之一;(2.4G,250kps,3-5公里距離DSSS 數傳模塊每只不到200元人民幣)
提供低成本,高可靠性的無線數傳互聯網平臺(包括軟件和硬件),以及相關技術支持,以滿足不同客戶的具體需要,就是我們的服務宗旨。
學習Zstack之1
Zstack情況:
本人采用的是TI的Zstack1.4.3協議,據說這個需要IAR7.30B及以上版本,而目前市面上又沒有破解,所以用的人很少,這也是我的機會!呵呵?。ㄉ敌τ悬c多,關鍵是WORD里沒有表情符號,不能正常表達我此時的心情?。?/span>
正式開始:
開始之前在說一句:從TI網站上下載的Zstack的方法就不介紹了。否則就是從-1開始了而不是從0開始了-----------------我是這么覺得的!
第一步:安裝Zstack
從TI官方網站上下載的Zstack為:swrc072c.zip,我想這個壓縮包大家都認識。解壓之后為:ZStack-CC2430-1.4.3.exe文件。這個安裝文件大家都會了。默認安裝路徑為:C:\Texas Instruments\ZStack-1.4.3。安裝之后在C:\Texas Instruments\ZStack-1.4.3目錄下有各PDF文檔為:Getting Started Guide CC2430.pdf,不用多說,這個肯定是要看的。既然把它放到這么前面,說明它是入門中的入門文檔。下面就簡單介紹下這個文檔:
1、介紹了安裝ZStack-CC2430-1.4.3.exe需要的硬件軟件條件:需要電腦、操作系統為Windows 2000或 Windows XP。至于更高或更低版本的本人沒有嘗試。
2、講了安裝流程。這個有點多余了,這年月哪個有電腦的沒有安裝上百上千次的軟件?。康切枰獜娬{的是安裝路徑----默認就好!
3、接下來就是讓我們看的第一個文檔為:
Start->Programs->Texas Instruments->ZStack-1.4.3->Z-Stack User’s Guide,
既然讓我看我就來看看這個文檔??!
第二步:Z-Stack 用戶指導
這個文檔的更新時間為:2007年12月21日----應該還是比較新的版本。由于本人英文的卻有限,就不翻譯了,瀏覽一遍,把大概意思說下就可以了:
1、介紹
1.1、適用范圍
本文檔適用于CC2430ZigBee開發板----CC2430ZDK。
2、產品包描述(TI提供的CC2430ZDK工具包)
2.1、安裝包內容
這個就是上面提到的的ZStack-CC2430-1.4.3.exe安裝之后的所有內容了。說白了就是包含Zstack開發所需要的所有軟件和文檔資料等。
2.2、開發板介紹
兩塊 SmartRF04EB 評估版,每個都可以用于CC2430EM評估模塊。如圖1-1所示:
個人認為要求已經相當低了,如果你的電腦沒有這配置,個人強烈建議馬上扔掉!不過如今筆記本電腦很少有串口的,所以建議使用臺式電腦,而且裝機的時候一定要把串口引出,否則就比較麻煩了!
3.2、目標板需求
其實也是開發環境需求--- IAR EW8051。目前需要的版本為7.30B及以上。要求還是比較高的,因為目前這個版本沒有破解的。但是在http://www.iar.com/上有30天評估版下載。這個版本使用一定要小心,因為如果30天之后僅僅是卸載IAR重新安裝是沒有用的,一般最笨的辦法是重新安裝操作系統。解決這個問題最好的辦法就是買正版,呵呵,我想絕大多數像我這樣的中國人都不會買的。除此之外最好的辦法就是破解,但是目前這個破解極少,都是需要收費的,而且都是國外網站才有,所以我們就只好期望中國的高人抓緊破解并公開了!當然其他解決辦法就相對來說很多了,比如安裝后弄個還原點什么的;或者安裝后我不停地使用(每天24小時),30天之后我覺得你也學會了,就不用IAR這個版本了,說不定就移植到低版本上去了;等等類似之法我覺得都可以的。本人采用的是本辦法中相對比較聰明的,也是一位高人告訴我的:裝個虛擬操作系統,在虛擬操作系統下時間可以隨時更改,讓它一直停留在某個時間,主要30天的試用就比較慢長了,只要你不要忘記改那時間。
4、產品安裝過程
4.1、安裝Z-Stack
這個也就是安裝ZStack-CC2430-1.4.3.exe的過程。
4.2、IAR安裝
一般來說安裝選擇默認路徑,但是自定義路徑也不會出問題的。注意IAR版本7.30B及以上版本才可以運行1.4.3協議。
4.3、設備IEEE地址
每個 CC2430DB, CC2430EM,和 CC2431EM都已經排列了一個唯一的64位物理地址(IEEE地址),這個地址已經寫到了CC2430內部FLASH里面,在CC2430DB, CC2430EM,和 CC2431EM板的底部有這個地址標簽。
這個地址被寫入到FLASH的0x1FFF8地址中,注意這個地址也可以更改的,通過些FLASH軟件,一般0xFFFFFFFFFFFFFFFF地址被認為是無效地址。
5、配置并試用Z-Stack
5.1、配置Z-Stack
這個詳見5.3節。
5.2、邏輯類型
這里主要是介紹了ZIGBEE協議中的三種設備類型:
ZigBee 協調者(ZC):這個設備被配置為初始化并建立一個PAN網絡
ZigBee 路由器(ZR):該設備被配置為加入一個存在的網絡,可以加入一個協調求或路由器,然后允許其他設備加入它,在網絡中路有數據信息。
ZigBee 終端節點 (ZED):該設備被配置為加入一個存在的網絡,可以加入一個協調求或路由器。
5.3、建立樣品應用設備:SampleApp
基本上就是采用SampleApp應用中的Demo例子來演示整個流程,就是采用一個協調器和一個或多個路由器來形成一個ZigBee網絡演示。在該例子中主要通過SmartRF04EB板上的某些跳線來完成設備類型的選型,當然這個方法在程序中是需要判斷哪個按鍵被拉低或拉高,對于做個設計的來說應該是相當好理解的。
申明:由于本人很窮,所以沒錢買TI原裝開發包,當然也就沒有上面提到的硬件,本人采用的是某家公司(為了避免廣告,這里就不說明了)的硬件系統。
5.4、建立一個SampleLight協調器設備
至于提到的硬件連接這里一律省略。
無疑:首先要打開對應工程,如圖1-4所示:
圖1-4
在工作窗口中選擇DemoEB,如圖1-5所示:
圖1-5
然后選擇工程菜單(Project)下的全部編譯(Rebuild All)選項,如圖1-6所示:
圖1-6
然后選擇工程菜單(Project)下的調試(Debug)選項,如圖1-7所示:
圖1-7
下載完之后就可以退出調試狀態,通過選中調試菜單下的停止調試選項,如圖1-8所示:
圖1-8
按照此種方法下載至少兩個CC2430EM模塊,就可以進行Demo演示了。
6、 Z-Stack 示范
略
至于詳細的示范流程,這里先不說了,因為本人采用的硬件與原裝有點差異,即使按照這個方法下載仍然不能演示,因為我這個不能用跳線來選擇設備類型。
所以我必須進入程序把跳線判斷程序進行簡單必要的修改才能演示。
該文檔介紹的演示結果及現象都是基于CHIPCON原廠評估板。
7.PanID和通道(Channel)選擇
ZigBee協議規范規定,一個14位的個域網標志符(PAN ID)來標識唯一的一個網絡。Z-Stack可以用兩種方式由用戶自己選擇其PAN ID,當ZDAPP_CONFIG_PAN_ID值設置不為0xFFFF時,那么設備建立或加入網絡的PAN ID由ZDAPP_CONFIG_PAN_ID指定;如果設置ZDAPP_CONFIG_PAN_ID為0xFFFF;那么設備就將建立或加入它發現網絡中的“最好”的網絡。關于這里提到的“最好”的網絡,我覺得可能是有些參數評估,只不過這里沒有詳細的介紹,在后續文檔中應該有介紹的。
在2.4G頻段上,IEEE 802.15.4/ZIGBEE規范規定了16各頻道。用戶可以通過選擇DEFAULT_CHANLIST不同的值可以選擇不同的頻道,其頻道如圖1-9所示。改協議默認頻道為0xB及0x00000800。
圖1-9
DEFAULT_CHANLIST 和 ZDAPP_CONFIG_PAN_ID都作為IAR IDE中的編譯選項可以進行設置,在應用文件中的…\Projects\Tools\CC2430DB目錄下的f8wConfig.cfg文件中有相應設置,如圖1-10所示。
圖1-10
學習Zstack之2
上節基本上初步認識了Zstack的一些情況,今天繼續我的學習,打開Sample例子看看,究竟ZIGBEE是怎么回事。
毫無疑問:如果是第一次打開這個例子工程,肯定很迷糊,因為此時我迷糊了。對圖2-1我簡直是相當迷糊。
圖2-1
這么多文件夾,打開之后又有那么多文件,從何看起?不要著急,特別是有些人拿到之后,啥都不知道的人第一個問題就是:我要實現XXX,在哪修改或者在哪添加我的函數呢?凡是我遇到這樣的客戶,我就可以肯定他技術部咋的。就連我這個外行都知道,不把這些弄明白,就是實現XXX只需要修改一個字母,那也不知道在哪改???所以我不急,但是我也理解很多客戶,因為有時候項目催的比較急,畢竟老板都是外行嘛!
兩條路:1就是先看主函數,2就是看看TI提供例子說明文檔沒有。
我這里先看看主函數再說哈!因為我就知道從主函數看起.
沒辦法大概每個文件夾找啊,主函數的特征還是比較明明顯的,見圖2-2所示:
圖2-2
下面把主函數復制過來簡單看下:
ZSEG int main( void )
{
// Turn off interrupts------------關閉中斷
osal_int_disable( INTS_ALL );
// Initialize HAL-----------初始化HAL,關于HAL是什么我想后面會有介紹的。
HAL_BOARD_INIT();
// Make sure supply voltage is high enough to run----電壓檢測,最好是能保證芯片能正常工作的電壓
zmain_vdd_check();
// Initialize stack memory-------------初始化stack存儲區
zmain_ram_init();
// Initialize board I/O------------初始化板載IO
InitBoard( OB_COLD );
// Initialze HAL drivers-------------初始化HAL驅動
HalDriverInit();
// Initialize NV System--------------初始化NV系統,NV是什么后面我想也會有介紹的
osal_nv_init( NULL );
// Determine the extended address------------確定擴展地址(64位IEEE/物理地址)
zmain_ext_addr();
// Initialize basic NV items----------------初始化基本NV條目
zgInit();
// Initialize the MAC----------------初始化MAC
ZMacInit();
#ifndef NONWK
// Since the AF isn't a task, call it's initialization routine
afInit();
#endif
// Initialize the operating system----------初始化操作系統,看樣子這里面還有OS,麻煩了……..!
osal_init_system();
// Allow interrupts-------------允許中斷
osal_int_enable( INTS_ALL );
// Final board initialization------------------最后的版在初始化
InitBoard( OB_READY );
// Display information about this device---------------顯示設備信息
zmain_dev_info();
/* Display the device info on the LCD */------------液晶支持顯示
#ifdef LCD_SUPPORTED
zmain_lcd_init();
#endif
osal_start_system(); // No Return from here-------------------這里沒有返回,大概是進入OS了。
} // main()
可以看到基本上都是初始化函數,因為函數名稱都基本上帶了init字樣的,呵呵,個人覺得TI的變成習慣比我好,一看名稱就知道大概功能了。所以這里也奉勸各位像我這樣菜鳥級的初學者,一開始一定就要養成規范化編程的習慣,據說這樣維護以及以后升級或者移植兼容性都比較好。我就先不管各個初始化函數是怎么實現的,我先看看各個功能是什么,現掌握整體功能在細化,我覺得這樣的學習方法比較好,因為代碼是在太多了,從一開始就逐句看,我敢保證沒幾個人有耐心看完看明白!
幸好每個初始化函數都有一句說明,雖然是英文的,但是理解起來一點都不難的。關于每個函數的功能我就直接寫在上面的程序里面,節省紙張哈!
一句話:主函數的功能就是初始化!
主函數看完了又開始模糊了,又從何看起呢?在無從下手之際,只有去尋求TI說明文檔的幫助了。上節不是漏掉了內容,是關于演示結果的,這里做上補充,怕因為缺調一點后面遇到什么不理解的就慘了!
Sample例子演示演示現象:
1、認識硬件------------按鍵和LED
上節提到了EM和DB兩個板子,其硬件是不一樣的。按鍵EM就有5各SW1~SW5,而DB只有1各方向鍵,但是他們有個對應關系,如圖2-3所示.
圖2-3
LED數量和顏色也不一樣,EM有四個LED,如圖2-4;而DB只有兩個,如圖2-5。
如圖2-4
如圖2-5
關于上面幾個圖2-4/5中出現的LEDx實際上是程序中出現的關鍵字。
2、初始化64位IEEE地址
實際上在主函數中有這么個初始化函數的:zmain_ext_addr()。這里說如果地址復位為0xFFFFFFFFFFFFFFFF的話,那么就會不停的閃爍LED1,一直等到按鍵SW5按下后程序才能繼續運行,意思就是說按下SW5后就把無效的地址初始化為有效地物理地址了,這個應該是程序上實現的,那么就來看看對應的程序zmain_ext_addr。
/*********************************************************************
* @fn zmain_ext_addr
* @brief Makes extended address if none exists.確定擴展地址是有效的
* @return none
*********************************************************************/
static ZSEG void zmain_ext_addr( void )
{
uint8 i;
uint8 led;
uint8 tmp;
uint8 *xad;
uint16 AtoD;
// Initialize extended address in NV初始化NV里的擴載地址
osal_nv_item_init(ZCD_NV_EXTADDR,Z_EXTADDR_LEN, NULL );
osal_nv_read( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, &aExtendedAddress );
// Check for uninitialized value (erased EEPROM = 0xFF)檢查是否為無效值(地址)
xad = (uint8*)&aExtendedAddress;
for (i =0;i < Z_EXTADDR_LEN; i++ )
if(*xad++ != 0xFF ) return;-----如果有一個字節不為0xFF,那么該地址有效返回
#ifdef ZDO_COORDINATOR
tmp = 0x10;
#else
tmp = 0x20;
#endif
// Initialize with a simple pattern----------------簡單初始化擴展地址
xad = (uint8*)&aExtendedAddress;
for ( i = 0; i < Z_EXTADDR_LEN; i++ )
*xad++ = tmp++;
// Flash LED1 until user hits SW5 ---------閃爍LED1直到SW5按下
led = HAL_LED_MODE_OFF;
while ( HAL_KEY_SW_5 != HalKeyRead() )---------------------SW5循環檢測
{
MicroWait( 62500 );
HalLedSet( HAL_LED_1, led^=HAL_LED_MODE_ON );//Toggle the LED
MicroWait( 62500 );
}
HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );
// Plug AtoD data into lower bytes
AtoD = HalAdcRead (HAL_ADC_CHANNEL_7, HAL_ADC_RESOLUTION_10);
xad = (uint8*)&aExtendedAddress;
*xad++ = LO_UINT16( AtoD );
*xad = HI_UINT16( AtoD );
#if !defined( ZTOOL_PORT ) || defined( ZPORT ) || defined( NV_RESTORE )
// If no support for Z-Tool serial I/O,
// Write temporary 64-bit address to NV些臨時的64位物理地址進入NV
osal_nv_write( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, &aExtendedAddress );
#endif
}
從程序中可以看出,一開始就檢測FLASH中的物理地址,因為這個地址在FLASH中是固定的存儲空間,一旦為有效地址就退出函數,一旦為無效地址(0xFFFFFFFFFFFFFFFF),那么就對其物理地址進行簡單的初始化并檢測SW5按鍵。還是比較好理解的!
3、運行例子
在這里提到了跳線,由于本人采用的非TI原裝硬件,沒有該跳線,所以必須對程序進行修改,否則檢測不到跳線,連ZIGBEE的設備類型都不能確定,肯定不能正常運行了。所以這里就先暫時不說了,這里要說的是一切都正常的情況下,例子的驗尸結果。小小跳躍一下。不然學習一直沒有進展很麻煩的!
協調器:上電運行,地址檢測如上面介紹的情況,通過之后呢-------就進行通道掃描,此時LED1閃爍,一旦協調器成功建立網絡,此時LED1停止閃爍,而LED3被點亮。
路由器:上電運行,仍然是地址檢測在前。之后就是通道掃描尋求是否又存在的網絡,此時LED1閃爍,一旦檢測到存在網絡并成功加入該網絡,LED1將停止閃爍,被替換的是LED3別點亮,也就表明路由器成功加入了網絡。
那么此時能進行的操作控制是什么呢,也是最簡單的表現手法---按鍵無線控制LED:
周期(5S)發送信息到網絡中每個設備
SW1按下,發送一個信息到組1的設備
SW2按下,退出/加入組1
這個我是經過驗證的。如:
按下協調器SW1,路由器的LED1狂閃幾下;按下路由器的SW1,那么協調器的LED1也就狂閃幾下;當然我是只有兩個節點。
如果按1下協調器的SW2,在按下路由器的SW1,此時協調器就沒有反應,表明協調器已經退出組1;但是再按下協調器SW2在按路由器的SW1就與上一步類似了。路由器與此類似可以通過SW2退出/加入組1.
終于把演示弄完了,接下來就來看看程序。在此之前還是來看看TI提供的Sample指導文檔。這個文檔個人覺得寫的不錯,要是沒看之前就看程序的卻很郁悶的!
但是本人英文很差,所以需要慢慢看,等點時間放上來!
Z-Stack之3
Sample Application分析(上)
1、Z-Stack CC2430DB and CC2430EB Sample Application
1.1、介紹
該文檔時介紹TI協議入門的一個例子SampleApp的,適用EM和DB開發板。
1.1.1、描述
這個例子是非常簡單的演示,每個設備都可以發送和接收兩個信息
周期信息-----加入該網絡的所有設備每隔10S(可能會加上一個隨機數的mS)都發送一個周期信息,該信息的數據載荷為發送信息次數的計數。
閃爍控制信息---------通過按下SW1可以發送一個控制燈閃爍的廣播信息,該廣播信息只針對組1的所有設備。
所有設備初始化為加入組1,所以網絡一旦成功建立/加入就可以進行閃爍控制??梢酝ㄟ^按下設備的SW2退出組1,所以可以通過退出組1可以不接受閃燈信息。通過按下SW2也可以讓不在組1的設備加入近組1,從而又可以接受閃燈信息了。
這個理解應該不困難的,反正我理解沒有什么障礙!
1.1.1.1、按鍵
SW1:發送閃爍信息到組1所有設備
SW2:轉換推出/加入組1狀態
1.1.2、用戶應用開發
這里我基本上能看明白是什么,但是我不打算寫出來,因為涉及到一些ZIGBEE的關鍵術語,不是很明白。
大概就是簡單介紹了下用戶怎么利用例子做自己的應用,但是實用價值不高,說的太籠統,全是概念性的說明。
1.2、OSAL任務
1.2.1、初始化
因為Z-Stack是在OS下運行的,所以在之前必須調用osalAddTasks()初始化任務。
1.2.2、組織
關于OS的API函數介紹請看文檔:Z-Stack OSAL API (F8W-2003-0002),應該說協議棧的每層或者說每部分都有相關的API說明文檔。osalAddTasks()初始化任務,osalTaskAdd()函數添加任務,都可以到API文檔或程序中詳細分析函數功能。
1.2.3、系統服務
OSAL和APL系統服務是唯一的,因為比如按鍵和串口類似事件處罰就只能用唯一的一個任務標識。這兩個硬件都留給了用戶自己定義使用。
1.2.4、應用設計
用戶可能為每一個應用對象都創建一個任務,或者為所有的應用對象只創建一個任務。當選擇上述的設計的時候,下面是一些設計思路:
1.2.4.1、為許多應用對象創建一個OSAL任務
下面是正面和反面(pros & cons)的一些敘述:
- Pro:接受一個互斥任務事件(開關按下或串口)時,動作是單一的。
- Pro:需要堆??臻g保存一些OSAL任務結構。
- Con:接收一個AF信息或一個AF數據確認時,動作是復雜的-----在一個用戶任務上,分支多路處理應用對象的信息事件。
- Con:通過匹配描述符(如:自動匹配)去發現服務的處理過程更復雜-----為了適當的對ZDO_NEW_DSTADDR信息起作用,一個靜態標志必須被維持。
1.2.4.2、為一個應用對象創建一個OSAL任務
一對一設計的反面和正面(pros & cons)是與上面一對多設計相反的:
- Pro:在應用對象試圖自動匹配時,僅僅一個ZDO_NEW_DSTADDR被接收。
- Pro:已經被協議棧下層多元處理后的一個AF輸入信息或一個AF數據確認。
- Con:需要堆??臻g保存一些OSAL任務結構。
- Con:如果兩個或更多應用對象用同一個唯一的資源,接收一個互斥任務事件的動作就更復雜。
1.2.5、強制方法
任何一個OSAL任務必須用兩種方法執行:一個是初始化,另一個是處理任務事件。
1.2.5.1、任務初始化
在例子中調用如下函數執行任務初始化:
“Application Name”_Init(如SAPI_Init)。該任務初始化函數應該完成如下功能:
變量或相應應用對象特征初始化,為了使OSAL內存管理更有效,在這里應該分配永久堆棧存儲區。
在AF層登記相應應用對象(如:afRegister())。
登記可用的OSAL或HAL系統服務(如:RegisterForKeys())
1.2.5.2、任務事件處理
調用如下函數處理任務事件:
“Application Name”_ProcessEvent (e.g. SAPI_ProcessEvent()).除了強制的事件之外,任一OSAL任務能被定義多達15個任務事件。
1.2.6、強制事件
一個任務事件SYS_EVENT_MSG (0x8000), 被保留必須通過OSAL任務設計。
2.2.6.1、SYS_EVENT_MSG (0x8000)
任務事件管理者應該處理如下的系統信息子集,下面只列出了部分信息,但是是最常用的幾個信息處理,推薦根據例子復制到自己項目中使用。
1.2.6.1.1、AF_DATA_CONFIRM_CMD
調用AF_DataRequest()函數數據請求成功的指示。Zsuccess確認數據請求傳輸成功,如果數據請求設置AF_ACK_REQUEST標志位,那么,只有最終目的地址成功接收后,Zsuccess確認才返回。如果如果數據請求沒有設置AF_ACK_REQUEST標志位,那么,數據請求只要成功傳輸到下跳節點就返回Zsuccess確認信息。
1.2.6.1.2、AF_INCOMING_MSG_CMD
AF信息輸入指示
1.2.6.1.3、KEY_CHANGE
鍵盤動作指示
1.2.6.1.4、ZDO_NEW_DSTADDR
匹配描述符請求(Match Deor Request)響應指示。(例如:自動匹配)
1.2.6.1.5、ZDO_STATE_CHANGE
網絡狀態改變指示
1.3、網絡格式化
示例應用程序編譯為協調器的在default_chanlist指定的通道上形成一個網絡,協調器將建立一個隨機編號源于自身的IEEE地址或由zdapp_config_pan_id指定的網絡PAN ID(如果zdapp_config_pan_id不為0xFFFF)。
示例應用程序編譯為路由器或結束設備的將嘗試加入網絡在default_chanlist指定的通道上,如果zdapp_config_pan_id沒有定義為0 xFFFF ,路由器將受到限制,只有加入參數zdapp_config_pan_id規定的網絡PAN ID。
1.3.1、自動啟動
設備自動開始嘗試組建或加入網絡。如果設備設置為等待計時器或其他外部事件發生后才啟動,那么HOLD_AUTO_START必須被定義。為了稍后以手動啟動方式啟動設備,那么需要調用ZDApp_StartUpFromApp(函數
1.3.2、軟件啟動
為了在形成網絡過程中節省所需的設備類型,那么所有的路由器設備可以被通過soft_star定義作為一個協調器。如果自動啟動是需要的話,那么auto_soft_start必須被定義。
1.3.3、網絡恢復
通過設置NV_RESTORE和/或NV_INIT,可以讓設備斷電或者意外掉電重新啟動后重新回復網絡。
1.3.4、加入通告
當設備形成或加入網絡后會發通報到ZDO_STATE_CHANGE信息事件。
學Z-Stack之4
Sample Application分析(下)
上節介紹了建立一個應用需要做的幾個必須的事情,現在就來通過分析Sample Application來具體看看需要做哪些事情,才能建立一個ZIGBEE應用功能。當然這里只是做點簡單的必須的工作。
The Sample Application (SampleApp)
1、介紹
主要是介紹一個應用建立的結構及需要進行的程序流程。
1.1、程序流程
1.1.1、初始化
首先需要調用初始化函數SampleApp_Init()。
SampleApp_TaskID = task_id;
初始化應用建立的任務ID號,其實用過OS的人都應該曉得這個是干啥的,我沒用過,不是很理解,但是我知道是必須的,就相當于一個任務的標識,這樣才能區分運行過程中不同任務中的不同事件。我是這么認為的,ID說白了就是給該任務取了各名字,就向人名字一樣,區分不同的人,就是一個代號。人名可以重復,重復了有時候叫起來就容易混淆;所以才程序中為了避免這種混淆,就強制性的規定任務ID不能重復。要是哪天國家或者聯合國姓名管理委員會規定,人民不能重復,那么這個人名就需要全球統一管理了。那給娃取個名字就要向聯合國姓名管理委員會申請了。呵呵!
SampleApp_NwkState = DEV_INIT;
初始化應用設備的網絡狀態。怎么說呢,據說是設備類型的改變都要產生一個事件,叫ZDO_STATE_CHANGE,從字面理解為ZDO狀態發生了改變。所以在設備初始化的時候一定要把它初始化為什么狀態都沒有。那么它就要去檢測整個環境,看是否能重新建立或者加入存在的網絡。但是有一種情況例外,就是當NV_RESTORE被設置的時候(NV_RESTORE是把信息保存在非易失存儲器中),那么當設備斷電或者某種意外重啟時,由于網絡狀態存儲在非易失存儲器中,那么此時就只需要恢復其網絡狀態,而不需要重新建立或者加入網絡了。我也是從文檔中這么理解的,至于為什么只有有待進一步考證。
SampleApp_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;
SampleApp_DstAddr.endPoint = 0;
SampleApp_DstAddr.addr.shortAddr = 0;
看見這幾句話從字面理解為:初始化不標設備地址模式及目標設備EP號和網絡地址。從代碼可以看出,這些地址或EP均為0。也就是說目標設備為協調者的ZDO,這個意義就很明顯了,就是設備建立后可以直接與協調器的ZDO交互信息。
SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
----- SampleApp EP描述符的EP號
SampleApp_epDesc.task_id = &SampleApp_TaskID;------ SampleApp EP描述符的任務ID
SampleApp_epDesc.simpleDesc =------------------ SampleApp EP簡單描述符
SimpleDeionFormat_t *)&SampleApp_SimpleDesc;
SampleApp_epDesc.latencyReq = noLatencyReqs;
//在AF層中登記注冊改應用EP
afRegister( &SampleApp_epDesc );
這里其實是對SampleApp的EP描述符進行初始化。
本人理解:要對改應用進行初始化并在AF進行登記,告訴應用層有這么一個EP已經可以使用,那么下層要是有關于改應用的信息或者應用要對下層做哪些操作,就自動得到下層的配合,至于這個配合是怎么回事,那么就需要好好研究下層的協議了。當然在這里肯定是沒那時間精力和能力研究了!
其實在這個應用中,只是讓AF配合SAMPLEAPP_PROFID / SAMPLEAPP_ENDPOINT這兩個應用。那么通過什么呢,通過發送OSAL SYS_EVENT_MSG消息中的(AF_INCOMING_MSG_CMD)事件到SampleApp任務ID。
RegisterForKeys( SampleApp_TaskID );
登記按鍵事件到SampleApp_TaskID,在前面已經說了按鍵這個是唯一的,也就是所有任務中有且只有各任務能登記鍵盤事件。前面還說了還有一個也是唯一,你猜是什么?
SampleApp_Group.ID = 0x0001;
osal_memcpy( SampleApp_Group.name, “Group1”);
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
閃燈信息被發送到組1,同樣也只有在組1的設備才能接收這個信息。設備啟動時已經被設定為組1設備了,但是可以通過按SW1推出/加入組1。這里提到了組的概念,我反正暫時不是很清楚這個是什么東西,在程序中怎么實現也很模糊,但是應用中的好處還是不難想象的,不外呼是就是想控制誰可以事先規定好,還可以動態更改。
1.2、事件處理
玩過OS的人都知道,OS中最重要的概念不外呼就是任務啦,消息啦,事件啦等。從我們自己平時的工作中也不難想象,如果老板安排了某項工作,那么我們就需要做的,這個工作可能是預先計劃好的,也有可能是臨時的,那么這些預先定好或者臨時的工作可以稱之為事件。而老板讓您做的方式,比如通過文件下達,或者叫:某某你把XXX做下。那么讓老板下達的文件內容或者說的內容我這里可以稱之為消息。老板給了你不同的消息那么就需要干不同的事件,至于任務可以理解為公司的不同的員工,呵呵!我簡直是理解的天才,這樣舉例居然也能忽悠通過?。。(∩_∩)o…哈哈
在Z-Stack中,每個應用任務都通過SampleApp_ProcessEvent()函數來處理任務中的事件。一旦SampleApp_TaskID任務的某個OSAL事件發生,那么就可以通過調用SampleApp_ProcessEvent()函數來處理。在SampleApp_ProcessEvent()中有一個事件處理循環,循環檢測是哪個事件發生。
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t*)osal_msg_receive( SampleApp_TaskID );
while ( MSGpkt )
{
可以看到是通過檢測SYS_EVENT_MSG是否有事件信息發生。
switch ( MSGpkt->hdr.event )
這里是判斷SYS_EVENT_MSG事件類型,不同的SYS_EVENT_MSG類型需要不同的處理。
case KEY_CHANGE:
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state,
((keyChange_t *)MSGpkt)->keys );
break;
比如這里判斷是否是鍵盤事件,如果鍵盤事件就調用鍵盤處理函數。
如果一個OSAL任務已經被登記組側,那么任何鍵盤事件都將接受一個KEY_CHANGE事件信息??赡苡腥缦聨追N方式得到鍵盤事件信息
1)、HAL檢測到鍵盤按下(中斷或者查詢檢測)
2)、HAL的OSAL任務檢測到一個鍵盤狀態改變調用回叫函數產生
3)、OSAL鍵盤改變回叫函數發送一個OSAL系統事件信息(KEY_CHANGE)。
case AF_DATA_CONFIRM_CMD:
// 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;
任何AF_DataRequest()數據請求函數調用后,都通過AF_DATA_CONFIRM_CMD系統事件信息回叫返回成功Zsuccess。
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ( (SampleApp_NwkState == DEV_ZB_COORD)
||(SampleApp_NwkState == DEV_ROUTER)
||(SampleApp_NwkState == DEV_END_DEVICE) )
{
// Update the LCD’s network indicator
// Start sending "the" message in a regular interval.
osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
}
break;
這里就是前面介紹的設備狀態改變事件處理了。
只要網絡狀態發生改變,那么通過ZDO_STATE_CHANGE事件通知所有的任務。注意:在這個例子中,一旦設備成功加入網絡,是通過定時運行的方式運行的。一旦網絡狀態為加入”JOINED”,那么它可能不需要任何的認為操作就能綁定其他設備,因為設置為自動發現并綁定的。
// Release the memory
osal_msg_deallocate( (uint8 *)MSGpkt );
釋放存儲空間。
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
{
// Send "the" message
SampleApp_SendPeriodicMessage();
// Setup to send message again
osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_MSG_TIMEOUT );
// return unprocessed events
return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
}
這里檢測事件是否為周期發送信息事件。
在SampleApp.h中定義了:
#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT 0x0001
在這個應用中,調用了osal_start_timer()函數來定時產生發送周期信息事件。而定時器的運行是設備一旦加入網絡就不停的在運行。從上面可以看到,用函數SampleApp_SendPeriodicMessage()發送周期信息,而用函數osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_MSG_TIMEOUT )來繼續運行定時器定時發送這個周期信息。關于這個osal_start_timer可以多了解下,第一個參數SAMPLEAPP_SEND_PERIODIC_MSG_EVT四信息時間,也就是事件到了產生一個什么事件。第二各參數SAMPLEAPP_SEND_MSG_TIMEOUT是需要定時的時間,這里就是發送周期信息的時間周期。
1.3、消息流程
通過OSAL定時器,這個應用定時發送一個周期信息:
void SampleApp_SendPeriodicMessage( void )
{
afAddrType_t dstAddr;
dstAddr. addrMode = afAddrBroadcast;
dstAddr.addr.shortAddr = 0xFFFF; // 廣播發送
dstAddr. endpoint = SAMPLEAPP_ENDPOINT;
if ( AF_DataRequest( & dstAddr, &SampleApp_epDesc,
SAMPLEAPP_PERIODIC_CLUSTERID,
(uint8)sampleAppPeriodicCounter++,
(uint8 *)&sampleAppPeriodCounter,
&SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
// Successfully requested to be sent.----發送成功處理
}
else
{
// Error occurred in request to send.---發送失敗處理
}
}
在這里調用了AF_DataRequest()函數用來發送數據。關于發送數據的具體過程這里就不做深入研究,不外乎就是把數據從應用層傳到網絡層,在傳到MAC,在傳到無力層,最后通過OTA發送出去。接收數據就是相反的過程了,那么接收之后,在應用層有什么反應呢,最直觀的反應就是會發送一個AF_INCOMING_MSG_CMD消息事件。
case AF_INCOMING_MSG_CMD:
SampleApp_MessageMSGCB( MSGpkt );
break;
這里表示收到某個信息,然后在里面調用了收到信息的信息處理函數SampleApp_MessageMSGCB( MSGpkt )。
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case SAMPLEAPP_PERIODIC_CLUSTERID:
// Display and increment a counter on the LCD in the periodic space
break;
case SAMPLEAPP_FLASH_CLUSTERID:
flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );
HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
break;
}
}
這里判斷了兩種信息:
周期信息
閃燈信息
不同的信息就相當于收到了不同的命令,然后根據不同的命令做出了不同的處理。是個會寫程序都明白?。。。?/span>
到這里,我就基本上把這個應用文檔看完了,至于理解了多少我迷糊,理解正確了多少我更加迷糊,反正我按照我自己的方式理解了!
學Z-Stack之5
前面雖然寫了不少,但是回頭看看大多都是廢話,不過也沒辦法,沒有廢話的潤色就太枯燥了,太技術化了,這個不是我的本意。不知道前面寫的怎么樣,技術含量肯定是不高的。這個本人是相當清楚,但是我最大的期望就是錯誤不要太多!
突然想起來前面有個問題沒有解決,我想很多人看到那里都很郁悶的。就是設備類型的選擇,在TI原裝系統上是通過板載跳線來選擇的,但是我這里不是采用原裝,那么就需要通過程序來修改其設備類型,然后編譯下載。具體程序段如下:
#if defined ( SOFT_START )
if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // SOFT_START
這里有個條件編譯,其條件編譯設置如圖5-1。
圖5-1
既然這里設置了SOFT_START,那么上段程序就要被編譯。那么第一句程序
if ( readCoordinatorJumper() )
就是檢測跳線,其實稍微知道編程的都了解怎么修改了,哈哈!
屏蔽:
if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
這3句,那么就只剩下:zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;了
那么編譯自然該設備就為路由器了。簡單吧!?。。???!
協調器我就不想多說怎么做了哈?。。。。。。。。。。。?/span>
還有一個問題需要說下,就是Ti原裝的EM板子用到了LCD,所以在程序中可能在某個地方要對LCD初始化,那么如果沒有液晶的板子或者與TI那個不完全一樣的LCD就有可能運行不走,通俗的解決辦法是禁止LCD初始化等操作,Ti在這個方面做的很人性化,禁止LCD功能沒有必要在程序中找到LCD相關程序刪除,而是僅僅需要通過條件編譯來禁止。顯得相當簡單,如5-2圖就是禁止LCD的條件編譯。
圖5-2
解決這個問題后一般都能夠運行程序了。也就是說到這里如果還把Demo程序運行不起來的話,那就證明我所有的東西都白寫了,反正我到這里我的Demo程序已經運行如飛了。
那么接下來就是來看看Z-Stack具體的一些東西了,我打算先這樣看起:
1、Z-Stack的結構,因為打開Z-Stack的目錄可以看出還是比較復雜的,只有比較清楚了解其結構之后呢,在程序運行或者修改中才能順利的找到自己想要的部分。
2、Z-Stack的應用建立。就是怎么在TI提供的協議(裸協議)上建立一個應用。這個層次要求就比較高了,我初步的設想是希望能分析完SAMPLE例子的應用就能自己建立,而不需要太多的去了解下層的協議。但是往往希望與現實是有偏差的,走一步算一步了。
3、了解硬件相關設定、驅動。也就是說把例子跑通了,畢竟是基于TI的硬件,或者說基于開發系統的硬件,如果要做自己的應用,那么必須要開發自己的硬件。怎么把自己的硬件驅動加入協議,這個我想也是需要解決的問題。
4、接下來可能就要深入分析協議了,這個目前我還不清楚從什么地方看起,因為畢竟對ZIGBEE這個協議本身就不太了解,但是在學習過程中應該會慢慢對它有認識。所以到了這一步的時候說不定我就已經摸索出一條方法了---畢竟俺是相當的聰明嘛!
5、需要解決的問題,需要了解的東西很多,對于不太了解這個東西的我來說,不可能非常有計劃并統籌安排這些事,走彎路是必然的,但是我一致認為走彎路才是經驗的積累!
學習Z-Stack之6
--------------Z-Stack指導
首先來看看Z-Stack的結構。
第一次打開工程印象最深刻的就是左邊一排文件夾,如圖6-1所示。
其實這個還是很容易理解的:
APP(Application Programming):應用層目錄,這是用戶創建各種不同工程的區域,在這個目錄中包含了應用層的內容和這個項目的主要內容,在協議棧里面一般是以操作系統的任務實現的。
HAL(Hardware (H/W) Abstraction Layer):硬件層目錄,包含有與硬件相關的配置和驅動及操作函數。
MAC:MAC 層目錄,包含了MAC 層的參數配置文件及其MAC 的LIB 庫的函數接口文件。
MT(Monitor Test):實現通過串口可控各層,于各層進行直接交互。
NWK(ZigBee Network Layer):網絡層目錄,含網絡層配置參數文件及網絡層庫的函數接口文件,APS層庫的函數接口
OSAL(Operating System (OS) Abstraction Layer):協議棧的操作系統。
Profile:AF(Application work)層目錄,包含AF層處理函數文件。
Security:安全層目錄,安全層處理函數,比如加密函數等。
Services:地址處理函數目錄,包括著地址模式的定義及地址處理函數。
Tools:工程配置目錄,包括空間劃分及ZStack 相關配置信息。
ZDO(ZigBee Device Objects):ZDO 目錄。
ZMac: MAC 層目錄,包括MAC 層參數配置及MAC 層LIB 庫函數回調處理函數。
ZMain:主函數目錄,包括入口函數及硬件配置文件。
Output:輸出文件目錄,這個EW8051 IDE 自動生成的。
那么知道各個文件夾大概是什么功能,分布在ZIGBEE的哪一層,那么在以后的工作中無論是查詢某些功能函數還是修改某些功能函數,甚至是添加或刪除某些功能函數就能順利的找到在什么地方了,當然要想真的順利還需要花更多的時間熟悉這個協議棧了!
了解Z-Stack結構后那么就能看看它的功能。
不用問,這個是針對ZIGBEE無線網絡寫的協議棧,呵呵!那么就要先大概了解下ZIGBEE這個技術。我這里就不介紹理論了,就從Z-Stack實際的角度介紹些實用的概念。
1、Zigbee網絡中的節點
在ZB網絡中,每個節點都有指定的配置參數,從而確定其設備類型,不同的設備類型,在網絡中有著不一樣網絡任務。在屬于多跳網絡的ZB網絡中,兩個節點需要完成數據傳輸,可能需要經過其他中間節點的協助,所以節點的類型參數配置是非常必要的。
對每個節點有兩個任務:
(i)執行指定的網絡功能函數
(ii)配置確定的參數到指定的值。
網絡功能的設置確定了該節點的類型,參數配置和指定的值確定了堆棧的模式。
節點類型
在ZB中,設備類型分為三類:協調器,路由器和終端設備。
圖6-2就是這三種設備類型組成的一個典型網絡。
其中黑色節點為協調器
紅色節點為路由器
白色節點為終端設備
那么這個就是一個典型的網狀網絡MESH。
協調器
協調器是一個ZB網絡的第一個開始的設備,或者是一個ZB網絡的啟動或建立網絡的設備。協調器節點選擇一個信道和網絡標志符(也叫PAN ID),然后開始建立一個網絡。協調器設備在網絡中還可以有其他作用,比如建立安全機制、網絡中的綁定的建立等等。
注意:協調器主要的作用是建立一個網絡和配置該網絡的性質參數。一旦這些完成,該協調器就如同一個路由器,網絡中的其他操作并不依賴該協調器,因為ZB是分布式網絡。
路由器
一個路由器的功能有(1)作為普通設備加入網絡(2)多跳路由(3)輔助其它的子節點完成通信。
一般來說,路由器需要一直處于工作狀態,所以需要主干線供電(區別于電池供電)。但是在某指定的網絡結構中可以采用電池供電,如“串樹型”網絡模式中,允許路由器周期的運行操作,所以可以采用電池供電。
終端設備
為了維持網絡最基本的運行,對于終端設備沒有指定的責任。也就是說,在一個基本網絡中,終端設備沒有必不可缺少性。所以它可以根據自己功能需要休眠或喚醒,因此為電池供電設備。一般來說,該設備需要的內存較少(特別是內部RAM)
堆棧模式(Stack Profile)
需要被配置為指定值的堆棧參數,連同這些值被稱為堆棧模式。這些堆棧模式參數被ZB聯盟定義指定。在同一個網絡中的設備必須符合同一個堆棧模式(同一個網絡中所有設備的堆棧模式配置參數必須一致)。
為了互操作性,ZB聯盟為06協議棧定義了一個堆棧模式,所有的設備只要遵循該模式的參數配置,即使在不同廠商買的不同設備同樣可以形成網絡。
如果應用開發者改變了這些參數配置,那么他的產品將不能與遵循ZB聯盟定義模式的產品組成網絡,也就是說該開發者開發的產品具有特殊性,我們稱之為“關閉的網絡”,也就是說它的設備只有在自己的產品中使用,不能與其他產品通信。
該協議模式標志符在設備通信的信標傳輸中被匹配,如果不匹配,那么該設備將不能加入網絡。“關閉網絡”的堆棧模式有一個0ID,而06協議棧模式有一個1ID。該堆棧模式被配置在nwk_globals.h文件中的STACK_PROFILE_ID參數。如:
#define STACK_PROFILE_ID HOME_CONTROLS。
2、Zigbee網絡中的地址
地址類型
ZB設備有兩種地址類型,一個是64位IEEE地址(也可以叫MAC地址或擴展地址),一個是16位網絡地址(也可以叫邏輯地址或短地址)。
64位地址是全球唯一的,作為設備(產品)的終生地址被分配。它通常被開發商或安裝的時候被指定。該地址由IEEE分配指定,該地址的信息和獲得該地址的方法見:http://standards.ieee.org/regauth/oui/index.shtml
16位地址在設備加入網絡的時候被分配,由這個網絡自動分配。該地址只能用與本網絡中,標志不同的設備間傳遞信息。
網絡地址分配
ZB分布式網絡中地址分配是唯一的。為了不使網絡中設備混亂,為每個設備指定確定的地址是非常必要的。
在分配地址之前,一些參數必須被設置:MAX_DEPTH, MAX_ROUTERS 和 MAX_CHILDREN 。
這些參數都是ZB協議模式的一部分,在06ZS模式中這些參數設置為: (MAX_DEPTH = 5, MAX_CHILDREN = 20, MAX_ROUTERS = 6).
參數設置
MAX_DEPTH決定了網絡的最大深度。協調器的深度是0,它的子設備的深度是1,他們的子設備的深度是2,依次類推。所以MAX_DEPTH參數限制了網絡物理上的“長度”
MAX_CHILDREN參數決定了一個路由器(或一個協調器)能承載子設備的最大數目。
MAX_ROUTERS參數決定了一個路由器(或一個協調器)能承載路由器的最大數目。這個參數實際上是MAX_CHILDREN參數的一個子集,剩下的(MAX_CHILDREN-MAX_ROUTERS)地址空間屬于終端設備。
開發者自定義
如果開發者想改變這些值,那么需要做如下幾步:
首先得保證這些參數新的值是合法的。既然整個地址空間被限制在2-16內,那么這些參數的大小就已經有了限制。分布在release(在文件夾Projects\zstack\Tools中)的Cskip.xls文件能校驗這些參數是否合法。在鍵入這些參數的值后大概這個電子表格,如果非法,一個錯誤信息將給出。
之后選擇合法的值,開發者需要確保不使用標準的協議棧模式,而用指定的協議棧模式代替(用NETWORK_SPECIFIC替換STACK_PROFILE_ID當前的值)。然后在“nwk_globals.h”文件中的MAX_DEPTH參數根據需要設置為適當的值。
另外,nwk_globals.c文件中排列的CskipChldrn和CskipRtrs必須被設置,這些排列是
z-stack中的尋址
為了在網絡中發送數據到一個設備,應用層一般用AF_DataRequest()函數。而被發送的目的設備的地址類型afAddrType_t被定義在“ZComDef.h”中:
typedef struct
{
union
{
uint16 shortAddr;
ZLongAddr_t extAddr;
} addr;
byte addrMode;
} zAddrType_t;
地址模式參數
注意:除這個網絡地址之外,地址模式參數也需要被指定。目的地址模式可能是如下值之一(AF地址模式被定義在“AF.h”中):
typedef enum
{
afAddrNotPresent = AddrNotPresent,
afAddr16Bit = Addr16Bit,
afAddrGroup = AddrGroup,
afAddrBroadcast = AddrBroadcast
} afAddrMode_t;
地址模式參數是需要的,因為在ZB中,數據包能被點傳輸、多點傳輸或者廣播傳輸。點傳輸被發送到單個設備,多點傳輸一定發送到一組設備,廣播傳輸一般被發送到網絡中的所有設備。如下是更詳細的說明。
點到傳輸 (Unicast)
這是標準地址模式,被用于發送一個數據包到網絡中單個已知地址的設備。這個addrMode參數被設置為Addr16Bit,目的網絡地址在數據包中一同被發送。
間接尋址
數據包中的最終目的地址不識別的時候使用。該模式被AddrNotPresent設置,而且目的地址沒有被指定。代替目的地址的是:一個存儲在發送設備協議棧的“綁定表格”,該表格中有被綁定設備的地址。這個特性被調用是源于綁定。(看后面關于綁定部分)
當被發送的信息包下載到協議棧時,從這個綁定表格中尋找使用的目的地址。然后該信息包被有規則的處理為點對點數據包。如果有多個(大于1)目的地址在綁定表格中被發現,那么該數據包將被拷貝成對應的份數分別發送給他們。
在(ZigBee04)版本之前,在協調器中有一個存儲綁定表格的選項。因此,發送設備發送數據包到這個協調器,然后協調器在它的綁定表格中查找最終的目的地址,對數據包進行在一次發送。該選項特性在協調器綁定被調用
廣播傳輸
該模式在應用層想發送一個數據包到所有網絡中的所有設備時被使用。該地址模式被AddrBroadcast被設置,目的地址被設置為下列值之一:
NWK_BROADCAST_SHORTADDR_DEVALL (0xFFFF)-信息將被發送到網絡中的所有設備(包括休眠的設備)。對于休眠的設備,這個信息將被保持在它的父節點,直到該休眠設備獲得該信息或者該信息時間溢出(在f8wConfig.cfg 中的NWK_INDIRECT_MSG_TIMEOUT選項)。
NWK_BROADCAST_SHORTADDR_DEVRXON (0xFFFD) –該信息將被發送到網絡中有接收器并處于IDLE(RXONWHENIDLE)狀態下的所有設備。也就是說,除了休眠模式設備的所有設備。
NWK_BROADCAST_SHORTADDR_DEVZCZR (0xFFFC) –該信息被發送到所有路由器(包括協調器)。
組地址
該模式用于應用層想發送一個數據包到一個設備組的時候。該地址模式被afAddrGroup設置這個組標志符。
用該特性之前,在網絡中,組不得不被定義[看ZStack API文檔中的] aps_AddGroup()
注意:組能與間接尋址一起結合使用。該目的地址在綁定表格中發現,可以作為點對點或一個組地址。也要注意廣播地址可以當作是組被提前設置,一個簡單的組尋址的特例,。
例子代碼對于一個設備添加它自己到一個組標志符1:
aps_Group_t group;
// Assign yourself to group 1
group.ID = 0x0001;
group.name[0] = 0; // This could be a human readable string
aps_AddGroup( SAMPLEAPP_ENDPOINT, &group );
重要設備地址
一個應用可以能想知道它自身和父節點的地址,用下面的函數可以得到設備的地址(被定義在ZStack API文檔中):
NLME_GetShortAddr() – 返回該設備的 16 位網絡地址
NLME_GetExtAddr() –返回該設備的64 位擴展地址.
用下面的函數可以得到該設備的父節點的地址(被定義在ZStack API文檔中)。注意該函數在協調器中不被涉及到,但是被設備父節點代替(MAC協調器):
NLME_GetCoordShortAddr() – returns this device’s parent’s 16 bit short address.
NLME_GetCoordExtAddr() – returns this device’s parent’s 64 bit extended address.
先介紹這兩個概念:節點和地址。其余的就改天繼續!
學習Z-Stack之7
--------------Z-Stack指導2
上節介紹了很大一部分Z-Stack的基礎知識,這里接著忽悠。雖然說的不是很專業也不是很通俗,但是我盡力了,希望有人能看明白!本人英文水平有限,翻譯的不好請諒解!
3、綁定
綁定是控制信息從一個應用層到另一個應用層流動的一種機制。在ZB06版本中,綁定機制在所有的設備中被執行。
綁定允許應用層發送信息不需要帶目的地址,APS層確定目的地址從他的綁定表格中,然后在信息前端加上這個目的地址或組。
注意:在ZB1.0版本中,所有綁定條目存儲在協調器中?,F在所有綁定條目存儲在發送數據的設備中。
3.1綁定一個綁定表格
有三種方式建立一個綁定表格:
ZDO 綁定請求 – 一個試運轉工具能告訴這個設備制作一個綁定報告。
ZDO 終端設備綁定請求 – 2設備能告訴協調器他們想建立綁定表格報告。該協調器將使協調并在這兩個設備上創建綁定表格條目
設備應用 – 在設備上的應用能建立或管理一個綁定表格 。
任何一個設備或應用能在網絡中發送一個ZDO信息到另一個設備()建立一個綁定報告。這是調用綁定幫助并且它將建立一個綁定條目為發送設備。
3.1.1 ZDO 綁定請求
通過調用函數ZDP_BindReq()發送一個綁定請求。第一個參數(dstAddr)是綁定的源地址的短地址。這之前應該確定允許綁定,在ZDConfig.h 文件中有參數[ZDO_BIND_UNBIND_REQUEST]允許綁定。能用同樣的參數調用函數ZDP_UnbindReq()移除綁定。
目標設備將調用函數ZDApp_BindRsp()或 ZDApp_UnbindRsp(),反饋綁定或移除綁定的響應,返回其操作狀態為ZDP_SUCCESS, ZDP_TABLE_FULL或ZDP_NOT_SUPPORTED.
3.1.2 ZDO 終端設備綁定請求
該機制是用一個按鈕按下或其他類似的動作來選擇設備在指定時間內被綁定。在規定時間內,該終端設備綁定請求信息被收集到協調器,并創建一個基于模式(profile) ID 和串(cluster) ID的規定的綁定表格條目。默認的終端設備綁定超時時間(APS_DEFAULT_MAXBINDING_TIME)為16S(定義在nwk_globals.h中),但是能被改變
發送綁定請求
在所有的應用例子中有一個處理鍵盤事件的函數[例如在TransmitApp.c文件中的TransmitApp_HandleKeys()函數]。在該函數中,調用了函數ZDApp_SendEndDeviceBindReq()[在ZDApp.c中],它將收集應用的終端設備的所有信息并調用函數ZDP_EndDeviceBindReq() [ZDProfile.c],發送一個綁定信息到協調器?;蛘?,在SampleLight 和 SampleSwitch例子中,直接調用ZDP_EndDeviceBindReq()函數就實現點亮/關閉燈的功能。
接收綁定請求
協調器將接收[ZDP_IncomingData() 在 ZDProfile.c]這些信息并分析處理[ZDO_ProcessEndDeviceBindReq() 在 ZDObject.c]這些信息并調用函數ZDApp_EndDeviceBindReqCB() [in ZDApp.c],它將調用ZDO_MatchEndDeviceBind() [ZDObject.c]處理這個請求
當協調器接收到2個匹配終端色后備的綁定請求時,它將啟動在綁定設備上創建源綁定條目的處理過程。該協調器有如下處理過程:
解除綁定
1. 發送一個ZDO解除綁定請求到第一個設備。終端設備綁定切換處理,所以解除綁定首先被發送到移除一個存在的綁定條目。
2. 等待ZDO解除綁定響應,如果響應狀態為ZDP_NO_ENTRY, 發送一個ZDO綁定請求,在源設備上制作一個綁定條目 。如果該響應為ZDP_SUCCESS, 為第一個設備繼續到move on to the cluster ID for the first device (the unbind removed the entry – toggle).
3. 等待ZDO綁定響應. When received, move on to the next cluster ID for the first device.
4. 當第一個設備完成時,對第二個設備做同樣的處理。
5. 當第二個設備完成時,發送ZDO 終端設備綁定響應信息到第一個和第二個設備
3.1.3設備應用綁定管理
在設備上其他進入綁定條目的方式是應用層管理綁定表格。
意思是說,應用層將調用下列函數進入和移除綁定表格條目:
bindAddEntry() –增加綁定表格條目
bindRemoveEntry() – 從綁定表格中移除條目
bindRemoveClusterIdFromList() – 從一個存在的綁定表格項目中移除一個串 ID 。
bindAddClusterIdToList()——向一個已經存在的綁定記錄中增加一個群ID
bindRemoveDev()——刪除所有地址引用的記錄
bindRemoveSrcDev()——刪除所有源地址引用的記錄
bindUpdateAddr()——將記錄更新為另一個地址
bindFindExisting()——查找一個綁定表記錄
bindIsClusterIdInList()——在表記錄中檢查一個已經存在的群ID
bindNumBoundTo()——擁有相同地址(源或者目的)的記錄的個數
bindNumEntries()——表中記錄的個數
bindCapacity()——最多允許的記錄個數
bindWriteNV()——在NV中更新表
3.2 配置源綁定
允許綁定源的編譯選項REFLECTOR在f8wConfig.cfg文件中。在文件f8wConfig.cfg,中查看這兩個綁定配置參數(NWK_MAX_BINDING_ENTRIES & MAX_BINDING_CLUSTER_IDS)。NWK_MAX_BINDING_ENTRIES綁定表格中最大的綁定實體數量參數;MAX_BINDING_CLUSTER_IDS 是在每個綁定實體中最大的串ID數量。
綁定表在靜態RAM中(未分配),因此綁定表中記錄的個數,每條記錄中群ID的個數都實際影響著使用RAM的數量。每一條綁定記錄是8字節多(MAX_BINDING_CLUSTER_IDS * 2字節)。除了綁定表使用的靜態RAM的數量,綁定配置項目也影響地址管理器中的記錄的個數。
4、路由
4.1 預覽
在MESH網絡中,為了使分布的節點間能夠很好的通信,路由是非常重要的一個環節。
在應用層上路由是完全透明的。一個簡單的應用數據發送到任意設備,下至協議棧,協議棧將負責發現一個路由路線。這個方式,應用層是不知道該操作在多跳網絡中完成的事實。
路由使ZB網絡具有“自動復原”的特性。如果一個無線連接斷了,路由功能將自動的發現一個新的路由路線,該路線是避開(繞過)壞了的那個連接節點。這就提高了無線網絡的可靠性,這也是ZB關鍵特點之一。
4.2 路由協議
ZB執行的路由協議是基于AODV(Ad hoc On demand Distance Vector)的路由協議。作為一個簡單的應用---傳感器網絡,ZB路由協議支持環境中的移動節點,連接失敗和丟包功能。
當一個路由器接收到一個點對點信息包時,從他的應用或者從其他設備,NWK層將繼續向前依照下面的進程。如果目的是路由器鄰節點(包括它的子設備)之一,該信息包將直接傳輸到目的設備。另外的就是,路由器將檢查它的路由表格,檢查相應的信息包目的條目。如果在路由表格中有一個活躍的路由路線到該目的設備,那么該信息包將被轉播到下一跳節點地址存儲依照路由條目。如果沒有活躍的條目發現,那么一個路由發現被啟動并且該信息被緩存直到該過程完成。
ZB終端設備路由
ZB終端設備不能執行任何路由功能。一個終端設備想發送一個信息包到任何設備都要向前到它的父設備,然后在由其父設備進行路由操作。類似的,任何設備想發送信息包到終端設備,都將發起一個路由發現操作,當然該操作都由終端設備的父設備響應。
注意:ZB地址分配方案使基于它的地址發起一個路由到任何目的成為可能。在Z-Sstack,這個機制被用于萬一正規的路由程序不能被啟動,作為一個自動退卻(一般情況是由于路由表格空間不夠)。
z-stack路由
在z-stack,執行的路由是已經被優化的路由存儲表格。一般情況,對于每一個目的設備路由表格條目是需要的。但是通過綜合攜帶父節點所有條目的特定父節點的終端設備的所有條目,沒有任何功能丟失的存儲已經被優化。
ZB路由器,包括協調器,執行如下路由功能 (i)路由發現和選擇 (ii) 路由維護(iii)
4.2.1路由發現和選擇
路由發現是網絡設備協作發現和建立路由的一個過程。一個路由操作總是針對某個目的,通過任何一個路由器啟動。該路由發現機制在源設備和目的設備間搜尋所有可能的路由并試圖選擇最好的路由路線。
? 路由選擇通過選擇最小消耗的路由路線。每個設備在連接到鄰節點幾乎保持不變的“連接消耗”。該連接消耗是接收信號的強度的一個典型功能。沿著路由路線加起所有的連接消耗,就是整個路由的“連接消耗”。路由算法試圖選擇這個路由最小的“路由消耗”。
路由請求
路由通過請求/響應信息包被發現。一個源設備為了一個目的地址,通過發送一個廣播路由請求(RREQ)信息到它的鄰設備請求一個路由。當一個節點接收到一個RREQ信息時,它將依次轉播這個RREQ信息。但是在做這個之前,它更新RREQ信息的消耗域,通過增加連接消耗為了最后的連接。這樣,RREQ信息將攜帶向前傳輸的所有的連接消耗。這個重復過程直到RREQ到達這個目的設備。RREQ的一些復制可能經過不同的路徑重復到達目的設備。該目的設備選擇最好的RREQ信息并發送一個路由答復(RREP)返回到源設備。
路由響應
RREP是沿著唯一的相反的路徑返回到最初的請求節點。
作為RREP信息傳播回源節點,中間的節點更新他們的路由表格,指出路由路線到目的設備。
一旦一個路由被創建,數據包能被發送。當一個節點丟失到它下一個節點的連通性時(發送數據包時,它不能接收一個MAC應答ACK),這個節點通過發送一個RERR到所有潛在的接收它RREP的節點,使該路由無效。在接收一個RREQ,RREP或RERR之上,這些節點都將更新他們的路由表格
4.2.2路由維護
MESH網絡提供路由維護和自動修復。中間節點保持沿著連接傳輸失效的路徑。如故一個連接被確定壞了,逆流的節點將啟動路由修復那些連接的所有路由路線。這些工作通過啟動路由重新發送被做,為了路由下一次數據包接收。如果路由重新發現不能啟動,或者由于某些原因失敗了,一個路由錯誤(RERR)信息被發送到這個數據包的源設備,然后重新啟動新的路由發現。任意方式都使得該路由得到重新自動建立。
4.2.3路由終結
為了建立路由,路由表格條目要被維護。如果一段時間沒有數據包沿著路由路線發送,該路由將被做終結記號。終止路由不是刪除直到空間需要時。因此沒有被刪除直到它完全需要時。自動路由終結時間能被配置“在f8wconfig.cfg"文件中”。設置ROUTE_EXPIRY_TIME參數為終結時間(秒)。設置0為了關閉路由終結。
4.3 表格存儲
路由功能需要路由器維護一些表格:
路由表格
路由發現表格
4.3.1路由表格
每一個路由器包括協調器都包含一個路由表。設備在路由表中保存數據包參與路由所需的信息。每一條路由表記錄都包含有目的地址,下一級節點和連接狀態。所有的數據包都通過相鄰的一級節點發送到目的地址。同樣,為了回收路由表空間,可以終止路由表中的那些已經無用的路徑記錄。
路由表的容量表明一個設備路由表擁有一個自由路由表記錄或者說它已經有一個與目標地址相關的路由表記錄。在文件“f8wConfig.cfg”文件中配置路由表的大小。將MAX_RTG_ENTRIES設置為表的大小(不能小于4)。
4.3.2路由發現表格
路由器設備致力于路徑發現,保持維護路徑發現表。這個表用來保存路徑發現過程中的臨時信息。這些記錄只在路徑發現操作期間存在。一旦某個記錄到期,則它可以被另一個路徑發現使用。這個值決定了在一個網絡中,可以同時并發執行的路徑發現的最大個數。這個可以在f8wConfig.cfg文件中配置MAX_ RREQ_ENTRIES。
4.4、路徑設置快速參考
設置路由表大小MAX_RTG_ENTRIES,這個值不能小于4 (f8wConfig.cfg文件)
設置路徑期滿時間ROUTE_EXPIRY_TIME,單位秒。設置為零則關閉路徑期滿(f8wConfig.cfg文件)
設置路徑發現表大小 MAX_RREQ_ENTRIES,網絡中可以同時執行的路徑發現操作的個數
學習ZStack之8
近段時間比較忙,幾乎都快荒廢了Z-Stack的學習了,把以前學的都快忘記了,這就是非專業技術的痛苦?。?!學習剛好有點眉目,突然意外中斷停下,當再一次學習的時候突然發現:以前學的都忘了8成了!郁悶??!今天真不知道從什么地方下手學習了,所以就針對最近客戶比較關心的問題做點介紹,這樣有針對性、有目的性的學習可能最適合現在的我了,不然從頭把以前那些所謂的筆記看一遍,可能今天晚上又沒了,指不定明晚以及后晚以及后后晚…都沒時間,不然老是看以前的筆記沒有進展就麻煩了!呵呵!
今天只解決1個問題:TI提供的例子程序的表演及功能介紹。
因為最近問這些的客戶比較多,特別又是剛入手的朋友,對Z-Stack非常迷糊的時期,如果能夠跑通幾個例子、看幾個演示,那么可以大大提高學習興趣;另外如果知道某個例子的大致功能及實現,那么在去看具體實現過程目的性就非常明確。
首先來看看TI究竟有哪些例子:
可以看出其例子是非常豐富的。
GenericApp,Location,SampleApp,SimpleApp,HomeAutomation,SerialApp,Transmit,
ZLOAD。這樣看來還是不少的。其中SampleApp例子已經在前面的學習中有所涉及,可以說前面的所有學習都是基于這個例子的,所以這里就不測試它了。Location是定位的測試例子,這里我的硬件是不夠的,所以也不做測試。其他我都做點測試,能成功的就成功,不能成功的就失敗,這個我也沒辦法,呵呵?。。。。。。?!
1、GenericApp
工程打開等我就不多說了,自己去找,如果連這些我都還說,那么我以前的東西是白學了。硬件連接中
當我用兩個節點分別燒寫入DB的協調器和路由器,從我的經驗看來,他們分別能建立網絡和加入網絡,但是從表象上幾乎看不見數傳現象,盡管我按了每個節點的按鍵,也僅僅是本節點的LED在改變。唯獨有點數傳感覺的是:按鍵右鍵對方有反應就是了,至于具體什么反映我覺得沒必要說明白,大家試試就知道了。
所以還決定看看程序來判斷這個例子的功能。
大約瀏覽了下,這個例子似乎還與設備的綁定有關系,因為在按建處理程序中發現:
if ( keys & HAL_KEY_SW_2 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate an End Device Bind Request for the mandatory endpoint
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = 0x0000; // Coordinator
ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),
GenericApp_epDesc.endPoint,
GENERICAPP_PROFID,
GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
FALSE );
}
很明顯這里按鍵2(右鍵)是發送綁定請求的命令。
if ( keys & HAL_KEY_SW_4 )
{
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
// Initiate a Match Deion Request (Service Discovery)
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,
GENERICAPP_PROFID,
GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,
FALSE );
}
顯然按鍵4(左)是初始化一個匹配描述符請求,也就是發現服務,或者叫自動尋求匹配設備。
這就不怪我按鍵有反映了!
而且在發送數據和接收數據處理函數發現:
void GenericApp_SendTheMessage( void )
{
char theMessageData[] = "Hello World";
if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
// Successfully requested to be sent.
}
else
{
// Error occurred in request to send.
}
}
居然發送的是一個字符串“Hello World”。
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
// "the" message
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
WPRINTSTR( pkt->cmd.Data );
#endif
break;
}
}
接收數據處理函數里居然要通過液晶顯示,本人這里的液晶暫時沒有移植過來,因為暫時還不具備那個實力,怪不得看不到發送數據的狀況!
這里本人就自作聰明的把以前SampleApp例子里面的一句話加過來了:
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
// "the" message
HalLedBlink( HAL_LED_4, 4, 50, (500) );
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
WPRINTSTR( pkt->cmd.Data );
#endif
break;
}
}
麼想到啊,這么一加居然就有反應了,o(∩_∩)o…!我不愧是天才的接班人?。?/span>
其實這里很簡單的了,就是接收到數據后閃爍4下燈,間隔0.5S。因為從:
if ( events & GENERICAPP_SEND_MSG_EVT )
{
// Send "the" message
GenericApp_SendTheMessage();
// Setup to send message again
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_SEND_MSG_EVT,
GENERICAPP_SEND_MSG_TIMEOUT );
// return unprocessed events
return (events ^ GENERICAPP_SEND_MSG_EVT);
}
這里可以看出,這個例子很明顯僅僅是個發送周期信息的例子。所以LED4就周期性的閃爍4下,當然是協調器發送,路由器閃爍,路由器發送,協調器閃爍。
但是這例子里體現了綁定的概念,應該說是從基本功能上很齊全的一個例子,而且在ZSTACK上實現無線網絡數傳,沒有任何多余的功能。所以該例子是一個典型的ZSTACK模板,也就是為用戶提供了一個通用模板可以通過這個建立自己的應用。關于如何在這個例子上建立、修改成自己的工程和應用項目詳細見文檔:
Create New Application For The CC2430DB_F8W-2005-0033_.pdf
這個例子就到此結束了,否則不然就很難把下面的弄玩了!
2、SimpleApp
這個例子我基本跑通了,可是鑒于時間的關系,沒有來得及打字了,所以就留到下一次了,時間真是如流水啊-------------------快!
學習Z-Stack之9
接到昨天的繼續忽悠,話說:
2、SimpleApp
“這個例子我基本跑通了,可是鑒于時間的關系,沒有來得及打字了,所以就留到下一次了,時間真是如流水啊-------------------快!….”
這個例子里面有兩個演示:一個是燈與開關的控制實驗,一個溫度傳感器實驗。咱一個個來,不忙。
燈與開關實驗
在這個例子中燈對應的工程名字為:SimpleControllerDB;開關對應:SimpleSwitchDB。嚴重需要注意的地方,這里選用的是DB。因為從從零開始學習Z-Stack之1上可以看到DB與EB的區別,而這里用DB的硬件就足以應付。
編譯下載我就不繼續羅嗦了。
咱關心的幾個問題不外乎就是表演過程和表演結果,以及初步看看為什么會有這樣的結果產生,當然就得從程序上簡單了解下。
首先打開Controller(也就是燈設備)的電源,那么LED2就會不停的閃爍,這個時候是設備正在初始化,讓您選擇設備以哪種類型啟動,從程序可以看出:
if ( keys & HAL_KEY_SW_1 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// Key 1 starts device as a coordinator
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );
if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )
{
logicalType = ZG_DEVICETYPE_COORDINATOR;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
}
// Do more configuration if necessary and then restart device with auto-start bit set
// write endpoint to simple desc...dont pass it in start req..then reset
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();
}
如果按下S1(UP),那么作為協調器啟動。
if ( keys & HAL_KEY_SW_2 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// Key 2 starts device as a router
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType );
if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )
{
logicalType = ZG_DEVICETYPE_ROUTER;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
}
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();
}
如果按下S2(RIGHT),設備作為路由器啟動。
這里由于是第一個啟動的設備,所以作為協調器啟動,就按下UP,此時燈會有狀態變化,最終結果是:LED2常亮,標示建立網絡成功。如果您還有另外的燈設備就可以按下RIGHT讓他們都作為路由器啟動,由于本人這里只有兩個節點,所以就只能有個協調器。
現在就來啟動開關設備的電源,同樣LED2會閃爍讓您選擇設備,但是在ZIGBEE中除了協調器和路由器就剩下終端設備了,所以開關就只能作為終端被啟動,但是也需要通過按鍵來控制,從程序中可以看出:
if ( keys & HAL_KEY_SW_1 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// The Switch device is always an end-device
logicalType = ZG_DEVICETYPE_ENDDEVICE;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
// Do more configuration if necessary and then restart device with auto-start bit set
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();
}
else
{
// Initiate a binding with null destination
zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID, NULL);
}
}
if ( keys & HAL_KEY_SW_2 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logical mode.
// The Switch device is always an end-device
logicalType = ZG_DEVICETYPE_ENDDEVICE;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
zb_SystemReset();
}
else
{
// Send the command to toggle light
zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,
(uint8 *)NULL, myAppSeqNumber, 0, 0 );
}
}
無論是按下S1還是S2(UP或者RIGHT),開關設備均作為終端設備啟動。
啟動之后呢,燈的狀態同樣會發生一些變化,最終結果是:LED2快速閃爍,表明此時開關已經成功加入剛才燈設備建立的那個網絡了。
那么接下來就要看這個例子的核心部分----------綁定!
首先按下燈設備(這里為協調器,如果有路由器也可以)的UP,那么程序中調用了:
zb_AllowBind( myAllowBindTimeout );
函數,允許綁定,這個允許的時間據說只有10S,當然這個時間是可以調整的,因為這里的參數為:static uint8 myAllowBindTimeout = 10;至于這個時間怎么計算的就需要到某個函數zb_AllowBind里去分析了。zb_AllowBind規定這個參數為1~64,如果為0,表示為假,就是不允許綁定的意思。如果大于64的話,就一直為真,就是一直都允許綁定。好像似乎是這個意思。至于這個10S是怎么制定的呢,在這個函數內部調用了:
osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000);
因為osal_start_timerEx定時函數最小單位為mS,所以*1000就表示S了。
而在SAPI_ProcessEvent事件處理函數中ZB_ALLOW_BIND_TIMER事件處理如下:
if ( events & ZB_ALLOW_BIND_TIMER )
{
afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
return (events ^ ZB_ALLOW_BIND_TIMER);
}
也就是定時取消綁定狀態?。?!
如果有人看著這些看不明白,那就把這個例子多看幾遍,多跑幾遍。一般如果您每天花費4個小時看這個例子,那么只需要一周事件,我想到時比我還精通明白的!
所以在10S之內,開關必須發起綁定,此時同樣按下開關設備的UP,那么開關設備就調用了函數:zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID, NULL);發送一個綁定請求去尋求綁定設備。
一個設備允許綁定,一個設備發起綁定請求,兩個是您情我愿的,所以就一拍即合,相當的登對!當然沒有這么簡單的哈,就如同兩個人談戀愛,至少也需要是一男一女啊,兩個都是男或女那就太不正常了,ZIGBEE是個國際化的標準,當然不能有這種變態行為,所以也需要兩個命令的屬性是相反的,就例如這里的控制燈開關的命令,對于燈來說這個命令為輸入,而對于開關來說這個命令是輸出。所以一入一出剛好就登對。呵呵!!
綁定成功的表象是:開關設備的LED1快速閃爍。
void zb_AllowBindConfirm( uint16 source )
{
// Flash LED
HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK );
}
綁定成功了就可以發送燈控制命令了。按下RIGHT,調用了函數:
zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,
(uint8 *)NULL, myAppSeqNumber, 0, 0 );
可以看出發送了一個數據請求,顯然是廣播發送的,而命令為切換燈狀態的TOGGLE_LIGHT_CMD_ID。當燈收到這命令,就有處理函數了:
void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8 *pData )
{
if (command == TOGGLE_LIGHT_CMD_ID)
{
// Received application command to toggle the LED
HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE);
}
}
所以LED1顯示狀態發生改變。
此時這個例子已經接近尾聲了,因為綁定成功開關能夠控制燈了,但是既然可以綁定那么也可以接觸綁定的,如果按下開關的DOWN,那么同樣調用了發送綁定請求函數:
zb_BindDevice(FALSE, TOGGLE_LIGHT_CMD_ID, NULL);
只是這里第一個參數為FALSE,所以就能解除綁定。如果某個開關被解除了綁定,那么此時就不能控制燈了。
在這個例子最后做個小結------綁定的好處。
綁定了之后,發送數據或者命令,就不需要設備的地址,因為這個命令只能在建立綁定間的設備中傳輸。------------絕對是我的理解!
還有,一個開關可以綁定多個燈,同樣,一個燈可以同時與多個開關發生綁定。這個不代表本人觀點,本人強力反對腳踏N只船?。。。。。?/span>
現在來簡單分析下傳感器的例子,由于前面燈的例子說的比較多,這里我就說少點。
中心節點對應SimpleCollectorEB ,傳感器節點對應SimpleSensorEB。這里用到了EB,主要是因為DB沒有串口硬件,而EB有,這個例子需要用到串口。
傳感器的例子效果是:協調器可以收集傳感器節點的溫度信息并通過串口傳輸到PC機,如下圖所示:
可以看到能夠看到節點的溫度和電源電壓。
具體實現與燈的例子稍區別,但是本質的原理是一樣的,先選擇設備類型,然后建立綁定,最后收集信息。這里建立綁定的區別在于,只要中心節點允許綁定(與前面操作一樣),然后傳感器節點是自動發送綁定請求的:
osal_start_timerEx( sapi_TaskID, MY_FIND_COLLECTOR_EVT, myBindRetryDelay );
定時去產生發MY_FIND_COLLECTOR_EVT事件:
if ( event & MY_FIND_COLLECTOR_EVT )
{
// Find and bind to a collector device
zb_BindDevice( TRUE, SENSOR_REPORT_CMD_ID, (uint8 *)NULL );
}
這個事件就是發送綁定請求的。
至于綁定后的現象與前面一樣了。
最后通過串口調試工具就能看到前面那個圖的效果了?。。。。。。。。。。。?!
這里的溫度為42,這個肯定不可能的,不然我就被蒸發掉了哈!因為采用的是芯片內部集成的溫度傳感器,這個傳感器做實驗還可以,因為可以看見溫度的變化,但是其準確性是在不敢恭維。TI也是的,做了溫度傳感器,還超級不準確,還不如不做,只有還可以降低硬件成本,幾乎沒有任何使用價值?。?!