ZIGBEEZ通過協議棧點對點通訊流程
通過ZigBee2007 的協議棧 Z-Stack-CC2530-2.3.0。
一.實現一個無線資料通訊時的一般步驟
1、組網:呼叫協議棧的組網函式、加入網路函式,實現網路的建立與節點的加入。
2、傳送:傳送節點呼叫協議棧的無線資料傳送函式,實現無線資料傳送。
3、接收:接收節點呼叫協議棧的無線資料接收函式,實現無線資料接收。 看起來是不是很簡單呢,是不是有動手試試的衝動。具體的例程講解在這裡就不說先了,在接下來的教程裡面會詳細地和大家一起討論 ZigBee 協議棧架構中每個層所包含的內容和功能及 Z-stack 的軟體架構。
二:關鍵字
CCM - Counter with CBC-MAC (mode of operation)
HAL - Hardware Abstraction Layer (硬體抽象層)
PAN - Personal Area Network (個人區域網)
RF - Radio Frequency (射頻)
RSSI - Received Signal Strength Indicator (接收訊號強度指示)
三:協議的結構
-Hardware layer
放在最底,實現資料傳輸的基礎。
-Hardware Abstraction layer
提供了一種介面來訪問 TIMER,GPIO,UART,ADC 等。這些介面都通過相應的函式進行實現。
-Basic RF layer
為雙向無線傳輸提供一種簡單的協議。
-Application layer
使用者應用層,它相當於使用者使用 Basic RF 層和 HAL 的介面,也就是說我們通過在 Application layer 就可以使用到封裝好的 Basic RF 和 HAL 的函式。
四:Basic RF layer 簡介:
Basic RF 由 TI 公司提供,它包含了 IEEE 802.15.4 標準的資料包的收發功能但並沒有使用到協議棧,它僅僅是是讓兩個結點進行簡單的通訊,也就是說Basic RF 僅僅是包含著 IEEE 802.15.4 標準的一小部分而已。其主要特點有:
1、不會自動加入協議、也不會自動掃描其他節點也沒有組網指示燈(LED3)。
2、沒有協議棧裡面所說的協調器、路由器或者終端的區分,節點的地位都 是相等的。
3、沒有自動重發的功能。
-要理解掌握 Basic RF ,通過這個協議能夠進行資料的傳送和接收。
五:Basic RF 的工作過程:啟動、發射、接收 。
1、啟動 :
/*1、建立一個 basicRfCfg_t 的資料結構,並初始化其中的成員,在 basic_rf.h 程式碼中可以找到 */
typedef struct {
uint16 myAddr; //16 位的短地址(就是節點的地址)
uint16 panId; //節點的 PAN ID
uint8 channel; //RF 通道(必須在 11-26 之間)
uint8 ackRequest; //目標確認就置 true
#ifdef SECURITY_CCM //是否加密,預定義裡取消了加密
uint8* securityKey;
uint8* securityNonce;
#endif
} basicRfCfg_t;
/*2.呼叫 basicRfInit()函式進行協議的初始化,在 basic_rf.c 程式碼中可以找到 */
uint8 basicRfInit(basicRfCfg_t* pRfConfig) ;
/*函式功能:對 Basic RF 的資料結構初始化,設定模組的傳輸通道,短地址,PAD ID。*/
2、傳送
/*
1. 建立一個 buffer,把 payload 放入其中。Payload 最大為 103 個位元組.
2. 呼叫 basicRfSendPacket()函式傳送,並檢視其返回值 。
在 basic_rf.c 中可以找到 :
*/
uint8 basicRfSendPacket(uint16 destAddr, uint8* pPayload, uint8 length) ;
/*
destAddr 目的短地址
pPayload 指向傳送緩衝區的指標
length 傳送資料長度
函式功能:給目的短地址傳送指定長度的資料,傳送成功剛返回 SUCCESS, 失敗則返回 FAILED
*/
3、接收
/*
1、 上層通過 basicRfPacketIsReady()函式來檢查是否收到一個 新資料包 。
在 basic_rf.c 中可以找到 :
*/
uint8 basicRfPacketIsReady(void);
//函式功能:檢查模組是否已經可以接收下一個資料,如果準備好剛返回 TRUE 。
/*
2、 呼叫 basicRfReceive()函式,把收到的資料複製到 buffer 中。
程式碼可以在 basic_rf.c 中可以找到 :
*/
uint8 basicRfReceive(uint8* pRxData, uint8 len, int16* pRssi) ;
//函式功能:接收來自 Basic RF 層的資料包,併為所接收的資料和 RSSI 值 配緩衝區。
使用 Basic RF 實現無線傳輸只要學會使用這些函式就可以了。
六:例程講解
light_switch.c 程式碼詳解:
無論你看哪個實驗的程式碼,首先要找的就是 main 函式。從 main 函式開始:
(部分已經遮蔽的程式碼並未貼出,詳細的程式碼請看開啟工程)
1. void main(void)
2. {
3. uint8 appMode = NONE; //不設定模組的模式
4. // Config basicRF
basicRfConfig.panId = PAN_ID; //上面講的 Basic RF 的啟動中的
5. basicRfConfig.channel = RF_CHANNEL; //初始化 basicRfCfg_t
6. basicRfConfig.ackRequest = TRUE; //結構體的成員。
7.
8. #ifdef SECURITY_CCM //金鑰安全通訊,本例程不加密
9. basicRfConfig.securityKey = key;
10. #endif
11.
12. // Initalise board peripherals 初始化外圍裝置
13. halBoardInit();
14. halJoystickInit();
15.
16. // Initalise hal_rf 硬體抽象層的 rf 進行初始化
17. if(halRfInit()= =FAILED)
18. {
19. HAL_ASSERT(FALSE);
20. }
21. /***********根據 WeBee 學習底板配置**********/
22. halLedClear(2); // 關 LED2
23. halLedClear(1); // 關 LED1
24.
25. /******選擇性下載程式,傳送模組和接收模組******/
26. appSwitch(); //節點為按鍵 S1 P0_0
27. appLight(); //節點為指示燈 LED1 P1_0
28. // Role is undefined. This code should not be reached
29. HAL_ASSERT(FALSE);
30. }
/*第 22~23 行:關閉 WeBee 底板的 LED2 和 LED1。halLedSet(x)置 1 是使燈 點亮,halLedClear(x)是使燈熄滅。 第 26~27 行:選擇其中的一行,並把另外一行遮蔽掉;這兩行重要啦,一個是實現發射按鍵資訊的功能,另一個是接收按鍵資訊並改變 LED 狀態的功能。分別為 Basic RF 發射和接收。不同模組在 燒寫程式時選擇不同功能。
注意:程式會在 appSwitch(); 或者 appLight();裡面迴圈或者等待,不會執行到第 29 行。
*/
//接下來看看 appSwitch()函式,它是如何實現資料傳送的呢?
1. static void appSwitch()
2. {
3. #ifdef ASSY_EXP4618_CC2420 //液晶模組的定義,我們不用管他
4. halLcdClearLine(1);
5. halLcdWriteSymbol(HAL_LCD_SYMBOL_TX, 1);
6. #endif
7. // Initialize BasicRF 8~11 Basic RF 啟動中的初始化
8. basicRfConfig.myAddr = SWITCH_ADDR;
9. if(basicRfInit(&basicRfConfig)==FAILED){
10. HAL_ASSERT(FALSE);
11. }
12. pTxData[0] = LIGHT_TOGGLE_CMD;
13. /* Basic RF 發射第 1 步,把要發射的資料或者命令放入一個數據 buffer,
此處把燈狀態改變的命令 LIGHT_TOGGLE_CMD 放到 pTxData 中。*/
14. basicRfReceiveOff(); //接收遮蔽掉以降低功耗
15. // Main loop 程式進入死迴圈
16. while (TRUE)
17. {
/*halButtonPushed()是 halButton.c 裡面的,它的功能是:按鍵 S1
有被按動時,就回返回true */
18. if(halButtonPushed()==HAL_BUTTON_1) //判斷按鍵 S1 被按下
19. {
20. basicRfSendPacket(LIGHT_ADDR,pTxData,APP_PAYLOAD_LENGTH);
21. //Basic RF 發射第 2 步,傳送資料
22. halIntOff();
23. halMcuSetLowPowerMode(HAL_MCU_LPM_3); // Will turn on global
24. // interrupt enable 使能中斷
25. halIntOn();
26. }
27. }
28. }
//傳送的 appSwitch()講解完畢,接下來就到我們的接收 appLight()函數了
1. static void appLight()
2. {
3. /*************************************************
4. halLcdWriteLine(HAL_LCD_LINE_1, “Light”);
5. halLcdWriteLine(HAL_LCD_LINE_2, “Ready”);
6. ***************************************************/
7. #ifdef ASSY_EXP4618_CC2420 // LCD 內容
8. halLcdClearLine(1);
9. halLcdWriteSymbol(HAL_LCD_SYMBOL_RX, 1);
10. #endif
11. // Initialize BasicRF Basic RF 啟動中的初始化
12. basicRfConfig.myAddr = LIGHT_ADDR;
13. if(basicRfInit(&basicRfConfig)==FAILED) {
14. HAL_ASSERT(FALSE);
15. }
/*開啟無線接收功能,呼叫這個函式後模組一直會接收,除非再呼叫 basicRfReceiveOff()使它關閉接收*/
16. basicRfReceiveOn();
17. // Main loop 程式開始進行不斷掃描的迴圈
18. while (TRUE)
19. {
20. while(!basicRfPacketIsReady()); //檢查是否接收上層資料
21. if(basicRfReceive(pRxData, APP_PAYLOAD_LENGTH, NULL)>0) { //判斷否接收到有資料
22. if(pRxData[0] == LIGHT_TOGGLE_CMD)
23. {
24. halLedToggle(1); //改變 Led1 的狀態
25. }
26. }
27. }
28. }