Download presentation
Presentation is loading. Please wait.
1
任务十 基于Z-Stack的点对点通信
2
目 录 一、实训目的 二、实训内容 三、实训原理 四、实训步骤
3
实训目的 通过实训,掌握在IAR环境下Z-Stack的使用,了解Z-Stack的基本架构,学会在IAR环境下Z-Stack的应用层的开发,能基于Z-Stack实现两个ZigBee节点进行点对点通信。
4
目 录 一、实训目的 二、实训内容 三、实训原理 四、实训步骤
5
实训内容 采用两个ZigBee模块,一个作为协调器(ZigBee节点1),另一个作为终端节点(ZigBee节点2),当ZigBee节点2发送“NEWLab”六个字符,ZigBee节点1收到数据后,对接收到的数据进行判断,如果收到的数据正确,则ZigBee节点1上LED2会闪烁,否则点亮LED2。数据传输模型如图10.1所示。
6
实训内容 ZigBee节点2 终端节点或路由器 ZigBee节点1 协调器 ZigBee无线网络 NEWLab 图10.1 数据传输模型
7
目 录 一、实训目的 二、实训内容 三、实训原理 四、实训步骤
8
实训原理 TI公司推出CC253x射频芯片的同时,还向用户提供了ZigBee的Z-Stack协议栈,这是经过ZigBee联盟认可,并被全球很多企业广泛采用的一种商业级协议栈。Z-Stack协议栈中包括一个小型操作系统(抽象层OSAL),其负责系统的调度,操作系统的大部分代码被封装在库代码中,用户查看不到的。对于用户来说,只能使用API来调用相关库函数。IAR公司开发的IAR Embedded Workbench for 8051软件可以作为Z-Stack协议栈的集成开发环境。 Z-Stack协议栈结构
9
实训原理 Z-Stack协议栈由物理层(PHY)、介质访问控制层(MAC)、网络层(NWK)和应用层(APS)组成,如图10.2所示。其中应用层包括应用程序支持子层、应用程序框架层和ZDO设备对象。在协议栈中,上层实现的功能对下层来说是不知道的,上层可以调用下层提供的函数来实现某些功能。
10
实训原理 图10.2 Z-Stack协议栈的结构
11
实训原理 1. 物理层(PHY) 物理层负责将数据通过发射天线发送出去,以及从天线上接收数据。 2. 介质访问控制层(MAC)
介质访问控制层提供点对点通信的数据确认,以及一些用于网络发现和网络形成的命令,但是介质访问控制层不支持多跳、网型网络等拓扑结构。
12
实训原理 3. 网络层(NWK) 网络层主要是对网型网络提供支持,如在全网范围内发送广播包,为单播数据包选择路由,确保数据包能够可靠地从一个节点发送到另一个节点。此外,网络层还具有安全特性,用户可以自行选择所需要的安全策略。 4. 应用层(APS) (1)应用程序支持子层主要提供一些API函数供用户调用,此外,绑定表也是存储在应用程序支持子层。
13
实训原理 (2)应用程序框架中包括了最多240个应用程序对象,每个应用程序对象运行在不同的端口上。因此,端口的作用是区分不同的应用程序对象。
(3)ZDO设备对象是运行在端口0的应用程序,对整个ZigBee设备的配置和管理,用户应用程序可以通过端口0与ZigBee协议栈的应用程序支持子层、网络层进行通信,从而实现对这些层的初始化工作。 Z-Stack协议栈基本概念
14
实训原理 1. 设备类型 在ZigBee网络中存在三种设备类型:协调器(Coordinator)、路由器(Router)和终端设备(End-Device)。ZigBee网络中只能有一个协调器,可以有多个路由器和多个终端设备。如图10.3所示,黑色节点为协调器,灰色节点路由器,白色节点为终端设备。
15
实训原理 图10.3 ZigBee网络示意图
16
实训原理 (1)协调器的作用 ① 协调器是每个独立的Zigbee网络中的核心设备,也是唯一一个协调器设备,负责选择一个信道和一个网络ID(也称PAN ID),启动整个ZigBee网络。 ② 协调器也可以用来协助建立网络中安全层和应用层的绑定。 ③ 协调器的主要角色是负责建立和配置网络。由于Zigbee网络本身的分布特性,一旦Zigbee网络建立完成后,整个网络的操作就不再依赖协调器是否存在,与普通的路由器没有什么区别。
17
实训原理 (2)路由器的作用 ① 允许其他设备加入网络,多跳路由协助由终端设备通信。
② 一般情况,路由器需要一直处于工作状态,必须使用电力电源供电。但是当使用树型网络拓扑结构时,允许路由器间隔一定的周期操作一次,则路由器可以使用电池供电。 (3)终端设备(终端节点)的作用 ① 终端设备是Zigbee实现低功耗的核心,它的入网过程和路由器是一样的。终端设备没有维持网络结构的职责,所以它并不是时刻都处在接收状态的,大部分情况下它都将处于IDLE或者低功耗休眠模式。因此,它可以由电池供电。
18
实训原理 ② 终端设备会定时同自己的父节点进行通信,询问是否有发给自己的消息,这个过程被形象地成为“心跳”。心跳周期也是在f8wConfig.cfg里配置的:-DPOLL_RATE=1000。Zstack默认的心跳周期为1000ms,终端节点每1s会同自己的父节点进行一次通信,处理属于自己的信息。因此,终端的无线传输是有一定延迟的。对于终端节点来说,它在网络中的生命是依赖于自己的父节点的,当终端的父节点由于某种原因失效时,终端能够“感知”到脱离网络,并开始搜索周围NETWORK ID相同的路由器或协调器,重新加入网络,并将该设备认作为自己新的父节点,保证自身无线数据收发的正常进行。
19
实训原理 2. 信道 ZigBee采用的是免执照的工业科学医疗(ISM)频段,所以ZigBee使用了3个频段,分别为:868MHz(欧洲)、915MHz(美国)、2.4GHz(全球)。 因此,ZigBee共定义了27个物理信道。其中,868MHz频段定义了一个信道;915MHz频段附近定义了10个信道,信道间隔为2MHz;2.4GHz频段定义了16个信道,信道间隔为5MHz。具体信道分配如表10.1所示。
20
实训原理 表10.1 ZigBee信道分配 信道编号 中心频率(MHz) 信道间隔(MHz) 频率上限(MHz) 频率下限(MHz) k=0 868.3 868.6 868.0 k =1,2,3……10 906+2×( k-1 ) 2 928.0 902.0 k =11,12,13……26 2401+5×( k-11 ) 5 2483.5 2400.0 理论上,在868MHz的物理层,数据传输速率为20Kb/s;在915MHz的物理层,数据传输速率为40Kb/s;在2.4GHz的物理层,数据传输速率为250Kb/s。实际上,除掉信道竞争应答和重传等消耗,真正能被应用所利用的速率可能不足100Kb/s,并且余下的速率可能要被临近多个节点和同一个节点的应用瓜分。
21
实训原理 注意:ZigBee工作在2.4GHz频段时,与其他通信协议的信道有冲突:15,20,25,26信道与Wi-Fi信道冲突较小;蓝牙基本不会冲突;无线电话尽量不与ZigBee同时使用。 3. PANID PANID其全称是Personal Area Network ID,一个网络只有一个PANID,主要用于区分不同的网络,从而允许同一地区可以同时存在多个不同PANID的ZigBee网络。 Z-Stack允许用两种方式配置PAN ID,当ZDAPP_CONFIG_PAN_ID值不设置为0xFFFF时,那么设备建立或
22
实训原理 或加入一个“最优”的网络,协调器可以随机获取一个16位的PANID建立一个网络,路由器或者终端节点可以加入任意一个自己设定信道上的网络,则不去关心PANID。 注意:在不同地区或者同一地区不同的信道可以使用同一PANID。 Z-Stack协议栈下载与安装 ZigBee协议栈有限多版本,不同厂商提供的ZigBee协议栈有一定的区别,本书选用TI公司推出的ZStack-CC a版本,用户可登录TI公司的官方网站下载,然后安装使用。另外,Z-Stack需要在IAR Assembler for 版本上运行。
23
实训原理 双击ZStack-CC2530-2.5.1a.exe文件,即可进行协议栈的安装,如图10.4所示,默认是安装到C盘根目录下。
24
实训原理 安装完成之后,在C:\Texas Instruments\ZStack-CC a目录下有4个文件夹,分别是Documents、Projects、Tools和Components。 1. Documents文件夹 该文件夹内有很多PDF文档,主要是对整个协议栈的进行说明,用户可以根据需要进行查阅。 2. Projects文件夹 该文件夹内包括用于Z-Stack功能演示的各个项目的例程,用户可以在这些例程的基础进行开发。
25
实训原理 3. Tools文件夹 该文件夹内包括TI公司提供的一些工具。 4. Components文件夹
Components是一个非常重要的文件夹,其内包括Z-Stack协议栈的各个功能函数,具体如下: (1)hal文件夹。为硬件平台的抽象层。 (2)mac文件夹。包括IEEE 物理协议所需要的头文件,TI公司没有给出这部分的具体源代码,而是以库文件的形式存在。 (3)mt文件夹。包括Z-tools调试功能所需要的源文件。
26
实训原理 (4)osal文件夹。包括操作系统抽象层所需要的文件。
(5)services文件夹。包括Z-Stack提供的两种服务所需要的文件,即寻址服务和数据服务。 (6)stack文件夹。其是Components文件夹最核心的部分,是ZigBee协议栈的具体实现部分,在该文件夹下,包括7个文件夹,分别是af(应用框架)、nwk(网络层)、sapi(简单应用接口)、sec(安全)、sys(系统头文件)、zcl(ZigBee簇库)和zdo(ZigBee设备对象)。 (7)zmac文件夹。包括Z-Stack MAC导出层文件。
27
实训原理 Z-Stack中的核心部分的代码都是编译好的,以库文件的形式给出,比如安全模块、路由模块、Mesh自组网模块等等。若要获得这部分的源代码,可以向TI公司购买。TI公司提供的Z-Stack代码并非我们理解的“开源”,仅仅提供了一个Z-Stack开发平台,用户可以在Z-Stack的基础上进行项目开发,根本无法看到有些函数的源代码。
28
目 录 一、实训目的 二、实训内容 三、实训原理 四、实训步骤
29
实训步骤 第一步,打开Z-Stack的SampleApp.eww工程。
在路径C:\Texas Instruments\ZStack-CC a\Projects\zstack\Samples\SampleApp\ CC2530DB目录下找到SampleApp.eww工程,如图10.5所示。 打开该工程后,可以看到SampleApp.eww工程文件布局,如图10.6所示。
30
实训步骤 图10.5 SampleApp.eww工程路径
31
实训步骤 图10.6 SampleApp.eww工程文件布局
32
实训步骤 第二步,编写协调器程序。 1.移除SampleApp工程中文件
将SampleApp工程中的SampleApp.h移除,移除方法为:选择SampleApp.h单击右键,在弹出的下拉菜单中选择Remove,如图10.7所示。
33
实训步骤 图10.7 移除SampleApp.h
34
实训步骤 按照上面的方法移除SampleApp.c、SampleAppHw.c、SampleApphw.h。 2.添加源文件
单击File,在弹出的下拉菜单中选择New,然后选择File,将文件保存为Coordinator.h,然后以同样的方法新建一个Coordinator.c和Enddevice.c文件,文件的保存路径为“C:\Texas Instruments\ZStack-CC a\Projects\zstack\Samples\SampleApp\Source”。 选择SampleApp工程中的App单击右键,在弹出的下拉菜单中选择Add,然后选择Add Files,选择刚才新建的三个文件(Coordinator.h、Coordinator.c、Enddevice.c)即可。
35
实训步骤 3.编写Coordinator.h程序 在Coordinator.h文件中输入以下代码: #ifndef SAMPLEAPP_H
#define SAMPLEAPP_H #include "ZComDef.h" #define SAMPLEAPP_ENDPOINT #define SAMPLEAPP_PROFID x0F08 #define SAMPLEAPP_DEVICEID x0001 #define SAMPLEAPP_DEVICE_VERSION 0
36
实训步骤 #define SAMPLEAPP_FLAGS 0 #define SAMPLEAPP_MAX_CLUSTERS 2
#define SAMPLEAPP_PERIODIC_CLUSTERID 1 extern void SampleApp_Init( uint8 task_id ); extern UINT16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ); #endif 说明:Coordinator.h文件中代码都是从SampleApp.h文件复制得到的。
37
实训步骤 4.编写Coordinator.c程序 在Coordinator.c中输入以下代码: #include "OSAL.h"
#include "ZGlobals.h" #include "AF.h" #include "ZDApp.h" #include "Coordinator.h" #include "OnBoard.h" #include "hal_lcd.h" #include "hal_led.h"
38
实训步骤 #include "hal_key.h"
const cId_t SampleApp_ClusterList[SAMPLEAPP_MAX_CLUSTERS] ={ SAMPLEAPP_PERIODIC_CLUSTERID }; //用来描述一个ZigBee设备节点,称为简单设备描述符 const SimpleDescriptionFormat_t SampleApp_SimpleDesc = { SAMPLEAPP_ENDPOINT, SAMPLEAPP_PROFID, SAMPLEAPP_DEVICEID,
39
实训步骤 SAMPLEAPP_DEVICE_VERSION, SAMPLEAPP_FLAGS,
SAMPLEAPP_MAX_CLUSTERS, (cId_t *)SampleApp_ClusterList, 0, (cId_t *)NULL }; endPointDesc_t SampleApp_epDesc; //节点描述符 uint8 SampleApp_TaskID; //任务优先级
40
实训步骤 uint8 SampleApp_TransID; //数据发送序列号
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );//声明消息处理函数 //该任务的任务初始化函数 void SampleApp_Init( uint8 task_id ) { SampleApp_TaskID = task_id; SampleApp_TransID = 0; SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_epDesc.task_id = &SampleApp_TaskID;
41
实训步骤 SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; SampleApp_epDesc.latencyReq = noLatencyReqs; afRegister( &SampleApp_epDesc ); } uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) { afIncomingMSGPacket_t *MSGpkt; //定义了一个指向接收消息结构体的指针MSGpkt
42
实训步骤 if ( events & SYS_EVENT_MSG ) {
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); while ( MSGpkt ) switch ( MSGpkt->hdr.event ) case AF_INCOMING_MSG_CMD: SampleApp_MessageMSGCB( MSGpkt );
43
实训步骤 break; default: } osal_msg_deallocate( (uint8 *)MSGpkt );
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); return (events ^ SYS_EVENT_MSG); //返回未处理的事件
44
实训步骤 } return 0; //丢弃未知的事件
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) { unsigned char buffer[6]=" "; switch ( pkt->clusterId ) case SAMPLEAPP_PERIODIC_CLUSTERID:
45
实训步骤 osal_memcpy(buffer,pkt->cmd.Data,6); //将接收到的数据拷贝到缓冲区buffer中
//判断接收到的数据是不是“NEWLab”这6个字符 if((buffer[0]=='N')||(buffer[1]=='E')||(buffer[2]=='W')||(buffer[3]=='L')||(buffer[4]=='a')||(buffer[5]=='b')) { HalLedBlink( HAL_LED_2, 0, 50, 500 ); //如果是“NEWLab”这6个字符,则使LED2闪烁 }
46
实训步骤 else { HalLedSet( HAL_LED_2,HAL_LED_MODE_ON); //如果不是“NEWLab”这6个字符,则点亮LED2 } break; } } 程序分析: 说明:Coordinator.c文件中代码大部分是从SampleApp.c文件复制得到的,头文件需要将#include "SampleApp.h"与#include "SampleAppHw.h"替换为#include "Coordinator.h",即上述代码的第5行。
47
实训步骤 ① 第10—13行,SAMPLEAPP_MAX_CLUSTERS是在SampleApp.h文件中定义的宏,这主要是为了与协议栈里面数据的定义格式保持一致,下面代码中的常量都是以宏定义的形式实现的。 ② 第34行,初始化了任务优先级(任务优先级由协议栈的操作系统OSAL分配)。 ③ 第35行,将发送数据包的序号初始化为0,在ZigBee协议栈中,每发送一个数据包,该发送序号自动加1(协议栈里面的数据发送函数会自动完成该功能),因此,在接收端可以查看接收数据包的序号来计算丢包率。
48
实训步骤 ④ 第36-39行,对节点描述符进行初始化,初始化格式较为固定,一般不需要修改。
⑤ 第40行,使用afRegister函数将节点描述符进行注册,只有注册以后,才可以使用OSAL提供的系统服务。 ⑥ 第47行,使用osal_msg_receive函数从消息队列上接收消息,该消息中包含了指向接收到的无线数据包的指针。 ⑦ 第52行,对接收到的消息进行判断,如果是接收到了无线数据,则调用第53行的函数对数据进行相应的处理。
49
实训步骤 ⑧ 第58行,接收到的消息处理完后,就需要释放消息所占据的存储空间,因为在ZigBee协议栈中,接收到的消息是存放在堆上的,所以需要调用osal_msg_deallocate函数将其占据的堆内存释放,否则容易引起“内存泄漏”。 ⑨ 第59行,处理完一个消息后,再从消息队列时接收消息,然后对其进行相应的处理,直到所有消息都处理完为止。 5.修改OSAL_SampleApp.c文件 将#include "SampleApp.h"注释掉,然后添加#include "Coordinator.h"即可。
50
实训步骤 6.设置Enddevice.c文件不参与编译
在Workspace下面的下拉列表框中选择CoordinatorEB,然后选择Enddevice.c文件单击右键,在弹出的下拉菜单中选择Options,在弹出的对话框中选择Exclude from build,使得Enddevice.c文件呈灰白显示状态。文件呈灰白显示状态说明该文件不参与编译,ZigBee协议栈正是使用这种方式实现对源文件编译的控制。 第三步,编写终端节点程序。 在Workspace下面的下拉列表框中选择EndDeviceEB,设置Coordinator.c文件不参与编译。在Enddevice.c文件中输入如下代码:
51
实训步骤 #include "OSAL.h" #include "ZGlobals.h" #include "AF.h"
#include "ZDApp.h" #include "Coordinator.h" #include "OnBoard.h" #include "hal_lcd.h" #include "hal_led.h" #include "hal_key.h"
52
实训步骤 const cId_t SampleApp_ClusterList[SAMPLEAPP_MAX_CLUSTERS] ={ SAMPLEAPP_PERIODIC_CLUSTERID}; //用来描述一个ZigBee设备节点,与Coordinator.c文件中的定义格式一致 const SimpleDescriptionFormat_t SampleApp_SimpleDesc = { SAMPLEAPP_ENDPOINT, SAMPLEAPP_PROFID, SAMPLEAPP_DEVICEID,
53
实训步骤 SAMPLEAPP_DEVICE_VERSION, SAMPLEAPP_FLAGS, 0, (cId_t *)NULL,
SAMPLEAPP_MAX_CLUSTERS, (cId_t *)SampleApp_ClusterList }; endPointDesc_t SampleApp_epDesc; //节点描述符 uint8 SampleApp_TaskID; //任务优先级 uint8 SampleApp_TransID; //数据发送序列号
54
实训步骤 devStates_t SampleApp_NwkState; //保存节点状态
void SampleApp_SendPeriodicMessage( void );//声明数据发送函数 //任务初始化函数 void SampleApp_Init( uint8 task_id ) { SampleApp_TaskID = task_id; //初始化任务优先级 SampleApp_NwkState = DEV_INIT; //设备状态初始化 SampleApp_TransID = 0; //将发送数据包的序列号初始化为0
55
实训步骤 //对节点描述符进行初始化 SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id = &SampleApp_TaskID; SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; SampleApp_epDesc.latencyReq = noLatencyReqs; afRegister( &SampleApp_epDesc );//使用afRegister函数将节点描述符进行注册 }
56
实训步骤 uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) {
afIncomingMSGPacket_t *MSGpkt; if ( events & SYS_EVENT_MSG ) MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); while ( MSGpkt )
57
实训步骤 switch ( MSGpkt->hdr.event ) { //收到网络中设备状态有变化时
case ZDO_STATE_CHANGE: SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //读取节点的设备类型 if ( (SampleApp_NwkState == DEV_END_DEVICE) ) { SampleApp_SendPeriodicMessage(); }
58
实训步骤 break; default: } osal_msg_deallocate( (uint8 *)MSGpkt );
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); return (events ^ SYS_EVENT_MSG);
59
实训步骤 return 0; } void SampleApp_SendPeriodicMessage( void ) {
unsigned char theMessageData[6] = "NEWLab"; afAddrType_t my_DstAddr; my_DstAddr.addrMode=(afAddrMode_t)Addr16Bit; my_DstAddr.endPoint=SAMPLEAPP_ENDPOINT; //初始化端口号
60
实训步骤 my_DstAddr.addr.shortAddr=0x0000;
AF_DataRequest(&my_DstAddr,&SampleApp_epDesc,SAMPLEAPP_PERIODIC_CLUSTERID,6,theMessageData,&SampleApp_TransID,AF_DISCV_ROUTE, AF_DEFAULT_RADIUS); HalLedBlink(HAL_LED_2,0,50,500); } 程序分析: 说明:Enddevice.c文件中代码大部分是从SampleApp.c文件复制得到的,头文件与Coordinator.c一样。
61
实训步骤 ① 第36行,将设备状态初始化为DEV_INIT,表示该节点没有连接到ZigBee网络。
② 第57行,对节点设备类型进行判断,如果是终端节点(设备类型码为DEV_END_DEVICE),再执行59行代码,实现无线数据发送。 ③ 第74行,定义了一个数组theMessageData,用于存放要发送的数据。 ④ 第75行,定义了一个afAddrType_t类型的变量my_DstAddr,因为数据发送函数AF_DataRequest的第一个参数就是这种类型的变量。
62
实训步骤 ⑤ 第76行,将发送地址模式设置为单播(Addr16Bit表示单播)。
⑥ 第78行,在ZigBee网络中,协调器的网络地址是固定的,为0x0000,因此,向协调器发送时,可以直接指定协调器的网络地址。 ⑦ 第79行,调用数据发送函数AF_DataRequest进行无线数据的发送。 ⑧ 第80行,调用HalLedBlink函数,使终端节点的LED2闪烁。 第四步,下载程序、运行。 编译无误后,将两块ZigBee模块上电,在Workspace下面的下拉列表框中选择CoordinatorEB把协调器程序下载到ZigBee模块中,在Workspace下面的下拉列表框中选择
63
实训步骤 EndDeviceEB把终端节点程序分别下载到另一个ZigBee模块中。几秒钟后,会发现终端节点与协调器的LED1连接灯点亮,LED2灯闪烁,这说明协调器已经收到终端节点发送的数据。
64
谢谢!
Similar presentations