通过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. }