Zigbee开发
准备工作
ZigBee 的技术特性决定它将是无线传感器网络的最好选择,广泛用于物联网,自动控制和监视等诸多领域。以美国德州仪器 TI 公司 CC2530 芯片为代表的 Zigbee解决方案在国内高校企业掀起了一股 Zigbee 技术应用的热潮。CC2530 支持 IEEE 802.15.4 标准 ZigBee/ZigBee RF4CE 和能源的应用。拥有庞大的快闪记忆体多达 256 个字节,CC2530 是理想 ZigBee 专业应用。

IAR集成开发环境:IAR是瑞典IAR Systems公司研发的一款微处理器开发集成开发环境。
仿真器调试与下载:仿真器选用SmartRF04EB,使用之前需安装驱动。仿真器连接上PC端和开发板,用于下载实验,调试代码。将仿真器卸下,程序已经写入了核心板的flash中,因此程序运行现象会持续存在,不需要擦除,因为每次实验会对上一个实验内容进行覆盖。
流程:IAR里编译完代码—>接上仿真器—>IAR中点击“下载和调试”—->程序下载到开发板中运行
(如果不进行断点调试,可以把仿真器卸下,就相当于是个简单的烧录器。)
仿真器和烧录器的区别
烧录器也叫编程器,是用来将特定格式的程序文件(比如*.hex *.bin等格式)烧进单片机的内部EEPROM,使其上电后能运行你烧入的程序。也就是说你每次修改完程序需要验证的时候都得烧一次芯片,然后接到板子上,再上电运行,而且不支持多种调试方式。
而仿真器是通过硬件和相应的软件对单片机进行仿真,可以直接接在用户板上运行程序,还可以进行程序调试(单步、断点等),它不需要每次修改程序都烧写芯片,更没有来回拆、装芯片的麻烦,是学习单片机极其方便的工具。
Z-Stack
Z-Stack 软件因其出色的 ZigBee 与 ZigBee PRO 特性集被 ZigBee 测试机构国家技术服务公司 (NTS) 评为 ZigBee 联盟最高业内水平,目前该软件已为全球数以千计的 ZigBee开发人员广泛采用。 Z-Stack 是在 2007 年 4 月,德州仪器推出业界领先的 ZigBee 协议栈,Z-Stack 符合 ZigBee 2006 规范,支持多种平台。Z-Stack 只是 ZigBee 协议的一种具体的实现,Z-Stack 是其中一种,不能把 Z-Stack 等同于 ZigBee 协议。简言之,Z-Stack是ZigBee协议的一种具体的实现,是CC2530上运行的协议栈。
zigbee协议栈与zigbee的区别
ZigBee 协议栈建立在 IEEE 802.15 4 的 PHY 层和 MAC 子层规范之上。它实现了网络层(networklayer,NWK)和应用层(applicationlayer,APL)。在应用层内提供了应用支持子层(APS)和 ZigBee 设备对象(ZDO)还有应用框架层(AF)。EEE802.15.4 2003标准定义了最下面的两层:物理层(PHY)和介质接入控制子层(MAC)。

协议是一系列标准,协议栈是协议的具体实现,协议和用户之间的接口,通过协议栈使用协议。可以理解为代码,函数库,供上层应用调用。商业化的协议栈就是写好了底层代码。符合协议标准,提供给开发者一个功能模块去调用,需要什么功能,调用什么函数,不用关心底层。
应用层包括:应用支持子层,ZDO层,应用框架层(AF)
应用支持子层:介于网络层和应用层之间,指定了应用层提供服务规范和接口的部分,该规范定义了允许应用对象传输数据的数据服务,以及提供绑定的管理服务。
zigbee设备对象层;为定义网络的节点的角色,以及网络服务。ZDO通过端点0可以使应用程序(应用层)和zigbee协议栈的其他层进行通信。
一个端点对应一个任务,一个任务都有唯一的任务号及任务处理函数,ZDO_RegisterForZDOMsg()在相应的任务中注册事件,并且每一个事件只能被成功的注册一次。注册的实质是将注册的信息通过ZDO_Msg_t的形式加入到链表中。ZDO是一个特殊的应用层的端点(Endpoint),ZDO占用每个节点(node)的0终端。它是应用层其他端点与应用子层管理实体交互的中间件。Endpoint是应用对象,node好像是一个硬件节点,一个节点最多有254个终端,也就是说一个节点可以配置为254种应用来使用,在两个通信端点只见能让多个应用循环使用APS。

