ZigBee入門小實驗——無線點燈
寫在前面:無線點燈實驗不涉及協議棧,只是對Basic RF的應用,但是其中關於數據收發的思想和協議棧類似,可以借鑒。這個代碼和實驗過程都是參考某教程的,然后有加上自己的理解......歡迎糾錯(*^__^*)
一、設備
兩個ZigBee模塊
一個方口USB線(這個只是供電用,要看自己模塊用什么接口,不一定是方口的,用電池也行)
一個編譯器
二、幾個名詞解釋
CCM -Counter with CBC-MAC(mode of operation) 就知道和加密有關,具體不明白...有人能解釋下嗎?
HAL -Hardware Abstraction Layer (硬件抽象層)
PAN -Personal Area Network (個人局域網)
RF -Radio Frequency (射頻)
RSSI -Received Signal Strength Indicator (接收信號強度指示)
三、關於Basic RF
- 在介紹Basic RF之前先看一下該實驗例程的大體結構,圖見下方
①Hardware layer 硬件層
實現數據傳輸的基礎
②Hardware Abstraction layer 硬件抽象層
提供接口以訪問TIMER,GPIO,UART,ADC等,這些接口都通過函數實現。
③Basic RF
為雙向無線通信提供一種簡單的協議
④Application layer 用戶應用層
它相當於一個接口,方便用戶使用Basic RF層和HAL,就是說在Application層就可以使用封裝好的Basic RF和HAL函數
2. Basic RF layer 簡介
Basic RF 由TI公司提供,包含IEEE 802.15.4標准的數據包收發功能但不使用協議棧,僅讓兩個結點進行簡單通信。
Basic RF layer 為雙向無線通信提供了一個簡單的協議,通過這個協議能夠進行數據的發送和接收
四、Basic RF 工作過程分析
Basic RF的工作過程分為三個部分:啟動、發射、接收
啟動:
- 確保外圍器件沒有問題
2. 定義一個新的結構體類型,變量名為basicRfCfg_t,打開basic_rf.h可以找到該結構體。
typedef struct { uint16 myAddr; //16位的短地址,就是結點的地址 uint16 panId; //結點的PAN ID uint8 channel; //PF通道(必須在11-26之間) uint8 ackRequest; //目標確認就置true #ifdef SECURITY_CCM //是否加密,預定義里取消了加密 uint8* securityKey; uint8* securityNonce; #endif } basicRfCfg_t;
3. 調用basicRfInit()函數進行協議的初始化,在basic_rf.h中可以找到函數聲明
Unit8 basicRfInit(basicRfCfg_t* pRfConfig);
函數功能:對basicRfCfg_t進行初始化,設置模塊的傳輸通道,短地址,PAN ID
發送:
1. 創建一個buffer,把payload放入其中。Payload最大為103個字節
2. 調用basicRfSendPacket()函數發送,並查看其返回值
在basic_rf.h中可以找到函數聲明
uint8 basicRfSendPacket(uint16 destAddr, uint8* pPayload, uint8 length);
destAddr 目的短地址
pPayload 指向發送緩沖區的指針
length 發送數據長度
函數功能:給目的短地址發送指定長度的數據,發送成功返回SUCCESS,失敗返回FAILED。
接收:
- 上層通過basicRfPacketIsReady()函數來檢查是否收到一個新數據包,在basic_rf.h中可以找到函數聲明
uint8 basicRfPacketIsReady(void);
函數功能:檢查模塊是否已經可以接收下一個數據,如果准備好返回TRUE
2. 調用basicRfReceive()函數,把收到的數據復制到buffer中,在basic_rf.h中可以找到該函數聲明
uint8 basicRfReceive(uint8* pRxData, uint8 len, int16* pRssi);
函數功能:接收來自Basic RF層的數據包,並為所接收的數據和RSSI值配緩沖區
據說只要能看懂啟動、發送、接收就基本上能使用這個無線模塊了......加油~
五、Light_switch.c 代碼詳解
這個代碼其實是對上面那些函數的應用
主要分為三個部分:主函數,按鍵函數,點燈函數
先看主函數吧
1 void main(void) 2 { 3 //不設置模塊的模式,代碼本意是通過這個來選擇這個模塊是按鍵還是點燈模塊 4 //但是因為代碼被改過了,其實這個已經沒有用啦 5 uint8 appMode = NONE; 6 7 // Config basicRF 8 //這里的basicRfConfig就是之前提到的basicRFCfg_t,只是重新定義了下 9 //以下是給各成員賦值 10 basicRfConfig.panId = PAN_ID; //設置panId的值 PAN_ID是自己定義的一個16位地址,程序開頭可以改 11 basicRfConfig.channel = RF_CHANNEL; //通道值,RF_CHANNEL也是自己定義的,開頭可以修改 12 basicRfConfig.ackRequest = TRUE; //目標確認為TRUE 這個應該不用改吧... 13 #ifdef SECURITY_CCM //加密的東西,暫時忽略 14 basicRfConfig.securityKey = key; //| 15 #endif //| 16 17 // Initalise board peripherals 18 //初始化外圍設備 19 halBoardInit(); //這個我暫時不知道是什么,以后補上,求解答 20 halJoystickInit(); //游戲搖桿,據說國外用比較多...我確定這個程序不需要這個... 21 22 // Initalise hal_rf 23 //硬件抽象層的RF進行初始化 24 if(halRfInit()==FAILED) { 25 HAL_ASSERT(FALSE); 26 } 27 28 // Indicate that device is powered 29 //把兩個燈都打開,表示下通電啦 30 halLedSet(2); //關閉LED2 31 halLedSet(1); //打開LED1 32 33 /************Select one and shield to another***********by boo*/ 34 //這個端口怎么改? hal_board.h里面的 35 //HAL_BOARD_IO_BTN_1_PORT 和 HAL_BOARD_IO_BTN_1_PIN 改按鍵端口 36 //HAL_BOARD_IO_LED_1_PORT 和 HAL_BOARD_IO_LED_1_PIN 改燈的端口 37 //問我怎么找出來的?一直go 頭 definition吧~ 笑... 38 appSwitch(); //節點為按鍵S1 P0_0 39 //appLight(); //節點為指示燈LED1 P1_0 40 41 // Role is undefined. This code should not be reached 42 HAL_ASSERT(FALSE); 43 }
主函數其實就三步
①啟動(初始化)Basic RF
②初始化其余外圍設備(按鍵、燈之類的)
③選擇是按鍵還是燈的函數(手動選擇啦,就是把另一行函數注釋掉!)
然后看下按鍵函數:
1 static void appSwitch() 2 { 3 halLcdWriteLine(HAL_LCD_LINE_1, " W e B e e ");//液晶 4 halLcdWriteLine(HAL_LCD_LINE_2, " ZigBee CC2530 "); //屏顯 5 halLcdWriteLine(HAL_LCD_LINE_4, " SWITCH "); //示的 6 //內容 7 #ifdef ASSY_EXP4618_CC2420 //, 8 halLcdClearLine(1); //忽略 9 halLcdWriteSymbol(HAL_LCD_SYMBOL_TX, 1); //! 10 #endif //! 11 12 13 // Initialize BasicRF 14 //初始化Basic RF 為什么又初始化?? 15 //其實就是剛才main函數里部分沒初始化的繼續初始化下 16 //因為點燈和按鍵的部分要求不一樣,應該是這樣的... 17 basicRfConfig.myAddr = SWITCH_ADDR; //確實,點燈和按鍵設置的地址怎么能一樣?! 18 if(basicRfInit(&basicRfConfig)==FAILED) { 19 HAL_ASSERT(FALSE); 20 } 21 22 //把要發送的數據寫到buffer里面去,這里buffer就1位 23 //LIGHT_TOGGLE_CMD是自己在上面定義的,0 24 pTxData[0] = LIGHT_TOGGLE_CMD; 25 26 // Keep Receiver off when not needed to save power 27 //把模塊的接收部分關掉,可以省點電! 28 basicRfReceiveOff(); 29 30 // Main loop 31 //以上都算是設初值吧,這里進去就出不來啦,死循環! 32 while (TRUE) { 33 //if( halJoystickPushed() )**********************by boo 34 if(halButtonPushed()==HAL_BUTTON_1)//**************by boo檢查按鍵S1是否按下! 35 { 36 //按下就發送數據(發給誰, 發的數據, 數據長度) 37 //這個應該很重要吧! 38 basicRfSendPacket(LIGHT_ADDR, pTxData, APP_PAYLOAD_LENGTH); 39 40 // Put MCU to sleep. It will wake up on joystick interrupt 41 //搖桿,忽略!!! 42 halIntOff(); 43 halMcuSetLowPowerMode(HAL_MCU_LPM_3); // Will turn on global 44 // interrupt enable 45 halIntOn(); 46 47 } 48 } 49 }
按鍵也是三步......
①初始化Basic RF的地址部分
②初始化條件觸發后要發送的數據,就是把要發送的數據先准備好,等要發送了就直接發出去就可以了,不需要重復賦值啦
③循環檢查按鍵是否按下,按下就發數據出去
最后還剩點燈啦,這個和按鍵差不多的呢
1 static void appLight() 2 { 3 4 halLcdWriteLine(HAL_LCD_LINE_1, " W e B e e "); //顯示屏,忽略 5 halLcdWriteLine(HAL_LCD_LINE_2, " ZigBee CC2530 "); //| 6 halLcdWriteLine(HAL_LCD_LINE_4, " LIGHT "); //| 7 //| 8 #ifdef ASSY_EXP4618_CC2420 //| 9 halLcdClearLine(1); //| 10 halLcdWriteSymbol(HAL_LCD_SYMBOL_RX, 1); //| 11 #endif //| 12 13 // Initialize BasicRF 14 //Basic RF設置地址 15 basicRfConfig.myAddr = LIGHT_ADDR; 16 if(basicRfInit(&basicRfConfig)==FAILED) { 17 HAL_ASSERT(FALSE); 18 } 19 basicRfReceiveOn(); //打開無線接收功能 20 21 // Main loop 22 //死循環 23 while (TRUE) { 24 while(!basicRfPacketIsReady()); //接收到東西了再繼續,不然循環 25 26 if(basicRfReceive(pRxData, APP_PAYLOAD_LENGTH, NULL)>0) { //判斷是否有接收到有效數據 27 if(pRxData[0] == LIGHT_TOGGLE_CMD) { //如果接收到剛才發的信號 28 halLedToggle(1); //改變燈的狀態(開變關,關變開) 29 } 30 } 31 } 32 }
點燈也是三步,和按鍵差不多啦~
①初始化Basic RF的地址部分
②打開無線接收功能
③循環,收到東西就改變燈狀態