组网概念
组建一个完整的zigbee网状网络包括两个步骤:网络初始化、节点加入网络。其中节点加入网络又包括两个步骤:通过与协调器连接入网和通过已有父节点入网。
ZigBee网络中的节点主要包含三个:终端节点、路由器节点、协调器节点
协调器节点:协调器负责启动整个网络。它也是网络的第一个设备。协调器选择一个信道和一个网络ID(也称之为PAN ID,即Personal Area Network ID),随后启动整个网络。ZigBee协调器是网络各节点信息的汇聚点,是网络的核心节点,负责组建、维护和管理网络,并通过串口实现各节点与上位机的数据传递;ZigBee协调器有较强的通信能力、处理能力和发射能力,能够把数据发送至远程控制端。
注意,协调器的角色主要涉及网络的启动和配置。一旦这些都完成后,协调器的工作就像一个路由器(网关)。由于ZigBee网络本身的分布特性,因此接下来整个网络的操作就不在依赖协调器是否存在。
路由器节点:负责转发数据资料包,进行数据的路由路径寻找和路由维护,允许节点加入网络并辅助其子节点通信;路由器节点是终端节点和协调器节点的中继,它为终端节点和协调器节点之间的通信进行接力。
终端节点:终端节点可以直接与协调器节点相连,也可以通过路由器节点与协调器节点相连。
协调器和终端节点的区别
协调器就相当于网关,是整个ZigBee网络的核心,所有数据最终都返回协调点去;节点分为路由节点和终端节点,路由节点可以当终端节点来使用,还可以连接到其他的路由节点和终端节点,而终端节点就是整个网络的最后一个点,不能连接到其他节点,只能直接返回数据给协调器。
工程文件结构
ZStack 3.0.1就是TI提供的ZigBee解决方案软件支持包(SDK),SDK并不是全开源的,没有开源的部分是以链接库的形式提供,非常稳定,我们也基本不会修改到。软件协议栈采用了Z-Stack,是TI提供的符合ZigBee规范(由ZigBee联盟制定)的免费协议栈,完全可以运行在GAINST CC2430节点上,利用Z-Stack,用户能够简单快速的开发出适合自己的ZigBee应用。 进入Z-Stack 3.0.1目录下:

Components,协议栈各个功能部件的实现.
bsp(板级支持包):为上层的驱动程序提供访问硬件设备寄存器的函数包。
driverlib(驱动链接库): 为上层提供驱动程序API。
hal(硬件设配层): 适配下层不同硬件的驱动程序,为上层提供统一API。
mac(数据链路层):实现IEEE802.15.4协议、射频收发控制等。
mt(监视器):为监视协议栈各层的运行状态提供支持。
osal(操作系统抽象层):实现系统调度、内存管理,存储管理等功能。
services(服务):提供一些公共的、常用的API,比如复制MAC地址等。
stack(ZigBee协议堆栈):实现ZigBee相关的功能和服务,这个目录和ZigBee协议的内容密切相关。
usblib(USB链接库):如果芯片支持USB(比如CC2538),就需要USB链接库的支持了。
zmac(数据链路子层):mac层的支持子层,属于mac层的一部分!
Projects目录下的zstcak文件夹下包含一些ZigBee面向家居自动化(智能家居)的应用工程
以SampleSwitch工程为例子进行讲解,这是一个ZigBee插座的应用例程:

由于我们的板子是CC2530,所以打开CC2530DB目录:

通过IAR 10.10.1打开SampleSwitch.eww,工程打开后:

三种设备的切换位置:

不同设备类型包含的文件不同,Coordinator包含f8wCoord, cfgRouter包含f8wRouter.cfg, EndDevice包含f8wEndev.cfg,这几个文件在协议栈Tools文件夹里看到:

节点加入网络
节点通过协调器加入网络
当节点协调器确定之后,节点首先需要和协调器建立连接加入网络。为了建立连接,FFD节点需要向协调器提出请求,协调器接收到节点的连接请求后根据情况决定是否允许其连接,然后对请求连接的节点做出响应,节点与协调器建立连接后,才能实现数据的收发。节点加入网络的具体流程可以分为下面的步骤:
查找网络协调器。
首先会主动扫描查找周围网络的协调器,如果在扫描期限内检测到信 标,那么将获得了协调器的有关信息,这时就向协调器发出连接请求。在选择合适的网络之后,上层将请求MAC层对物理层PHY和MAC层的phyCurrentChannel、macPANID等PIB属性进行相应的设置。如果没有检测到,间隔一段时间后,节点重新发起扫描。
发送关联请求命令(Associaterequest command)。
节点将关联请求命令发送给协调器,协调器收到后立即回复一个确认帧(ACK),同时向它的上层发送连接指示原语,表示已经收到节点的连接请求。但是这并不意味着已经建立连接,只表示协调器已经收到节点的连接请求。当协调器的mac层的上层接收到连接指示原语后,将根据自己的资源情况(存储空间和能量)决定是否同意此节点的加入请求,然后给节点的mac层发送响应。
- 等待协调器处理。
当节点收到协调器加入关联请求命令的ACK后,节点mac将等待一段时间,接受协调器的连接响应。在预定的时间内,如果接收到连接响应,它将这个响应向它的上层通告。而协调器给节点的mac层发送响应时会设置一个等待响应时间(T_ResponseWaitTime)来等待协调器对其加入请求命令的处理,若协调器的资源足够,协调器会给节点分配一个16位的短地址,并产生包含新地址和连接成功状态的连接响应命令,则此节点将成功的和协调器建立连接并可以开始通信。若协调器资源不够,待加入的节点将重新发送请求信息,直接入网成功。
- 发送数据请求命令。
如果协调器在响应时间内同意节点加入,那么将产生关联响应命令(Associateresponse command)并存储这个命令。当响应时间过后,节点发送数据请求命令(Datarequest command)给协调器,协调器收到后立即回复ACK,然后将存储的关联响应命令发给节点。如果在响应时间到后,协调器还没有决定是否同意节点加入,那么节点将试图从协调器的信标帧中提取关联响应命令,成功的话就可以入网成功,否则重新发送请求信息直到入网成功。
回复。
节点收到关联响应命令后,立即向协调器回复一个确认帧(ACK),以确认接收到连接响应命令,此时节点将保存协调器的短地址和扩展地址,并且节点的MLME向上层发送连接确认原语,通告关联加入成功的信息。
节点通过已有节点加入网络
当靠近协调器的FFD节点和协调器关联成功后,处于这个网络范围内的其他节点就以这些FFD节点作为父节点加入网络了,具体加入网络有两种方式,一种是通过关联(associate)方式,就是待加入的节点发起加入网络;另一种是直接(direct)方式,就是待加入的节点具体加入到那个节点下,作为该节点的子节点。其中关联方式是zigbee网络中新节点加入网络的主要途径。
对于一个节点来说只有没有加入过网络的才能进行加入网络。在这些节点中,有些是曾经加入过网络中,但是却与它的父节点失去联系(这样的被称为孤儿节点),而有些则是新节点。当是孤儿节点时,在它的相邻表中存有原父节点的信息,于是它可以直接给原父节点发送加入网络的请求信息。如果父节点有能力同意它加入,于是直接告诉它的以前被分配的网络地址,它便入网成功;如果此时它原来的父节点的网络中,子节点数已达到最大值,也就是说网络地址已经分配满,父节点便无法批准它加入,它只能以新节点身份重新寻找并加入网络。
而对于新节点来说,他首先会在预先设定的一个或多个信道上通过主动或被动扫描周围它可以找到的网络,寻找有能力批准自己加入网络的父节点,并把可以找到的父节点的资料存入自己的相邻表。存入相邻表的父节点的资料包括zigbee协议的版本、协议栈的规范、PAN ID和可以加入的信息。在相邻表中所有的父节点中选择一个深度最小的,并对其发出请求信息,如果出现相同最小深度的两个以上的父节点,那么随机选取一个发送请求。如果相邻表中没有合适的父节点的信息,那么表示入网失败,终止过程。如果发出的请求被批准,那么父节点同时会分配一个16位的网络地址,此时入网成功,子节点可以开始通信。如果请求失败,那么重新查找相邻表,继续发送请求信息,直到加入网络。


第一张图是所有设备都要执行的部分,startDevice
函数会判断设备类型,进行不同的处理。
第7步这里,会”发送“一个网络初始化的消息(ZDO_NETWORK_INIT).(触发事件)

然后在ZDOApp_event_loop
函数中,接收到网络初始化消息后,发送一个设备状态改变的消息,(ZDO_STATE_CHANGE_EVT),后调用startdevice

设备完成入网流程的最后一步是调用ZDO_UpdateNwkStatus()函数更新网络状态,该函数第二个参数是应用在AF层注册的SampleApp的任务ID,也就是将网路状态的改变从ZDO层(ZDO文件夹)传递到应用层(App文件夹)。
我们的目标
在某个条件下,禁止特定的某个设备加入网络:
ZDP_MgmtPermitJoinReq: 该函数可以由协调器指定广播地址进行广播,这个函数广播的命令即是PermitJoinReq命令,其他设备收到后会调用NLME_PermitJoiningRequest()。该函数用于设置该协调器是否允许其他网络加入。
NLME_PermitJoiningRequest 是对于自己而言, 开启或者关闭 本地端 允许其他设备入网
ZDP_MgmtPermitJoinReq 是通过 地址 ,告诉某个设备 或者 所有路由 开启或者关闭 允许其他设备入网
这个函数实现的是一段时间内禁止所有设备加入网络,不满足我们的要求。
- osal_set_event: 一个”开关按钮“?,一按,可以在新的设备初始化的时候就不触发ZDO状态改变事件,或者触发一个新的事件,接收到这个事件后就直接去调用ZDO_UpdateNwkStatus()函数,将网络状态传递给应用层,反映给用户。
自组网的概念
Z-Stack协议栈中默认配置的是自组网!意味着,各个设备一旦启动,均会默认自动扫描创建或搜寻加入网络,无须我们人为去控制或做任何配置!
ZigBee设备的启动,最终是要调用ZDO_StartDevice()函数来实现的。下面看一下是怎么启动这个函数的。在ZDOInitDevice()函数的最后,调用了下面的ZDApp_NetworkInit()函数,在这个函数中,启动了ZDO_NETWORK_INIT事件,这个事件是在ZDApp_event_loop()事件处理函数中进行处理的。在这个事件中调用了启动设备的函数ZDO_StartDevice()。
如果使用HOLD_AUTO_START选项,那么本工程就会禁止自动启动ZDApp事件处理循环中的ZDO_NETWORK_INIT事件,也就是上电后不自动调用ZDOInitDevice(),需要通过外部事件,或者用户自己调用这个函数