最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

Zstack

IT圈 admin 27浏览 0评论

2024年10月13日发(作者:罗远)

关于ZIGBEE技术

Zigbee的由来

在蓝牙技术的使用过程中,人们发现蓝牙技术尽管有许多优点,但仍存在

许多缺陷。对工业,家庭自动化控制和遥测遥控领域而言,蓝牙技术显得太复杂,

功耗大,距离近,组网规模太小等,而工业自动化对无线通信的需求越来越强烈。

正因此,经过人们长期努力,Zigbee协议在2003年中通过后,于2004正式问世

了。

Zigbee是什么

Zigbee是一个由可多到65000个无线数传模块组成的一个无线数传网络平

台,十分类似现有的移动通信的CDMA网或GSM网,每一个Zigbee网络数传

模块类似移动网络的一个基站,在整个网络范围内,它们之间可以进行相互通信;

每个网络节点间的距离可以从标准的75米,到扩展后的几百米,甚至几公里;

另外整个Zigbee网络还可以与现有的其它的各种网络连接。例如,你可以通过

互联网在北京监控云南某地的一个Zigbee控制网络。

不同的是,Zigbee网络主要是为自动化控制数据传输而建立,而移动通信

网主要是为语音通信而建立;每个移动基站价值一般都在百万元人民币以上,而

每个Zigbee―基站‖却不到1000元人民币;每个Zigbee 网络节点不仅本身可以与

监控对对象,例如传感器连接直接进行数据采集和监控,它还可以自动中转别的

网络节点传过来的数据资料; 除此之外,每一个Zigbee网络节点(FFD)还可在

自己信号覆盖的范围内,和多个不承担网络信息中转任务的孤立的子节点(RFD)

无线连接。

每个Zigbee网络节点(FFD和RFD)可以可支持多到31个的传感器和受

控设备,每一个传感器和受控设备终可以有8种不同的接口方式。可以采集和传

输数字量和模拟量。

Zigbee技术的应用领域

Zigbee技术的目标就是针对工业,家庭自动化,遥测遥控,汽车自动化、

农业自动化和医疗护理等,例如灯光自动化控制,传感器的无线数据采集和监控,

油田,电力,矿山和物流管理等应用领域。另外它还可以对局部区域内移动目标

例如城市中的车辆进行定位.

通常,符合如下条件之一的应用,就可以考虑采用Zigbee技术做无线传输:

1.需要数据采集或监控的网点多;

2.要求传输的数据量不大,而要求设备成本低;

3.要求数据传输可性高,安全性高;

4.设备体积很小,不便放置较大的充电电池或者电源模块;

5.电池供电;

6.地形复杂,监测点多,需要较大的网络覆盖;

7.现有移动网络的覆盖盲区;

8.使用现存移动网络进行低数据量传输的遥测遥控系统。

9.使用GPS效果差,或成本太高的局部区域移动目标的定位应用。

Zigbee 技术的特点

省电:两节五号电池支持长达6个月到2年左右的使用时间。

可靠:采用了碰撞避免机制,同时为需要固定带宽的通信业务预留了专用

时隙,避免了发送数据时的竞争和冲突;节点模块之间具有自动动态组网的功能,

信息在整个Zigbee网络中通过自动路由的方式进行传输,从而保证了信息传输

的可靠性。

时延短:针对时延敏感的应用做了优化,通信时延和从休眠状态激活的时

延都非常短。

网络容量大:可支持达65000个节点。

安全:ZigBee提供了数据完整性检查和鉴权功能,加密算法采用通用的

AES-128。

高保密性:64位出厂编号和支持AES-128加密。

Zigbee的发展前景

Zigbee技术和RFID 技术在2004年就被列为当今世界发展最快,市场前景

最广阔的十大最新技术中的两个。关于这方面的报道,你只需在百度,或

GOOGLE搜索栏中键入―Zigbee‖,你就会看到大量的有关报道。总之,今后若干

年,都将是Zigbee技术飞速发展的时期。

Zigbee技术在我国的应用情况

尽管,国内不少人已经开始关注Zigbee这们新技术,而且也有不少单位开

始涉足Zigbee技术的开发工作,然而,由于Zigbee 本身是一种新的系统集成技

术,应用软件的开发必须和网络传输,射频技术和底层软硬件控制技术结合在一

起。因而深入理解这个来自国外的新技术,再组织一个在这几个方面都有丰富经

验的配套的队伍,本身就不是一件容易的事情,因而,到目前为止,国内目前除

了成都西谷曙光数字技术有限公司,真正将Zigbee技术开发成产品,并成功地

用于解决几个领域的实际生产问题而外,尚未见到其它报道。

Zigbee 和现有移动网(GPRS,CDMA-1X)的比较

1.无网络使用费:使用移动网需要长期支付网络使用费,而且是按节点终

端的数量计算的,而Zigbee没有这笔费用;

2.设备投入低:使用移动网需要购买移动终端设备,每个终端的价格在人

民币1000元上下,而使用Zigbee 网络,不仅Zigbee网络节点模块(相当于基

站)费用每只人民币不到1000元,而且,主要使用的网络子节点(相当于手机)

的价格还要低得多;

3.通信更可靠:由于现有移动网主要是为手机通信而设计的,尽管

CDMA-1X和GPRS可以进行数据通信,但实践发现,不仅通信数率比设计速率

低很多,而且数据通信的可靠信也存在一定的问题。而Zigbee网络则是专门为

控制数据的传输而设计的,因而控制数据的传输具有相当的保证。

4.高度的灵活性和低成本:首先,通过使用覆盖距离不同,功能不同的Zigbee

网络节点,以及其它非Zigbee系统的低成本的无线收发模块,建立起一个Zigbee

局部自动化控制网,(这个网络可以是星型,树状,网状及其共同组成的复合网

结构)再通过互联网或移动网与远端的计算机相连,从而实现低成本,高效率的

工业自动化遥测遥控;

5.比起现有的移动网来,尽管Zigbee仅仅只是一个局域网,覆盖区域有限,

但它却可以与现有的移动网,互联网和其它通信网络相连接,将许多Zigbee局

域网相互连成为一个整体。有效的解决移动网的盲区覆盖问题:我们知道,现有

移动网络在许多地方存在盲区,特别是铁路,公路,油田,矿山等野外,更是如

此。而增加一个移动基站或直放站的费用是相当可观的,此时使用Zigbee网络

进行盲区覆盖不仅经济有效,而且往往是现在唯一可行手段。

Zigbee与现有数传电台的比较

1.可靠性高:由于Zigbee模块的集成度远比一般数传电台高,分离元器件

少,因而可靠性更高;

2.使用方便安全:因为集成度高,比起一般数传电台来,Zigbee收法模块

体积可以做得很小,而且功耗低,例如成都西谷公司远距离传输模块(2-5公里),

最大发射电流比一个CDMA手机还要小许多,因而很容易集成或直接安放在到

设备之中,不仅使用方便,而且在户外使用时,不容易受到破坏;

3.抗干扰力强,保密性好,误码率低:Zigbee收发模块使用的是2.4G 直

序扩频技术,比起一般FSK, ASK和跳频的数传电台来,具有更好的抗干扰能力,

和更远的传输距离;参阅我们网站中有关CDMA直序扩频技术的优越性讨论,

和Cypress公司有关实验报道。

4.免费频段:Zigbee使用的是免费频段,而许多数传电台所使用的频段不

仅需要申请,而且每年都需要向国家无委会交纳相当的频率使用费。

5.价格低: Zigbee数传模块的价格只有具有类似功能的数传电台的几分

之一;(2.4G,250kps,3-5公里距离DSSS 数传模块每只不到200元人民币)

提供低成本,高可靠性的无线数传互联网平台(包括软件和硬件),以及相

关技术支持,以满足不同客户的具体需要,就是我们的服务宗旨。

学习Zstack之1

Zstack情况:

本人采用的是TI的Zstack1.4.3协议,据说这个需要IAR7.30B及以上版本,

而目前市面上又没有破解,所以用的人很少,这也是我的机会!呵呵!(傻笑有

点多,关键是WORD里没有表情符号,不能正常表达我此时的心情!)

正式开始:

开始之前在说一句:从TI网站上下载的Zstack的方法就不介绍了。否则就

是从-1开始了而不是从0开始了-----------------我是这么觉得的!

第一步:安装Zstack

从TI官方网站上下载的Zstack为:,我想这个压缩包大家都

认识。解压之后为:文件。这个安装文件大家都会了。

默认安装路径为:C:Texas InstrumentsZStack-1.4.3。安装之后在C:Texas

InstrumentsZStack-1.4.3目录下有各PDF文档为:Getting Started Guide

,不用多说,这个肯定是要看的。既然把它放到这么前面,说明它是

入门中的入门文档。下面就简单介绍下这个文档:

1、介绍了安装需要的硬件软件条件:需要电脑、操作系

统为Windows 2000或 Windows XP。至于更高或更低版本的本人没有尝试。

2、讲了安装流程。这个有点多余了,这年月哪个有电脑的没有安装上百上千次

的软件啊?但是需要强调的是安装路径----默认就好!

3、接下来就是让我们看的第一个文档为:

Start->Programs->Texas Instruments->ZStack-1.4.3->Z-Stack User’s Guide,

既然让我看我就来看看这个文档!!

第二步:Z-Stack 用户指导

这个文档的更新时间为:2007年12月21日----应该还是比较新的版本。由

于本人英文的却有限,就不翻译了,浏览一遍,把大概意思说下就可以了:

1、介绍

1.1、适用范围

本文档适用于CC2430ZigBee开发板----CC2430ZDK。

2、产品包描述(TI提供的CC2430ZDK工具包)

2.1、安装包内容

这个就是上面提到的的安装之后的所有内容了。说白了

就是包含Zstack开发所需要的所有软件和文档资料等。

2.2、开发板介绍

两块 SmartRF04EB 评估版,每个都可以用于CC2430EM评估模块。如图1-1

所示:

Figure 1: Chipcon SmartRF04EB Evaluation Board with CC2430EM

5块CC2430DB 评估板,如图1-2所示:

Figure 2: Chipcon CC2430DB Development Board

10个SOC_BB 评估板,每个都可以用于CC2430EM或CC2431EM。如图1-3

所示:

Figure 3: Chipcon SOC_BB Battery Board

2.3、电缆

也就是包含开发包所需要的电缆,如RS232串口线,USB线等等附属配件。

3、安装配置

3.1、主机配置

一台个人计算机----也就是电脑哈。我想玩嵌入式的应该都有,而现今不过时的

配置就可以:下面是最低配置

.NET 1.1 架构

Windows XP Service Pack 1 (i如果是 Windows XP)

1个串口(也就是RS232接口)s

1 USB接口

个人认为要求已经相当低了,如果你的电脑没有这配置,个人强烈建议马

上扔掉!不过如今笔记本电脑很少有串口的,所以建议使用台式电脑,而且装机

的时候一定要把串口引出,否则就比较麻烦了!

3.2、目标板需求

其实也是开发环境需求--- IAR EW8051。目前需要的版本为7.30B及以上。

要求还是比较高的,因为目前这个版本没有破解的。但是在/

上有30天评估版下载。这个版本使用一定要小心,因为如果30天之后仅仅是卸

载IAR重新安装是没有用的,一般最笨的办法是重新安装操作系统。解决这个

问题最好的办法就是买正版,呵呵,我想绝大多数像我这样的中国人都不会买的。

除此之外最好的办法就是破解,但是目前这个破解极少,都是需要收费的,而且

都是国外网站才有,所以我们就只好期望中国的高人抓紧破解并公开了!当然其

他解决办法就相对来说很多了,比如安装后弄个还原点什么的;或者安装后我不

停地使用(每天24小时),30天之后我觉得你也学会了,就不用IAR这个版本

了,说不定就移植到低版本上去了;等等类似之法我觉得都可以的。本人采用的

是本办法中相对比较聪明的,也是一位高人告诉我的:装个虚拟操作系统,在虚

拟操作系统下时间可以随时更改,让它一直停留在某个时间,主要30天的试用

就比较慢长了,只要你不要忘记改那时间。

4、产品安装过程

4.1、安装Z-Stack

这个也就是安装的过程。

4.2、IAR安装

一般来说安装选择默认路径,但是自定义路径也不会出问题的。注意IAR

版本7.30B及以上版本才可以运行1.4.3协议。

4.3、设备IEEE地址

每个 CC2430DB, CC2430EM,和 CC2431EM都已经排列了一个唯一的64

位物理地址(IEEE地址),这个地址已经写到了CC2430内部FLASH里面,在

CC2430DB, CC2430EM,和 CC2431EM板的底部有这个地址标签。

这个地址被写入到FLASH的0x1FFF8地址中,注意这个地址也可以更改的,

通过些FLASH软件,一般0xFFFFFFFFFFFFFFFF地址被认为是无效地址。

5、配置并试用Z-Stack

5.1、配置Z-Stack

这个详见5.3节。

5.2、逻辑类型

这里主要是介绍了ZIGBEE协议中的三种设备类型:

ZigBee 协调者(ZC):这个设备被配置为初始化并建立一个PAN网络

ZigBee 路由器(ZR):该设备被配置为加入一个存在的网络,可以加入一个协调

求或路由器,然后允许其他设备加入它,在网络中路有数据信息。

ZigBee 终端节点 (ZED):该设备被配置为加入一个存在的网络,可以加入一个

协调求或路由器。

5.3、建立样品应用设备:SampleApp

基本上就是采用SampleApp应用中的Demo例子来演示整个流程,就是采用一

个协调器和一个或多个路由器来形成一个ZigBee网络演示。在该例子中主要通

过SmartRF04EB板上的某些跳线来完成设备类型的选型,当然这个方法在程序

中是需要判断哪个按键被拉低或拉高,对于做个设计的来说应该是相当好理解

的。

申明:由于本人很穷,所以没钱买TI原装开发包,当然也就没有上面提到

的硬件,本人采用的是某家公司(为了避免广告,这里就不说明了)的硬件系统。

5.4、建立一个SampleLight协调器设备

至于提到的硬件连接这里一律省略。

无疑:首先要打开对应工程,如图1-4所示:

图1-4

在工作窗口中选择DemoEB,如图1-5所示:

图1-5

然后选择工程菜单(Project)下的全部编译(Rebuild All)选项,如图1-6所示:

图1-6

然后选择工程菜单(Project)下的调试(Debug)选项,如图1-7所示:

图1-7

下载完之后就可以退出调试状态,通过选中调试菜单下的停止调试选项,如图

1-8所示:

图1-8

按照此种方法下载至少两个CC2430EM模块,就可以进行Demo演示了。

6、 Z-Stack 示范

至于详细的示范流程,这里先不说了,因为本人采用的硬件与原装有点差

异,即使按照这个方法下载仍然不能演示,因为我这个不能用跳线来选择设备类

型。

所以我必须进入程序把跳线判断程序进行简单必要的修改才能演示。

该文档介绍的演示结果及现象都是基于CHIPCON原厂评估板。

和通道(Channel)选择

ZigBee协议规范规定,一个14位的个域网标志符(PAN ID)来标识唯一

的一个网络。Z-Stack可以用两种方式由用户自己选择其PAN ID,当

ZDAPP_CONFIG_PAN_ID值设置不为0xFFFF时,那么设备建立或加入网络的

PAN ID由ZDAPP_CONFIG_PAN_ID指定;如果设置ZDAPP_CONFIG_PAN_ID

为0xFFFF;那么设备就将建立或加入它发现网络中的―最好‖的网络。关于这里

提到的―最好‖的网络,我觉得可能是有些参数评估,只不过这里没有详细的介绍,

在后续文档中应该有介绍的。

在2.4G频段上,IEEE 802.15.4/ZIGBEE规范规定了16各频道。用户可以

通过选择DEFAULT_CHANLIST不同的值可以选择不同的频道,其频道如图1-9

所示。改协议默认频道为0xB及0x00000800。

图1-9

DEFAULT_CHANLIST 和 ZDAPP_CONFIG_PAN_ID都作为IAR IDE中的编译

选项可以进行设置,在应用文件中的…ProjectsToolsCC2430DB目录下的

文件中有相应设置,如图1-10所示。

图1-10

学习Zstack之2

上节基本上初步认识了Zstack的一些情况,今天继续我的学习,打开Sample

例子看看,究竟ZIGBEE是怎么回事。

毫无疑问:如果是第一次打开这个例子工程,肯定很迷糊,因为此时我迷

糊了。对图2-1我简直是相当迷糊。

图2-1

这么多文件夹,打开之后又有那么多文件,从何看起?不要着急,特别是

有些人拿到之后,啥都不知道的人第一个问题就是:我要实现XXX,在哪修改

或者在哪添加我的函数呢?凡是我遇到这样的客户,我就可以肯定他技术部咋

的。就连我这个外行都知道,不把这些弄明白,就是实现XXX只需要修改一个

字母,那也不知道在哪改啊?所以我不急,但是我也理解很多客户,因为有时候

项目催的比较急,毕竟老板都是外行嘛!

两条路:1就是先看主函数,2就是看看TI提供例子说明文档没有。

我这里先看看主函数再说哈!因为我就知道从主函数看起.

没办法大概每个文件夹找啊,主函数的特征还是比较明明显的,见图2-2

所示:

图2-2

下面把主函数复制过来简单看下:

ZSEG int main( void )

{

// Turn off interrupts------------关闭中断

osal_int_disable( INTS_ALL );

// Initialize HAL-----------初始化HAL,关于HAL是什么我想后面会有介绍的。

HAL_BOARD_INIT();

// Make sure supply voltage is high enough to run----电压检测,最好是能保证芯片

能正常工作的电压

zmain_vdd_check();

// Initialize stack memory-------------初始化stack存储区

zmain_ram_init();

// Initialize board I/O------------初始化板载IO

InitBoard( OB_COLD );

// Initialze HAL drivers-------------初始化HAL驱动

HalDriverInit();

// Initialize NV System--------------初始化NV系统,NV是什么后面我想也会有介

绍的

osal_nv_init( NULL );

// Determine the extended address------------确定扩展地址(64位IEEE/物理地址)

zmain_ext_addr();

// Initialize basic NV items----------------初始化基本NV条目

zgInit();

// Initialize the MAC----------------初始化MAC

ZMacInit();

#ifndef NONWK

// Since the AF isn't a task, call it's initialization routine

afInit();

#endif

// Initialize the operating system----------初始化操作系统,看样子这里面还有OS,

麻烦了……..!

osal_init_system();

// Allow interrupts-------------允许中断

osal_int_enable( INTS_ALL );

// Final board initialization------------------最后的版在初始化

InitBoard( OB_READY );

// Display information about this device---------------显示设备信息

zmain_dev_info();

/* Display the device info on the LCD */------------液晶支持显示

#ifdef LCD_SUPPORTED

zmain_lcd_init();

#endif

osal_start_system(); // No Return from here-------------------这里没有返回,大概是进

入OS了。

} // main()

可以看到基本上都是初始化函数,因为函数名称都基本上带了init字样的,

呵呵,个人觉得TI的变成习惯比我好,一看名称就知道大概功能了。所以这里

也奉劝各位像我这样菜鸟级的初学者,一开始一定就要养成规范化编程的习惯,

据说这样维护以及以后升级或者移植兼容性都比较好。我就先不管各个初始化函

数是怎么实现的,我先看看各个功能是什么,现掌握整体功能在细化,我觉得这

样的学习方法比较好,因为代码是在太多了,从一开始就逐句看,我敢保证没几

个人有耐心看完看明白!

幸好每个初始化函数都有一句说明,虽然是英文的,但是理解起来一点都

不难的。关于每个函数的功能我就直接写在上面的程序里面,节省纸张哈!

一句话:主函数的功能就是初始化!

主函数看完了又开始模糊了,又从何看起呢?在无从下手之际,只有去寻

求TI说明文档的帮助了。上节不是漏掉了内容,是关于演示结果的,这里做上

补充,怕因为缺调一点后面遇到什么不理解的就惨了!

Sample例子演示演示现象:

1、认识硬件------------按键和LED

上节提到了EM和DB两个板子,其硬件是不一样的。按键EM就有5各

SW1~SW5,而DB只有1各方向键,但是他们有个对应关系,如图2-3所示.

图2-3

LED数量和颜色也不一样,EM有四个LED,如图2-4;而DB只有两个,

如图2-5。

如图2-4

如图2-5

关于上面几个图2-4/5中出现的LEDx实际上是程序中出现的关键字。

2、初始化64位IEEE地址

实际上在主函数中有这么个初始化函数的:zmain_ext_addr()。这里说如果

地址复位为0xFFFFFFFFFFFFFFFF的话,那么就会不停的闪烁LED1,一直等到

按键SW5按下后程序才能继续运行,意思就是说按下SW5后就把无效的地址初

始化为有效地物理地址了,这个应该是程序上实现的,那么就来看看对应的程序

zmain_ext_addr。

/********************************************************************

*

* @fn zmain_ext_addr

* @brief Makes extended address if none exists.确定扩展地址是有效的

* @return none

********************************************************************

*/

static ZSEG void zmain_ext_addr( void )

{

uint8 i;

uint8 led;

uint8 tmp;

uint8 *xad;

uint16 AtoD;

// Initialize extended address in NV初始化NV里的扩载地址

osal_nv_item_init(ZCD_NV_EXTADDR,Z_EXTADDR_LEN, NULL );

osal_nv_read( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, &aExtendedAddress );

// Check for uninitialized value (erased EEPROM = 0xFF)检查是否为无效值(地址)

xad = (uint8*)&aExtendedAddress;

for (i =0;i < Z_EXTADDR_LEN; i++ )

if(*xad++ != 0xFF ) return;-----如果有一个字节不为0xFF,那么该地址有效返回

#ifdef ZDO_COORDINATOR

tmp = 0x10;

#else

tmp = 0x20;

#endif

// Initialize with a simple pattern----------------简单初始化扩展地址

xad = (uint8*)&aExtendedAddress;

for ( i = 0; i < Z_EXTADDR_LEN; i++ )

*xad++ = tmp++;

// Flash LED1 until user hits SW5 ---------闪烁LED1直到SW5按下

led = HAL_LED_MODE_OFF;

while ( HAL_KEY_SW_5 != HalKeyRead() )---------------------SW5循环检测

{

MicroWait( 62500 );

HalLedSet( HAL_LED_1, led^=HAL_LED_MODE_ON );//Toggle the LED

MicroWait( 62500 );

}

HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );

// Plug AtoD data into lower bytes

AtoD = HalAdcRead (HAL_ADC_CHANNEL_7, HAL_ADC_RESOLUTION_10);

xad = (uint8*)&aExtendedAddress;

*xad++ = LO_UINT16( AtoD );

*xad = HI_UINT16( AtoD );

#if !defined( ZTOOL_PORT ) || defined( ZPORT ) || defined( NV_RESTORE )

// If no support for Z-Tool serial I/O,

// Write temporary 64-bit address to NV些临时的64位物理地址进入NV

osal_nv_write( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, &aExtendedAddress );

#endif

}

从程序中可以看出,一开始就检测FLASH中的物理地址,因为这个地址在

FLASH中是固定的存储空间,一旦为有效地址就退出函数,一旦为无效地址

(0xFFFFFFFFFFFFFFFF),那么就对其物理地址进行简单的初始化并检测SW5

按键。还是比较好理解的!

3、运行例子

在这里提到了跳线,由于本人采用的非TI原装硬件,没有该跳线,所以必

须对程序进行修改,否则检测不到跳线,连ZIGBEE的设备类型都不能确定,肯

定不能正常运行了。所以这里就先暂时不说了,这里要说的是一切都正常的情况

下,例子的验尸结果。小小跳跃一下。不然学习一直没有进展很麻烦的!

协调器:上电运行,地址检测如上面介绍的情况,通过之后呢-------就进行

通道扫描,此时LED1闪烁,一旦协调器成功建立网络,此时LED1停止闪烁,

而LED3被点亮。

路由器:上电运行,仍然是地址检测在前。之后就是通道扫描寻求是否又

存在的网络,此时LED1闪烁,一旦检测到存在网络并成功加入该网络,LED1

将停止闪烁,被替换的是LED3别点亮,也就表明路由器成功加入了网络。

那么此时能进行的操作控制是什么呢,也是最简单的表现手法---按键无线

控制LED:

周期(5S)发送信息到网络中每个设备

SW1按下,发送一个信息到组1的设备

SW2按下,退出/加入组1

这个我是经过验证的。如:

按下协调器SW1,路由器的LED1狂闪几下;按下路由器的SW1,那么协

调器的LED1也就狂闪几下;当然我是只有两个节点。

如果按1下协调器的SW2,在按下路由器的SW1,此时协调器就没有反应,

表明协调器已经退出组1;但是再按下协调器SW2在按路由器的SW1就与上一

步类似了。路由器与此类似可以通过SW2退出/加入组1.

终于把演示弄完了,接下来就来看看程序。在此之前还是来看看TI提供的

Sample指导文档。这个文档个人觉得写的不错,要是没看之前就看程序的却很

郁闷的!

但是本人英文很差,所以需要慢慢看,等点时间放上来!

Z-Stack之3

Sample Application分析(上)

1、Z-Stack CC2430DB and CC2430EB Sample Application

1.1、介绍

该文档时介绍TI协议入门的一个例子SampleApp的,适用EM和DB开发

板。

1.1.1、描述

这个例子是非常简单的演示,每个设备都可以发送和接收两个信息

周期信息-----加入该网络的所有设备每隔10S(可能会加上一个随机数的

mS)都发送一个周期信息,该信息的数据载荷为发送信息次数的计数。

闪烁控制信息---------通过按下SW1可以发送一个控制灯闪烁的广播信息,

该广播信息只针对组1的所有设备。

所有设备初始化为加入组1,所以网络一旦成功建立/加入就可以进行闪烁

控制。可以通过按下设备的SW2退出组1,所以可以通过退出组1可以不接受

闪灯信息。通过按下SW2也可以让不在组1的设备加入近组1,从而又可以接

受闪灯信息了。

这个理解应该不困难的,反正我理解没有什么障碍!

1.1.1.1、按键

SW1:发送闪烁信息到组1所有设备

SW2:转换推出/加入组1状态

1.1.2、用户应用开发

这里我基本上能看明白是什么,但是我不打算写出来,因为涉及到一些

ZIGBEE的关键术语,不是很明白。

大概就是简单介绍了下用户怎么利用例子做自己的应用,但是实用价值不

高,说的太笼统,全是概念性的说明。

1.2、OSAL任务

1.2.1、初始化

因为Z-Stack是在OS下运行的,所以在之前必须调用osalAddTasks()初始

化任务。

1.2.2、组织

关于OS的API函数介绍请看文档:Z-Stack OSAL API (F8W-2003-0002),

应该说协议栈的每层或者说每部分都有相关的API说明文档。osalAddTasks()初

始化任务,osalTaskAdd()函数添加任务,都可以到API文档或程序中详细分析函

数功能。

1.2.3、系统服务

OSAL和APL系统服务是唯一的,因为比如按键和串口类似事件处罚就只

能用唯一的一个任务标识。这两个硬件都留给了用户自己定义使用。

1.2.4、应用设计

用户可能为每一个应用对象都创建一个任务,或者为所有的应用对象只创

建一个任务。当选择上述的设计的时候,下面是一些设计思路:

1.2.4.1、为许多应用对象创建一个OSAL任务

下面是正面和反面(pros & cons)的一些叙述:

- Pro:接受一个互斥任务事件(开关按下或串口)时,动作是单一的。

- Pro:需要堆栈空间保存一些OSAL任务结构。

- Con:接收一个AF信息或一个AF数据确认时,动作是复杂的-----在一个

用户任务上,分支多路处理应用对象的信息事件。

- Con:通过匹配描述符(如:自动匹配)去发现服务的处理过程更复杂-----

为了适当的对ZDO_NEW_DSTADDR信息起作用,一个静态标志必须被维持。

1.2.4.2、为一个应用对象创建一个OSAL任务

一对一设计的反面和正面(pros & cons)是与上面一对多设计相反的:

- Pro:在应用对象试图自动匹配时,仅仅一个ZDO_NEW_DSTADDR被接

收。

- Pro:已经被协议栈下层多元处理后的一个AF输入信息或一个AF数据确

认。

- Con:需要堆栈空间保存一些OSAL任务结构。

- Con:如果两个或更多应用对象用同一个唯一的资源,接收一个互斥任务

事件的动作就更复杂。

1.2.5、强制方法

任何一个OSAL任务必须用两种方法执行:一个是初始化,另一个是处理

任务事件。

1.2.5.1、任务初始化

在例子中调用如下函数执行任务初始化:

―Application Name‖_Init(如SAPI_Init)。该任务初始化函数应该完成如下

功能:

变量或相应应用对象特征初始化,为了使OSAL内存管理更有效,在这里

应该分配永久堆栈存储区。

在AF层登记相应应用对象(如:afRegister())。

登记可用的OSAL或HAL系统服务(如:RegisterForKeys())

1.2.5.2、任务事件处理

调用如下函数处理任务事件:

―Application Name‖_ProcessEvent (e.g. SAPI_ProcessEvent()).除了强制的事

件之外,任一OSAL任务能被定义多达15个任务事件。

1.2.6、强制事件

一个任务事件SYS_EVENT_MSG (0x8000), 被保留必须通过OSAL任务设

计。

2.2.6.1、SYS_EVENT_MSG (0x8000)

任务事件管理者应该处理如下的系统信息子集,下面只列出了部分信息,

但是是最常用的几个信息处理,推荐根据例子复制到自己项目中使用。

1.2.6.1.1、AF_DATA_CONFIRM_CMD

调用AF_DataRequest()函数数据请求成功的指示。Zsuccess确认数据请求传

输成功,如果数据请求设置AF_ACK_REQUEST标志位,那么,只有最终目的

地址成功接收后,Zsuccess确认才返回。如果如果数据请求没有设置

AF_ACK_REQUEST标志位,那么,数据请求只要成功传输到下跳节点就返回

Zsuccess确认信息。

1.2.6.1.2、AF_INCOMING_MSG_CMD

AF信息输入指示

1.2.6.1.3、KEY_CHANGE

键盘动作指示

1.2.6.1.4、ZDO_NEW_DSTADDR

匹配描述符请求(Match Deor Request)响应指示。(例如:自动匹配)

1.2.6.1.5、ZDO_STATE_CHANGE

网络状态改变指示

1.3、网络格式化

示例应用程序编译为协调器的在default_chanlist指定的通道上形成一个网

络,协调器将建立一个随机编号源于自身的IEEE地址或由zdapp_config_pan_id

指定的网络PAN ID(如果zdapp_config_pan_id不为0xFFFF)。

示例应用程序编译为路由器或结束设备的将尝试加入网络在

default_chanlist指定的通道上,如果zdapp_config_pan_id没有定义为0 xFFFF ,

路由器将受到限制,只有加入参数zdapp_config_pan_id规定的网络PAN ID。

1.3.1、自动启动

设备自动开始尝试组建或加入网络。如果设备设置为等待计时器或其他外

部事件发生后才启动,那么HOLD_AUTO_START必须被定义。为了稍后以手动

启动方式启动设备,那么需要调用ZDApp_StartUpFromApp(函数

1.3.2、软件启动

为了在形成网络过程中节省所需的设备类型,那么所有的路由器设备可以

被通过soft_star定义作为一个协调器。如果自动启动是需要的话,那么

auto_soft_start必须被定义。

1.3.3、网络恢复

通过设置NV_RESTORE和/或NV_INIT,可以让设备断电或者意外掉电重

新启动后重新回复网络。

1.3.4、加入通告

当设备形成或加入网络后会发通报到ZDO_STATE_CHANGE信息事件。

学Z-Stack之4

Sample Application分析(下)

上节介绍了建立一个应用需要做的几个必须的事情,现在就来通过分析

Sample Application来具体看看需要做哪些事情,才能建立一个ZIGBEE应用功

能。当然这里只是做点简单的必须的工作。

The Sample Application (SampleApp)

1、介绍

主要是介绍一个应用建立的结构及需要进行的程序流程。

1.1、程序流程

1.1.1、初始化

首先需要调用初始化函数SampleApp_Init()。

SampleApp_TaskID = task_id;

初始化应用建立的任务ID号,其实用过OS的人都应该晓得这个是干啥的,

我没用过,不是很理解,但是我知道是必须的,就相当于一个任务的标识,这样

才能区分运行过程中不同任务中的不同事件。我是这么认为的,ID说白了就是

给该任务取了各名字,就向人名字一样,区分不同的人,就是一个代号。人名可

以重复,重复了有时候叫起来就容易混淆;所以才程序中为了避免这种混淆,就

强制性的规定任务ID不能重复。要是哪天国家或者联合国姓名管理委员会规定,

人民不能重复,那么这个人名就需要全球统一管理了。那给娃取个名字就要向联

合国姓名管理委员会申请了。呵呵!

SampleApp_NwkState = DEV_INIT;

初始化应用设备的网络状态。怎么说呢,据说是设备类型的改变都要产生

一个事件,叫ZDO_STATE_CHANGE,从字面理解为ZDO状态发生了改变。所

以在设备初始化的时候一定要把它初始化为什么状态都没有。那么它就要去检测

整个环境,看是否能重新建立或者加入存在的网络。但是有一种情况例外,就是

当NV_RESTORE被设置的时候(NV_RESTORE是把信息保存在非易失存储器

中),那么当设备断电或者某种意外重启时,由于网络状态存储在非易失存储器

中,那么此时就只需要恢复其网络状态,而不需要重新建立或者加入网络了。我

也是从文档中这么理解的,至于为什么只有有待进一步考证。

SampleApp_de = (afAddrMode_t)AddrNotPresent;

SampleApp_nt = 0;

SampleApp_ddr = 0;

看见这几句话从字面理解为:初始化不标设备地址模式及目标设备EP号和

网络地址。从代码可以看出,这些地址或EP均为0。也就是说目标设备为协调

者的ZDO,这个意义就很明显了,就是设备建立后可以直接与协调器的ZDO交

互信息。

SampleApp_nt = SAMPLEAPP_ENDPOINT;

----- SampleApp EP描述符的EP号

SampleApp__id = &SampleApp_TaskID;------ SampleApp EP描述符的

任务ID

SampleApp_Desc =------------------ SampleApp EP简单描述符

SimpleDeionFormat_t *)&SampleApp_SimpleDesc;

SampleApp_yReq = noLatencyReqs;

//在AF层中登记注册改应用EP

afRegister( &SampleApp_epDesc );

这里其实是对SampleApp的EP描述符进行初始化。

本人理解:要对改应用进行初始化并在AF进行登记,告诉应用层有这么一

个EP已经可以使用,那么下层要是有关于改应用的信息或者应用要对下层做哪

些操作,就自动得到下层的配合,至于这个配合是怎么回事,那么就需要好好研

究下层的协议了。当然在这里肯定是没那时间精力和能力研究了!

其实在这个应用中,只是让AF配合SAMPLEAPP_PROFID /

SAMPLEAPP_ENDPOINT这两个应用。那么通过什么呢,通过发送OSAL

SYS_EVENT_MSG消息中的(AF_INCOMING_MSG_CMD)事件到SampleApp任

务ID。

RegisterForKeys( SampleApp_TaskID );

登记按键事件到SampleApp_TaskID,在前面已经说了按键这个是唯一的,

也就是所有任务中有且只有各任务能登记键盘事件。前面还说了还有一个也是唯

一,你猜是什么?

SampleApp_ = 0x0001;

osal_memcpy( SampleApp_, ―Group1‖ );

aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );

闪灯信息被发送到组1,同样也只有在组1的设备才能接收这个信息。设备

启动时已经被设定为组1设备了,但是可以通过按SW1推出/加入组1。这里提

到了组的概念,我反正暂时不是很清楚这个是什么东西,在程序中怎么实现也很

模糊,但是应用中的好处还是不难想象的,不外呼是就是想控制谁可以事先规定

好,还可以动态更改。

1.2、事件处理

玩过OS的人都知道,OS中最重要的概念不外呼就是任务啦,消息啦,事

件啦等。从我们自己平时的工作中也不难想象,如果老板安排了某项工作,那么

我们就需要做的,这个工作可能是预先计划好的,也有可能是临时的,那么这些

预先定好或者临时的工作可以称之为事件。而老板让您做的方式,比如通过文件

下达,或者叫:某某你把XXX做下。那么让老板下达的文件内容或者说的内容

我这里可以称之为消息。老板给了你不同的消息那么就需要干不同的事件,至于

任务可以理解为公司的不同的员工,呵呵!我简直是理解的天才,这样举例居然

也能忽悠通过!!!o(∩_∩)o…哈哈

在Z-Stack中,每个应用任务都通过SampleApp_ProcessEvent()函数来处理

任务中的事件。一旦SampleApp_TaskID任务的某个OSAL事件发生,那么就可

以通过调用SampleApp_ProcessEvent()函数来处理。在SampleApp_ProcessEvent()

中有一个事件处理循环,循环检测是哪个事件发生。

if ( events & SYS_EVENT_MSG )

{

MSGpkt = (afIncomingMSGPacket_t*)osal_msg_receive( SampleApp_TaskID );

while ( MSGpkt )

{

可以看到是通过检测SYS_EVENT_MSG是否有事件信息发生。

switch ( MSGpkt-> )

这里是判断SYS_EVENT_MSG事件类型,不同的SYS_EVENT_MSG类型

需要不同的处理。

case KEY_CHANGE:

SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state,

((keyChange_t *)MSGpkt)->keys );

break;

比如这里判断是否是键盘事件,如果键盘事件就调用键盘处理函数。

如果一个OSAL任务已经被登记组侧,那么任何键盘事件都将接受一个

KEY_CHANGE事件信息。可能有如下几种方式得到键盘事件信息

1)、HAL检测到键盘按下(中断或者查询检测)

2)、HAL的OSAL任务检测到一个键盘状态改变调用回叫函数产生

3)、OSAL键盘改变回叫函数发送一个OSAL系统事件信息

(KEY_CHANGE)。

case AF_DATA_CONFIRM_CMD:

// The status is of ZStatus_t type [defined in ZComDef.h]

// The message fields are defined in AF.h

afDataConfirm = (afDataConfirm_t *)MSGpkt;

sentEP = afDataConfirm->endpoint;

sentStatus = afDataConfirm->;

sentTransID = afDataConfirm->transID;

任何AF_DataRequest()数据请求函数调用后,都通过AF_DATA_CONFIRM_CMD

系统事件信息回叫返回成功Zsuccess。

case ZDO_STATE_CHANGE:

SampleApp_NwkState = (devStates_t)(MSGpkt->);

if ( (SampleApp_NwkState == DEV_ZB_COORD)

||(SampleApp_NwkState == DEV_ROUTER)

||(SampleApp_NwkState == DEV_END_DEVICE) )

{

// Update the LCD’s network indicator

// Start sending "the" message in a regular interval.

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );

}

break;

这里就是前面介绍的设备状态改变事件处理了。

只要网络状态发生改变,那么通过ZDO_STATE_CHANGE事件通知所有的

任务。注意:在这个例子中,一旦设备成功加入网络,是通过定时运行的方式运

行的。一旦网络状态为加入‖JOINED‖,那么它可能不需要任何的认为操作就能绑

定其他设备,因为设置为自动发现并绑定的。

// Release the memory

osal_msg_deallocate( (uint8 *)MSGpkt );

释放存储空间。

if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )

{

// Send "the" message

SampleApp_SendPeriodicMessage();

// Setup to send message again

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_MSG_TIMEOUT );

// return unprocessed events

return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);

}

这里检测事件是否为周期发送信息事件。

在SampleApp.h中定义了:

#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT 0x0001

在这个应用中,调用了osal_start_timer()函数来定时产生发送周期信息事件。而

定时器的运行是设备一旦加入网络就不停的在运行。从上面可以看到,用函数

SampleApp_SendPeriodicMessage()发送周期信息,而用函数

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEN

D_MSG_TIMEOUT )来继续运行定时器定时发送这个周期信息。关于这个

osal_start_timer可以多了解下,第一个参数

SAMPLEAPP_SEND_PERIODIC_MSG_EVT四信息时间,也就是事件到了产生

一个什么事件。第二各参数SAMPLEAPP_SEND_MSG_TIMEOUT是需要定时的

时间,这里就是发送周期信息的时间周期。

1.3、消息流程

通过OSAL定时器,这个应用定时发送一个周期信息:

void SampleApp_SendPeriodicMessage( void )

{

afAddrType_t dstAddr;

dstAddr. addrMode = afAddrBroadcast;

ddr = 0xFFFF; // 广播发送

dstAddr. endpoint = SAMPLEAPP_ENDPOINT;

if ( AF_DataRequest( & dstAddr, &SampleApp_epDesc,

SAMPLEAPP_PERIODIC_CLUSTERID,

(uint8)sampleAppPeriodicCounter++,

(uint8 *)&sampleAppPeriodCounter,

&SampleApp_TransID,

AF_DISCV_ROUTE,

AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )

{

// Successfully requested to be sent.----发送成功处理

}

else

{

// Error occurred in request to send.---发送失败处理

}

}

在这里调用了AF_DataRequest()函数用来发送数据。关于发送数据的具体过

程这里就不做深入研究,不外乎就是把数据从应用层传到网络层,在传到MAC,

在传到无力层,最后通过OTA发送出去。接收数据就是相反的过程了,那么接

收之后,在应用层有什么反应呢,最直观的反应就是会发送一个

AF_INCOMING_MSG_CMD消息事件。

case AF_INCOMING_MSG_CMD:

SampleApp_MessageMSGCB( MSGpkt );

break;

这里表示收到某个信息,然后在里面调用了收到信息的信息处理函数

SampleApp_MessageMSGCB( MSGpkt )。

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

switch ( pkt->clusterId )

{

case SAMPLEAPP_PERIODIC_CLUSTERID:

// Display and increment a counter on the LCD in the periodic space

break;

case SAMPLEAPP_FLASH_CLUSTERID:

flashTime = BUILD_UINT16(pkt->[1], pkt->[2] );

HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );

break;

}

}

这里判断了两种信息:

周期信息

闪灯信息

不同的信息就相当于收到了不同的命令,然后根据不同的命令做出了不同

的处理。是个会写程序都明白!!!!

到这里,我就基本上把这个应用文档看完了,至于理解了多少我迷糊,理

解正确了多少我更加迷糊,反正我按照我自己的方式理解了!

学Z-Stack之5

前面虽然写了不少,但是回头看看大多都是废话,不过也没办法,没有废

话的润色就太枯燥了,太技术化了,这个不是我的本意。不知道前面写的怎么样,

技术含量肯定是不高的。这个本人是相当清楚,但是我最大的期望就是错误不要

太多!

突然想起来前面有个问题没有解决,我想很多人看到那里都很郁闷的。就

是设备类型的选择,在TI原装系统上是通过板载跳线来选择的,但是我这里不

是采用原装,那么就需要通过程序来修改其设备类型,然后编译下载。具体程序

段如下:

#if defined ( SOFT_START )

if ( readCoordinatorJumper() )

zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;

else

zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;

#endif // SOFT_START

这里有个条件编译,其条件编译设置如图5-1。

图5-1

既然这里设置了SOFT_START,那么上段程序就要被编译。那么第一句程序

if ( readCoordinatorJumper() )

就是检测跳线,其实稍微知道编程的都了解怎么修改了,哈哈!

屏蔽:

if ( readCoordinatorJumper() )

zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;

else

这3句,那么就只剩下:zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;

那么编译自然该设备就为路由器了。简单吧!!!!??!

协调器我就不想多说怎么做了哈!!!!!!!!!!!!

还有一个问题需要说下,就是Ti原装的EM板子用到了LCD,所以在程序中

可能在某个地方要对LCD初始化,那么如果没有液晶的板子或者与TI那个不完

全一样的LCD就有可能运行不走,通俗的解决办法是禁止LCD初始化等操作,

Ti在这个方面做的很人性化,禁止LCD功能没有必要在程序中找到LCD相关程

序删除,而是仅仅需要通过条件编译来禁止。显得相当简单,如5-2图就是禁止

LCD的条件编译。

图5-2

解决这个问题后一般都能够运行程序了。也就是说到这里如果还把Demo

程序运行不起来的话,那就证明我所有的东西都白写了,反正我到这里我的Demo

程序已经运行如飞了。

那么接下来就是来看看Z-Stack具体的一些东西了,我打算先这样看起:

1、Z-Stack的结构,因为打开Z-Stack的目录可以看出还是比较复杂的,只

有比较清楚了解其结构之后呢,在程序运行或者修改中才能顺利的找到自己想要

的部分。

2、Z-Stack的应用建立。就是怎么在TI提供的协议(裸协议)上建立一个

应用。这个层次要求就比较高了,我初步的设想是希望能分析完SAMPLE例子

的应用就能自己建立,而不需要太多的去了解下层的协议。但是往往希望与现实

是有偏差的,走一步算一步了。

3、了解硬件相关设定、驱动。也就是说把例子跑通了,毕竟是基于TI的

硬件,或者说基于开发系统的硬件,如果要做自己的应用,那么必须要开发自己

的硬件。怎么把自己的硬件驱动加入协议,这个我想也是需要解决的问题。

4、接下来可能就要深入分析协议了,这个目前我还不清楚从什么地方看起,

因为毕竟对ZIGBEE这个协议本身就不太了解,但是在学习过程中应该会慢慢对

它有认识。所以到了这一步的时候说不定我就已经摸索出一条方法了---毕竟俺是

相当的聪明嘛!

5、需要解决的问题,需要了解的东西很多,对于不太了解这个东西的我来

说,不可能非常有计划并统筹安排这些事,走弯路是必然的,但是我一致认为走

弯路才是经验的积累!

学习Z-Stack之6

--------------Z-Stack指导

首先来看看Z-Stack的结构。

第一次打开工程印象最深刻的就是左边一排文件夹,如图6-1所示。

其实这个还是很容易理解的:

APP(Application Programming):应用层目录,这是用户创建各种不同工程的区域,

在这个目录中包含了应用层的内容和这个项目的主要内容,在协议栈里面一般是以操作系统

的任务实现的。

HAL(Hardware (H/W) Abstraction Layer):硬件层目录,包含有与硬件相关的配置和驱

动及操作函数。

MAC:MAC 层目录,包含了MAC 层的参数配置文件及其MAC 的LIB 库的函数接

口文件。

MT(Monitor Test):实现通过串口可控各层,于各层进行直接交互。

NWK(ZigBee Network Layer):网络层目录,含网络层配置参数文件及网络层库的函

数接口文件,APS层库的函数接口

OSAL(Operating System (OS) Abstraction Layer):协议栈的操作系统。

Profile:AF(Application work)层目录,包含AF层处理函数文件。

Security:安全层目录,安全层处理函数,比如加密函数等。

Services:地址处理函数目录,包括着地址模式的定义及地址处理函数。

Tools:工程配置目录,包括空间划分及ZStack 相关配置信息。

ZDO(ZigBee Device Objects):ZDO 目录。

ZMac: MAC 层目录,包括MAC 层参数配置及MAC 层LIB 库函数回调处理函数。

ZMain:主函数目录,包括入口函数及硬件配置文件。

Output:输出文件目录,这个EW8051 IDE 自动生成的。

那么知道各个文件夹大概是什么功能,分布在ZIGBEE的哪一层,那么在以后的工作

中无论是查询某些功能函数还是修改某些功能函数,甚至是添加或删除某些功能函数就能顺

利的找到在什么地方了,当然要想真的顺利还需要花更多的时间熟悉这个协议栈了!

了解Z-Stack结构后那么就能看看它的功能。

不用问,这个是针对ZIGBEE无线网络写的协议栈,呵呵!那么就要先大概了解下

ZIGBEE这个技术。我这里就不介绍理论了,就从Z-Stack实际的角度介绍些实用的概念。

1、Zigbee网络中的节点

在ZB网络中,每个节点都有指定的配置参数,从而确定其设备类型,不同的设备类型,

在网络中有着不一样网络任务。在属于多跳网络的ZB网络中,两个节点需要完成数据传输,

可能需要经过其他中间节点的协助,所以节点的类型参数配置是非常必要的。

对每个节点有两个任务:

(i)执行指定的网络功能函数

(ii)配置确定的参数到指定的值。

网络功能的设置确定了该节点的类型,参数配置和指定的值确定了堆栈的模式。

节点类型

在ZB中,设备类型分为三类:协调器,路由器和终端设备。

图6-2就是这三种设备类型组成的一个典型网络。

其中黑色节点为协调器

红色节点为路由器

白色节点为终端设备

那么这个就是一个典型的网状网络MESH。

协调器

协调器是一个ZB网络的第一个开始的设备,或者是一个ZB网络的启动或建立网络

的设备。协调器节点选择一个信道和网络标志符(也叫PAN ID),然后开始建立一个网络。

协调器设备在网络中还可以有其他作用,比如建立安全机制、网络中的绑定的建立等等。

注意:协调器主要的作用是建立一个网络和配置该网络的性质参数。一旦这些完成,该协调

器就如同一个路由器,网络中的其他操作并不依赖该协调器,因为ZB是分布式网络。

路由器

一个路由器的功能有(1)作为普通设备加入网络(2)多跳路由(3)辅助其它的子

节点完成通信。

一般来说,路由器需要一直处于工作状态,所以需要主干线供电(区别于电池供电)。

但是在某指定的网络结构中可以采用电池供电,如―串树型‖网络模式中,允许路由器周期的

运行操作,所以可以采用电池供电。

终端设备

为了维持网络最基本的运行,对于终端设备没有指定的责任。也就是说,在一个基本

网络中,终端设备没有必不可缺少性。所以它可以根据自己功能需要休眠或唤醒,因此为电

池供电设备。一般来说,该设备需要的内存较少(特别是内部RAM)

堆栈模式(Stack Profile)

需要被配置为指定值的堆栈参数,连同这些值被称为堆栈模式。这些堆栈模式参数被

ZB联盟定义指定。在同一个网络中的设备必须符合同一个堆栈模式(同一个网络中所有设

备的堆栈模式配置参数必须一致)。

为了互操作性,ZB联盟为06协议栈定义了一个堆栈模式,所有的设备只要遵循该模

式的参数配置,即使在不同厂商买的不同设备同样可以形成网络。

如果应用开发者改变了这些参数配置,那么他的产品将不能与遵循ZB联盟定义模式

的产品组成网络,也就是说该开发者开发的产品具有特殊性,我们称之为―关闭的网络‖,也

就是说它的设备只有在自己的产品中使用,不能与其他产品通信。

该协议模式标志符在设备通信的信标传输中被匹配,如果不匹配,那么该设备将不能

加入网络。―关闭网络‖的堆栈模式有一个0ID,而06协议栈模式有一个1ID。该堆栈模式被

配置在nwk_globals.h文件中的STACK_PROFILE_ID参数。如:

#define STACK_PROFILE_ID HOME_CONTROLS。

2、Zigbee网络中的地址

地址类型

ZB设备有两种地址类型,一个是64位IEEE地址(也可以叫MAC地址或扩展地址),

一个是16位网络地址(也可以叫逻辑地址或短地址)。

64位地址是全球唯一的,作为设备(产品)的终生地址被分配。它通常被开发商或安

装的时候被指定。该地址由IEEE分配指定,该地址的信息和获得该地址的方法见:

/regauth/oui/

16位地址在设备加入网络的时候被分配,由这个网络自动分配。该地址只能用与本网

络中,标志不同的设备间传递信息。

网络地址分配

ZB分布式网络中地址分配是唯一的。为了不使网络中设备混乱,为每个设备指定确

定的地址是非常必要的。

在分配地址之前,一些参数必须被设置:MAX_DEPTH, MAX_ROUTERS 和

MAX_CHILDREN 。

这些参数都是ZB协议模式的一部分,在06ZS模式中这些参数设置为: (MAX_DEPTH

= 5, MAX_CHILDREN = 20, MAX_ROUTERS = 6).

参数设置

MAX_DEPTH决定了网络的最大深度。协调器的深度是0,它的子设备的深度是1,

他们的子设备的深度是2,依次类推。所以MAX_DEPTH参数限制了网络物理上的―长度‖

MAX_CHILDREN参数决定了一个路由器(或一个协调器)能承载子设备的最大数目。

MAX_ROUTERS参数决定了一个路由器(或一个协调器)能承载路由器的最大数目。

这个参数实际上是MAX_CHILDREN参数的一个子集,剩下的

(MAX_CHILDREN-MAX_ROUTERS)地址空间属于终端设备。

开发者自定义

如果开发者想改变这些值,那么需要做如下几步:

首先得保证这些参数新的值是合法的。既然整个地址空间被限制在2-16内,那么这些

参数的大小就已经有了限制。分布在release(在文件夹ProjectszstackTools中)的

文件能校验这些参数是否合法。在键入这些参数的值后大概这个电子表格,如果非法,一个

错误信息将给出。

之后选择合法的值,开发者需要确保不使用标准的协议栈模式,而用指定的协议栈模

式代替(用NETWORK_SPECIFIC替换STACK_PROFILE_ID当前的值)。然后在

―nwk_globals.h‖文件中的MAX_DEPTH参数根据需要设置为适当的值。

另外,nwk_globals.c文件中排列的CskipChldrn和CskipRtrs必须被设置,这些排列是

z-stack中的寻址

为了在网络中发送数据到一个设备,应用层一般用AF_DataRequest()函数。而被发送

的目的设备的地址类型afAddrType_t被定义在―ZComDef.h‖中:

typedef struct

{

union

{

uint16 shortAddr;

ZLongAddr_t extAddr;

} addr;

byte addrMode;

} zAddrType_t;

地址模式参数

注意:除这个网络地址之外,地址模式参数也需要被指定。目的地址模式可能是如下值之一

(AF地址模式被定义在―AF.h‖中):

typedef enum

{

afAddrNotPresent = AddrNotPresent,

afAddr16Bit = Addr16Bit,

afAddrGroup = AddrGroup,

afAddrBroadcast = AddrBroadcast

} afAddrMode_t;

地址模式参数是需要的,因为在ZB中,数据包能被点传输、多点传输或者广播传输。

点传输被发送到单个设备,多点传输一定发送到一组设备,广播传输一般被发送到网络中的

所有设备。如下是更详细的说明。

点到传输 (Unicast)

这是标准地址模式,被用于发送一个数据包到网络中单个已知地址的设备。这个

addrMode参数被设置为Addr16Bit,目的网络地址在数据包中一同被发送。

间接寻址

数据包中的最终目的地址不识别的时候使用。该模式被AddrNotPresent设置,而且目

的地址没有被指定。代替目的地址的是:一个存储在发送设备协议栈的―绑定表格‖,该表格

中有被绑定设备的地址。这个特性被调用是源于绑定。(看后面关于绑定部分)

当被发送的信息包下载到协议栈时,从这个绑定表格中寻找使用的目的地址。然后该信息包

被有规则的处理为点对点数据包。如果有多个(大于1)目的地址在绑定表格中被发现,那

么该数据包将被拷贝成对应的份数分别发送给他们。

在(ZigBee04)版本之前,在协调器中有一个存储绑定表格的选项。因此,发送设备发

送数据包到这个协调器,然后协调器在它的绑定表格中查找最终的目的地址,对数据包进行

在一次发送。该选项特性在协调器绑定被调用

广播传输

该模式在应用层想发送一个数据包到所有网络中的所有设备时被使用。该地址模式被

AddrBroadcast被设置,目的地址被设置为下列值之一:

NWK_BROADCAST_SHORTADDR_DEVALL (0xFFFF)-信息将被发送到网络中的所有设备

(包括休眠的设备)。对于休眠的设备,这个信息将被保持在它的父节点,直到该休眠设备

获得该信息或者该信息时间溢出(在 中的NWK_INDIRECT_MSG_TIMEOUT

选项)。

NWK_BROADCAST_SHORTADDR_DEVRXON (0xFFFD) –该信息将被发送到网络中有接

收器并处于IDLE(RXONWHENIDLE)状态下的所有设备。也就是说,除了休眠模式设备的

所有设备。

NWK_BROADCAST_SHORTADDR_DEVZCZR (0xFFFC) –该信息被发送到所有路由器(包

括协调器) 。

组地址

该模式用于应用层想发送一个数据包到一个设备组的时候。该地址模式被

afAddrGroup设置这个组标志符。

用该特性之前,在网络中,组不得不被定义[看ZStack API文档中的] aps_AddGroup()

注意:组能与间接寻址一起结合使用。该目的地址在绑定表格中发现,可以作为点对点或一

个组地址。也要注意广播地址可以当作是组被提前设置,一个简单的组寻址的特例,。

例子代码对于一个设备添加它自己到一个组标志符1:

aps_Group_t group;

// Assign yourself to group 1

= 0x0001;

[0] = 0; // This could be a human readable string

aps_AddGroup( SAMPLEAPP_ENDPOINT, &group );

重要设备地址

一个应用可以能想知道它自身和父节点的地址,用下面的函数可以得到设备的地址

(被定义在ZStack API文档中):

NLME_GetShortAddr() – 返回该设备的 16 位网络地址

NLME_GetExtAddr() –返回该设备的64 位扩展地址.

用下面的函数可以得到该设备的父节点的地址(被定义在ZStack API文档中)。注意该函数

在协调器中不被涉及到,但是被设备父节点代替(MAC协调器):

NLME_GetCoordShortAddr() – returns this device’s parent’s 16 bit short address.

NLME_GetCoordExtAddr() – returns this device’s parent’s 64 bit extended address.

先介绍这两个概念:节点和地址。其余的就改天继续!

学习Z-Stack之7

--------------Z-Stack指导2

上节介绍了很大一部分Z-Stack的基础知识,这里接着忽悠。虽然说的不是

很专业也不是很通俗,但是我尽力了,希望有人能看明白!本人英文水平有限,

翻译的不好请谅解!

3、绑定

绑定是控制信息从一个应用层到另一个应用层流动的一种机制。在ZB06

版本中,绑定机制在所有的设备中被执行。

绑定允许应用层发送信息不需要带目的地址,APS层确定目的地址从他的

绑定表格中,然后在信息前端加上这个目的地址或组。

注意:在ZB1.0版本中,所有绑定条目存储在协调器中。现在所有绑定条

目存储在发送数据的设备中。

3.1绑定一个绑定表格

有三种方式建立一个绑定表格:

ZDO 绑定请求 – 一个试运转工具能告诉这个设备制作一个绑定报告。

ZDO 终端设备绑定请求 – 2设备能告诉协调器他们想建立绑定表格报告。

该协调器将使协调并在这两个设备上创建绑定表格条目

设备应用 – 在设备上的应用能建立或管理一个绑定表格 。

任何一个设备或应用能在网络中发送一个ZDO信息到另一个设备()建立

一个绑定报告。这是调用绑定帮助并且它将建立一个绑定条目为发送设备。

3.1.1 ZDO 绑定请求

通过调用函数ZDP_BindReq()发送一个绑定请求。第一个参数(dstAddr)

是绑定的源地址的短地址。这之前应该确定允许绑定,在ZDConfig.h 文件中有

参数[ZDO_BIND_UNBIND_REQUEST]允许绑定。能用同样的参数调用函数

ZDP_UnbindReq()移除绑定。

目标设备将调用函数ZDApp_BindRsp()或 ZDApp_UnbindRsp(),反馈绑定

或移除绑定的响应,返回其操作状态为ZDP_SUCCESS, ZDP_TABLE_FULL或

ZDP_NOT_SUPPORTED.

3.1.2 ZDO 终端设备绑定请求

该机制是用一个按钮按下或其他类似的动作来选择设备在指定时间内被绑

定。在规定时间内,该终端设备绑定请求信息被收集到协调器,并创建一个基于

模式(profile) ID 和串(cluster) ID的规定的绑定表格条目。默认的终端设

备绑定超时时间(APS_DEFAULT_MAXBINDING_TIME)为16S(定义在

nwk_globals.h中),但是能被改变

发送绑定请求

在所有的应用例子中有一个处理键盘事件的函数[例如在TransmitApp.c文

件中的TransmitApp_HandleKeys()函数]。在该函数中,调用了函数

ZDApp_SendEndDeviceBindReq()[在ZDApp.c中],它将收集应用的终端设备的

所有信息并调用函数ZDP_EndDeviceBindReq() [ZDProfile.c],发送一个绑定信息

到协调器。或者,在SampleLight 和 SampleSwitch例子中,直接调用

ZDP_EndDeviceBindReq()函数就实现点亮/关闭灯的功能。

接收绑定请求

协调器将接收[ZDP_IncomingData() 在 ZDProfile.c]这些信息并分析处理

[ZDO_ProcessEndDeviceBindReq() 在 ZDObject.c]这些信息并调用函数

ZDApp_EndDeviceBindReqCB() [in ZDApp.c],它将调用

ZDO_MatchEndDeviceBind() [ZDObject.c]处理这个请求

当协调器接收到2个匹配终端色后备的绑定请求时,它将启动在绑定设备

上创建源绑定条目的处理过程。该协调器有如下处理过程:

解除绑定

1. 发送一个ZDO解除绑定请求到第一个设备。终端设备绑定切换处理,所

以解除绑定首先被发送到移除一个存在的绑定条目。

2. 等待ZDO解除绑定响应,如果响应状态为ZDP_NO_ENTRY, 发送一个

ZDO绑定请求,在源设备上制作一个绑定条目 。如果该响应为ZDP_SUCCESS,

为第一个设备继续到move on to the cluster ID for the first device (the unbind

removed the entry – toggle).

3. 等待ZDO绑定响应. When received, move on to the next cluster ID for the

first device.

4. 当第一个设备完成时,对第二个设备做同样的处理。

5. 当第二个设备完成时,发送ZDO 终端设备绑定响应信息到第一个和第

二个设备

3.1.3设备应用绑定管理

在设备上其他进入绑定条目的方式是应用层管理绑定表格。

意思是说,应用层将调用下列函数进入和移除绑定表格条目:

bindAddEntry() –增加绑定表格条目

bindRemoveEntry() – 从绑定表格中移除条目

bindRemoveClusterIdFromList() – 从一个存在的绑定表格项目中移除一个串

ID 。

bindAddClusterIdToList()——向一个已经存在的绑定记录中增加一个群ID

bindRemoveDev()——删除所有地址引用的记录

bindRemoveSrcDev()——删除所有源地址引用的记录

bindUpdateAddr()——将记录更新为另一个地址

bindFindExisting()——查找一个绑定表记录

bindIsClusterIdInList()——在表记录中检查一个已经存在的群ID

bindNumBoundTo()——拥有相同地址(源或者目的)的记录的个数

bindNumEntries()——表中记录的个数

bindCapacity()——最多允许的记录个数

bindWriteNV()——在NV中更新表

3.2 配置源绑定

允许绑定源的编译选项REFLECTOR在文件中。在文件

,中查看这两个绑定配置参数(NWK_MAX_BINDING_ENTRIES &

MAX_BINDING_CLUSTER_IDS)。NWK_MAX_BINDING_ENTRIES绑定表格

中最大的绑定实体数量参数;MAX_BINDING_CLUSTER_IDS 是在每个绑定实

体中最大的串ID数量。

绑定表在静态RAM中(未分配),因此绑定表中记录的个数,每条记录中群

ID的个数都实际影响着使用RAM的数量。每一条绑定记录是8字节多

(MAX_BINDING_CLUSTER_IDS * 2字节)。除了绑定表使用的静态RAM的数

量,绑定配置项目也影响地址管理器中的记录的个数。

4、路由

4.1 预览

在MESH网络中,为了使分布的节点间能够很好的通信,路由是非常重要

的一个环节。

在应用层上路由是完全透明的。一个简单的应用数据发送到任意设备,下

至协议栈,协议栈将负责发现一个路由路线。这个方式,应用层是不知道该操作

在多跳网络中完成的事实。

路由使ZB网络具有―自动复原‖的特性。如果一个无线连接断了,路由功能

将自动的发现一个新的路由路线,该路线是避开(绕过)坏了的那个连接节点。

这就提高了无线网络的可靠性,这也是ZB关键特点之一。

4.2 路由协议

ZB执行的路由协议是基于AODV(Ad hoc On demand Distance Vector)的

路由协议。作为一个简单的应用---传感器网络,ZB路由协议支持环境中的移动

节点,连接失败和丢包功能。

当一个路由器接收到一个点对点信息包时,从他的应用或者从其他设备,

NWK层将继续向前依照下面的进程。如果目的是路由器邻节点(包括它的子设

备)之一,该信息包将直接传输到目的设备。另外的就是,路由器将检查它的路

由表格,检查相应的信息包目的条目。如果在路由表格中有一个活跃的路由路线

到该目的设备,那么该信息包将被转播到下一跳节点地址存储依照路由条目。如

果没有活跃的条目发现,那么一个路由发现被启动并且该信息被缓存直到该过程

完成。

ZB终端设备路由

ZB终端设备不能执行任何路由功能。一个终端设备想发送一个信息包到任

何设备都要向前到它的父设备,然后在由其父设备进行路由操作。类似的,任何

设备想发送信息包到终端设备,都将发起一个路由发现操作,当然该操作都由终

端设备的父设备响应。

注意:ZB地址分配方案使基于它的地址发起一个路由到任何目的成为可

能。在Z-Sstack,这个机制被用于万一正规的路由程序不能被启动,作为一个自

动退却(一般情况是由于路由表格空间不够)。

z-stack路由

在z-stack,执行的路由是已经被优化的路由存储表格。一般情况,对于每

一个目的设备路由表格条目是需要的。但是通过综合携带父节点所有条目的特定

父节点的终端设备的所有条目,没有任何功能丢失的存储已经被优化。

ZB路由器,包括协调器,执行如下路由功能 (i)路由发现和选择 (ii) 路由

维护(iii)

4.2.1路由发现和选择

路由发现是网络设备协作发现和建立路由的一个过程。一个路由操作总是

针对某个目的,通过任何一个路由器启动。该路由发现机制在源设备和目的设备

间搜寻所有可能的路由并试图选择最好的路由路线。

? 路由选择通过选择最小消耗的路由路线。每个设备在连接到邻节点几乎保持不

变的―连接消耗‖。该连接消耗是接收信号的强度的一个典型功能。沿着路由路线

加起所有的连接消耗,就是整个路由的―连接消耗‖。路由算法试图选择这个路由

最小的―路由消耗‖。

路由请求

路由通过请求/响应信息包被发现。一个源设备为了一个目的地址,通过发

送一个广播路由请求(RREQ)信息到它的邻设备请求一个路由。当一个节点接

收到一个RREQ信息时,它将依次转播这个RREQ信息。但是在做这个之前,

它更新RREQ信息的消耗域,通过增加连接消耗为了最后的连接。这样,RREQ

信息将携带向前传输的所有的连接消耗。这个重复过程直到RREQ到达这个目

的设备。RREQ的一些复制可能经过不同的路径重复到达目的设备。该目的设备

选择最好的RREQ信息并发送一个路由答复(RREP)返回到源设备。

路由响应

RREP是沿着唯一的相反的路径返回到最初的请求节点。

作为RREP信息传播回源节点,中间的节点更新他们的路由表格,指出路

由路线到目的设备。

一旦一个路由被创建,数据包能被发送。当一个节点丢失到它下一个节点

的连通性时(发送数据包时,它不能接收一个MAC应答ACK),这个节点通过

发送一个RERR到所有潜在的接收它RREP的节点,使该路由无效。在接收一

个RREQ,RREP或RERR之上,这些节点都将更新他们的路由表格

4.2.2路由维护

MESH网络提供路由维护和自动修复。中间节点保持沿着连接传输失效的

路径。如故一个连接被确定坏了,逆流的节点将启动路由修复那些连接的所有路

由路线。这些工作通过启动路由重新发送被做,为了路由下一次数据包接收。如

果路由重新发现不能启动,或者由于某些原因失败了,一个路由错误(RERR)

信息被发送到这个数据包的源设备,然后重新启动新的路由发现。任意方式都使

得该路由得到重新自动建立。

4.2.3路由终结

为了建立路由,路由表格条目要被维护。如果一段时间没有数据包沿着路

由路线发送,该路由将被做终结记号。终止路由不是删除直到空间需要时。因此

没有被删除直到它完全需要时。自动路由终结时间能被配置―在"文

件中‖。设置ROUTE_EXPIRY_TIME参数为终结时间(秒)。设置0为了关闭路

由终结。

4.3 表格存储

路由功能需要路由器维护一些表格:

路由表格

路由发现表格

4.3.1路由表格

每一个路由器包括协调器都包含一个路由表。设备在路由表中保存数据包

参与路由所需的信息。每一条路由表记录都包含有目的地址,下一级节点和连接

状态。所有的数据包都通过相邻的一级节点发送到目的地址。同样,为了回收路

由表空间,可以终止路由表中的那些已经无用的路径记录。

路由表的容量表明一个设备路由表拥有一个自由路由表记录或者说它已经

有一个与目标地址相关的路由表记录。在文件―‖文件中配置路由表

的大小。将MAX_RTG_ENTRIES设置为表的大小(不能小于4)。

4.3.2路由发现表格

路由器设备致力于路径发现,保持维护路径发现表。这个表用来保存路径

发现过程中的临时信息。这些记录只在路径发现操作期间存在。一旦某个记录到

期,则它可以被另一个路径发现使用。这个值决定了在一个网络中,可以同时并

发执行的路径发现的最大个数。这个可以在文件中配置MAX_

RREQ_ENTRIES。

4.4、路径设置快速参考

设置路由表大小MAX_RTG_ENTRIES,这个值不能小于4 (

文件)

设置路径期满时间ROUTE_EXPIRY_TIME,单位秒。设置为零则关闭路径期满

(文件)

设置路径发现表大小 MAX_RREQ_ENTRIES,网络中可以同时执行的路径

发现操作的个数

学习ZStack之8

近段时间比较忙,几乎都快荒废了Z-Stack的学习了,把以前学的都快忘记

了,这就是非专业技术的痛苦啊!!学习刚好有点眉目,突然意外中断停下,当

再一次学习的时候突然发现:以前学的都忘了8成了!郁闷啊!今天真不知道从

什么地方下手学习了,所以就针对最近客户比较关心的问题做点介绍,这样有针

对性、有目的性的学习可能最适合现在的我了,不然从头把以前那些所谓的笔记

看一遍,可能今天晚上又没了,指不定明晚以及后晚以及后后晚…都没时间,不

然老是看以前的笔记没有进展就麻烦了!呵呵!

今天只解决1个问题:TI提供的例子程序的表演及功能介绍。

因为最近问这些的客户比较多,特别又是刚入手的朋友,对Z-Stack非常迷

糊的时期,如果能够跑通几个例子、看几个演示,那么可以大大提高学习兴趣;

另外如果知道某个例子的大致功能及实现,那么在去看具体实现过程目的性就非

常明确。

首先来看看TI究竟有哪些例子:

可以看出其例子是非常丰富的。

GenericApp,Location,SampleApp,SimpleApp,HomeAutomation,SerialApp,

Transmit,

ZLOAD。这样看来还是不少的。其中SampleApp例子已经在前面的学习中有所

涉及,可以说前面的所有学习都是基于这个例子的,所以这里就不测试它了。

Location是定位的测试例子,这里我的硬件是不够的,所以也不做测试。其他我

都做点测试,能成功的就成功,不能成功的就失败,这个我也没办法,呵

呵!!!!!!!!

1、GenericApp

工程打开等我就不多说了,自己去找,如果连这些我都还说,那么我以前

的东西是白学了。硬件连接中

当我用两个节点分别烧写入DB的协调器和路由器,从我的经验看来,他

们分别能建立网络和加入网络,但是从表象上几乎看不见数传现象,尽管我按了

每个节点的按键,也仅仅是本节点的LED在改变。唯独有点数传感觉的是:按

键右键对方有反应就是了,至于具体什么反映我觉得没必要说明白,大家试试就

知道了。

所以还决定看看程序来判断这个例子的功能。

大约浏览了下,这个例子似乎还与设备的绑定有关系,因为在按建处理程

序中发现:

if ( keys & HAL_KEY_SW_2 )

{

HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );

// Initiate an End Device Bind Request for the mandatory endpoint

de = Addr16Bit;

ddr = 0x0000; // Coordinator

ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),

GenericApp_nt,

GENERICAPP_PROFID,

GENERICAPP_MAX_CLUSTERS, (cId_t

*)GenericApp_ClusterList,

GENERICAPP_MAX_CLUSTERS, (cId_t

*)GenericApp_ClusterList,

FALSE );

}

很明显这里按键2(右键)是发送绑定请求的命令。

if ( keys & HAL_KEY_SW_4 )

{

HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );

// Initiate a Match Deion Request (Service Discovery)

de = AddrBroadcast;

ddr = NWK_BROADCAST_SHORTADDR;

ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,

GENERICAPP_PROFID,

GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,

GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,

FALSE );

}

显然按键4(左)是初始化一个匹配描述符请求,也就是发现服务,或者叫自动

寻求匹配设备。

这就不怪我按键有反映了!

而且在发送数据和接收数据处理函数发现:

void GenericApp_SendTheMessage( void )

{

char theMessageData[] = "Hello World";

if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,

GENERICAPP_CLUSTERID,

(byte)osal_strlen( theMessageData ) + 1,

(byte *)&theMessageData,

&GenericApp_TransID,

AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) ==

afStatus_SUCCESS )

{

// Successfully requested to be sent.

}

else

{

// Error occurred in request to send.

}

}

居然发送的是一个字符串―Hello World‖。

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

switch ( pkt->clusterId )

{

case GENERICAPP_CLUSTERID:

// "the" message

#if defined( LCD_SUPPORTED )

HalLcdWriteScreen( (char*)pkt->, "rcvd" );

#elif defined( WIN32 )

WPRINTSTR( pkt-> );

#endif

break;

}

}

接收数据处理函数里居然要通过液晶显示,本人这里的液晶暂时没有移植过来,

因为暂时还不具备那个实力,怪不得看不到发送数据的状况!

这里本人就自作聪明的把以前SampleApp例子里面的一句话加过来了:

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

switch ( pkt->clusterId )

{

case GENERICAPP_CLUSTERID:

// "the" message

HalLedBlink( HAL_LED_4, 4, 50, (500) );

#if defined( LCD_SUPPORTED )

HalLcdWriteScreen( (char*)pkt->, "rcvd" );

#elif defined( WIN32 )

WPRINTSTR( pkt-> );

#endif

break;

}

}

麽想到啊,这么一加居然就有反应了,o(∩_∩)o…!我不愧是天才的接班人啊!

其实这里很简单的了,就是接收到数据后闪烁4下灯,间隔0.5S。因为从:

if ( events & GENERICAPP_SEND_MSG_EVT )

{

// Send "the" message

GenericApp_SendTheMessage();

// Setup to send message again

osal_start_timerEx( GenericApp_TaskID,

GENERICAPP_SEND_MSG_EVT,

GENERICAPP_SEND_MSG_TIMEOUT );

// return unprocessed events

return (events ^ GENERICAPP_SEND_MSG_EVT);

}

这里可以看出,这个例子很明显仅仅是个发送周期信息的例子。所以LED4就周

期性的闪烁4下,当然是协调器发送,路由器闪烁,路由器发送,协调器闪烁。

但是这例子里体现了绑定的概念,应该说是从基本功能上很齐全的一个例子,而

且在ZSTACK上实现无线网络数传,没有任何多余的功能。所以该例子是一个

典型的ZSTACK模板,也就是为用户提供了一个通用模板可以通过这个建立自

己的应用。关于如何在这个例子上建立、修改成自己的工程和应用项目详细见文

档:

Create New Application For The CC2430DB_F8W-2005-0033_.pdf

这个例子就到此结束了,否则不然就很难把下面的弄玩了!

2、SimpleApp

这个例子我基本跑通了,可是鉴于时间的关系,没有来得及打字了,所以就留到

下一次了,时间真是如流水啊-------------------快!

学习Z-Stack之9

接到昨天的继续忽悠,话说:

2、SimpleApp

―这个例子我基本跑通了,可是鉴于时间的关系,没有来得及打字了,所以就留

到下一次了,时间真是如流水啊-------------------快!….‖

这个例子里面有两个演示:一个是灯与开关的控制实验,一个温度传感器实验。

咱一个个来,不忙。

灯与开关实验

在这个例子中灯对应的工程名字为:SimpleControllerDB;开关对应:

SimpleSwitchDB。严重需要注意的地方,这里选用的是DB。因为从从零开始学

习Z-Stack之1上可以看到DB与EB的区别,而这里用DB的硬件就足以应付。

编译下载我就不继续罗嗦了。

咱关心的几个问题不外乎就是表演过程和表演结果,以及初步看看为什么

会有这样的结果产生,当然就得从程序上简单了解下。

首先打开Controller(也就是灯设备)的电源,那么LED2就会不停的闪烁,

这个时候是设备正在初始化,让您选择设备以哪种类型启动,从程序可以看出:

if ( keys & HAL_KEY_SW_1 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// Key 1 starts device as a coordinator

zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType );

if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )

{

logicalType = ZG_DEVICETYPE_COORDINATOR;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

}

// Do more configuration if necessary and then restart device with

auto-start bit set

// write endpoint to dont pass it in hen reset

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

如果按下S1(UP),那么作为协调器启动。

if ( keys & HAL_KEY_SW_2 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// Key 2 starts device as a router

zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType );

if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )

{

logicalType = ZG_DEVICETYPE_ROUTER;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

}

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

如果按下S2(RIGHT),设备作为路由器启动。

这里由于是第一个启动的设备,所以作为协调器启动,就按下UP,此时灯

会有状态变化,最终结果是:LED2常亮,标示建立网络成功。如果您还有另外

的灯设备就可以按下RIGHT让他们都作为路由器启动,由于本人这里只有两个

节点,所以就只能有个协调器。

现在就来启动开关设备的电源,同样LED2会闪烁让您选择设备,但是在

ZIGBEE中除了协调器和路由器就剩下终端设备了,所以开关就只能作为终端被

启动,但是也需要通过按键来控制,从程序中可以看出:

if ( keys & HAL_KEY_SW_1 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// The Switch device is always an end-device

logicalType = ZG_DEVICETYPE_ENDDEVICE;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

// Do more configuration if necessary and then restart device with auto-start bit

set

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

else

{

// Initiate a binding with null destination

zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID, NULL);

}

}

if ( keys & HAL_KEY_SW_2 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// The Switch device is always an end-device

logicalType = ZG_DEVICETYPE_ENDDEVICE;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

else

{

// Send the command to toggle light

zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,

(uint8 *)NULL, myAppSeqNumber, 0, 0 );

}

}

无论是按下S1还是S2(UP或者RIGHT),开关设备均作为终端设备启动。

启动之后呢,灯的状态同样会发生一些变化,最终结果是:LED2快速闪烁,表

明此时开关已经成功加入刚才灯设备建立的那个网络了。

那么接下来就要看这个例子的核心部分----------绑定!

首先按下灯设备(这里为协调器,如果有路由器也可以)的UP,那么程序

中调用了:

zb_AllowBind( myAllowBindTimeout );

函数,允许绑定,这个允许的时间据说只有10S,当然这个时间是可以调整

的,因为这里的参数为:static uint8 myAllowBindTimeout = 10;至于这个时间怎么

计算的就需要到某个函数zb_AllowBind里去分析了。zb_AllowBind规定这个参

数为1~64,如果为0,表示为假,就是不允许绑定的意思。如果大于64的话,

就一直为真,就是一直都允许绑定。好像似乎是这个意思。至于这个10S是怎么

制定的呢,在这个函数内部调用了:

osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000);

因为osal_start_timerEx定时函数最小单位为mS,所以*1000就表示S了。

而在SAPI_ProcessEvent事件处理函数中ZB_ALLOW_BIND_TIMER事件处理如

下:

if ( events & ZB_ALLOW_BIND_TIMER )

{

afSetMatch(sapi_Desc->EndPoint, FALSE);

return (events ^ ZB_ALLOW_BIND_TIMER);

}

也就是定时取消绑定状态!!!

如果有人看着这些看不明白,那就把这个例子多看几遍,多跑几遍。一般

如果您每天花费4个小时看这个例子,那么只需要一周事件,我想到时比我还精

通明白的!

所以在10S之内,开关必须发起绑定,此时同样按下开关设备的UP,那么

开关设备就调用了函数:zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID,

NULL);发送一个绑定请求去寻求绑定设备。

一个设备允许绑定,一个设备发起绑定请求,两个是您情我愿的,所以就

一拍即合,相当的登对!当然没有这么简单的哈,就如同两个人谈恋爱,至少也

需要是一男一女啊,两个都是男或女那就太不正常了,ZIGBEE是个国际化的标

准,当然不能有这种变态行为,所以也需要两个命令的属性是相反的,就例如这

里的控制灯开关的命令,对于灯来说这个命令为输入,而对于开关来说这个命令

是输出。所以一入一出刚好就登对。呵呵!!

绑定成功的表象是:开关设备的LED1快速闪烁。

void zb_AllowBindConfirm( uint16 source )

{

// Flash LED

HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK );

}

绑定成功了就可以发送灯控制命令了。按下RIGHT,调用了函数:

zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,

(uint8 *)NULL, myAppSeqNumber, 0, 0 );

可以看出发送了一个数据请求,显然是广播发送的,而命令为切换灯状态的

TOGGLE_LIGHT_CMD_ID。当灯收到这命令,就有处理函数了:

void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8

*pData )

{

if (command == TOGGLE_LIGHT_CMD_ID)

{

// Received application command to toggle the LED

HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE);

}

}

所以LED1显示状态发生改变。

此时这个例子已经接近尾声了,因为绑定成功开关能够控制灯了,但是既然可以

绑定那么也可以接触绑定的,如果按下开关的DOWN,那么同样调用了发送绑

定请求函数:

zb_BindDevice(FALSE, TOGGLE_LIGHT_CMD_ID, NULL);

只是这里第一个参数为FALSE,所以就能解除绑定。如果某个开关被解除了绑

定,那么此时就不能控制灯了。

在这个例子最后做个小结------绑定的好处。

绑定了之后,发送数据或者命令,就不需要设备的地址,因为这个命令只能在建

立绑定间的设备中传输。------------绝对是我的理解!

还有,一个开关可以绑定多个灯,同样,一个灯可以同时与多个开关发生

绑定。这个不代表本人观点,本人强力反对脚踏N只船!!!!!!

现在来简单分析下传感器的例子,由于前面灯的例子说的比较多,这里我

就说少点。

中心节点对应SimpleCollectorEB ,传感器节点对应SimpleSensorEB。这里

用到了EB,主要是因为DB没有串口硬件,而EB有,这个例子需要用到串口。

传感器的例子效果是:协调器可以收集传感器节点的温度信息并通过串口传输到

PC机,如下图所示:

可以看到能够看到节点的温度和电源电压。

具体实现与灯的例子稍区别,但是本质的原理是一样的,先选择设备类型,然后

建立绑定,最后收集信息。这里建立绑定的区别在于,只要中心节点允许绑定(与

前面操作一样),然后传感器节点是自动发送绑定请求的:

osal_start_timerEx( sapi_TaskID, MY_FIND_COLLECTOR_EVT,

myBindRetryDelay );

定时去产生发MY_FIND_COLLECTOR_EVT事件:

if ( event & MY_FIND_COLLECTOR_EVT )

{

// Find and bind to a collector device

zb_BindDevice( TRUE, SENSOR_REPORT_CMD_ID, (uint8 *)NULL );

}

这个事件就是发送绑定请求的。

至于绑定后的现象与前面一样了。

最后通过串口调试工具就能看到前面那个图的效果了!!!!!!!!!!!!!

这里的温度为42,这个肯定不可能的,不然我就被蒸发掉了哈!因为采用的是

芯片内部集成的温度传感器,这个传感器做实验还可以,因为可以看见温度的变

化,但是其准确性是在不敢恭维。TI也是的,做了温度传感器,还超级不准确,

还不如不做,只有还可以降低硬件成本,几乎没有任何使用价值!!!

2024年10月13日发(作者:罗远)

关于ZIGBEE技术

Zigbee的由来

在蓝牙技术的使用过程中,人们发现蓝牙技术尽管有许多优点,但仍存在

许多缺陷。对工业,家庭自动化控制和遥测遥控领域而言,蓝牙技术显得太复杂,

功耗大,距离近,组网规模太小等,而工业自动化对无线通信的需求越来越强烈。

正因此,经过人们长期努力,Zigbee协议在2003年中通过后,于2004正式问世

了。

Zigbee是什么

Zigbee是一个由可多到65000个无线数传模块组成的一个无线数传网络平

台,十分类似现有的移动通信的CDMA网或GSM网,每一个Zigbee网络数传

模块类似移动网络的一个基站,在整个网络范围内,它们之间可以进行相互通信;

每个网络节点间的距离可以从标准的75米,到扩展后的几百米,甚至几公里;

另外整个Zigbee网络还可以与现有的其它的各种网络连接。例如,你可以通过

互联网在北京监控云南某地的一个Zigbee控制网络。

不同的是,Zigbee网络主要是为自动化控制数据传输而建立,而移动通信

网主要是为语音通信而建立;每个移动基站价值一般都在百万元人民币以上,而

每个Zigbee―基站‖却不到1000元人民币;每个Zigbee 网络节点不仅本身可以与

监控对对象,例如传感器连接直接进行数据采集和监控,它还可以自动中转别的

网络节点传过来的数据资料; 除此之外,每一个Zigbee网络节点(FFD)还可在

自己信号覆盖的范围内,和多个不承担网络信息中转任务的孤立的子节点(RFD)

无线连接。

每个Zigbee网络节点(FFD和RFD)可以可支持多到31个的传感器和受

控设备,每一个传感器和受控设备终可以有8种不同的接口方式。可以采集和传

输数字量和模拟量。

Zigbee技术的应用领域

Zigbee技术的目标就是针对工业,家庭自动化,遥测遥控,汽车自动化、

农业自动化和医疗护理等,例如灯光自动化控制,传感器的无线数据采集和监控,

油田,电力,矿山和物流管理等应用领域。另外它还可以对局部区域内移动目标

例如城市中的车辆进行定位.

通常,符合如下条件之一的应用,就可以考虑采用Zigbee技术做无线传输:

1.需要数据采集或监控的网点多;

2.要求传输的数据量不大,而要求设备成本低;

3.要求数据传输可性高,安全性高;

4.设备体积很小,不便放置较大的充电电池或者电源模块;

5.电池供电;

6.地形复杂,监测点多,需要较大的网络覆盖;

7.现有移动网络的覆盖盲区;

8.使用现存移动网络进行低数据量传输的遥测遥控系统。

9.使用GPS效果差,或成本太高的局部区域移动目标的定位应用。

Zigbee 技术的特点

省电:两节五号电池支持长达6个月到2年左右的使用时间。

可靠:采用了碰撞避免机制,同时为需要固定带宽的通信业务预留了专用

时隙,避免了发送数据时的竞争和冲突;节点模块之间具有自动动态组网的功能,

信息在整个Zigbee网络中通过自动路由的方式进行传输,从而保证了信息传输

的可靠性。

时延短:针对时延敏感的应用做了优化,通信时延和从休眠状态激活的时

延都非常短。

网络容量大:可支持达65000个节点。

安全:ZigBee提供了数据完整性检查和鉴权功能,加密算法采用通用的

AES-128。

高保密性:64位出厂编号和支持AES-128加密。

Zigbee的发展前景

Zigbee技术和RFID 技术在2004年就被列为当今世界发展最快,市场前景

最广阔的十大最新技术中的两个。关于这方面的报道,你只需在百度,或

GOOGLE搜索栏中键入―Zigbee‖,你就会看到大量的有关报道。总之,今后若干

年,都将是Zigbee技术飞速发展的时期。

Zigbee技术在我国的应用情况

尽管,国内不少人已经开始关注Zigbee这们新技术,而且也有不少单位开

始涉足Zigbee技术的开发工作,然而,由于Zigbee 本身是一种新的系统集成技

术,应用软件的开发必须和网络传输,射频技术和底层软硬件控制技术结合在一

起。因而深入理解这个来自国外的新技术,再组织一个在这几个方面都有丰富经

验的配套的队伍,本身就不是一件容易的事情,因而,到目前为止,国内目前除

了成都西谷曙光数字技术有限公司,真正将Zigbee技术开发成产品,并成功地

用于解决几个领域的实际生产问题而外,尚未见到其它报道。

Zigbee 和现有移动网(GPRS,CDMA-1X)的比较

1.无网络使用费:使用移动网需要长期支付网络使用费,而且是按节点终

端的数量计算的,而Zigbee没有这笔费用;

2.设备投入低:使用移动网需要购买移动终端设备,每个终端的价格在人

民币1000元上下,而使用Zigbee 网络,不仅Zigbee网络节点模块(相当于基

站)费用每只人民币不到1000元,而且,主要使用的网络子节点(相当于手机)

的价格还要低得多;

3.通信更可靠:由于现有移动网主要是为手机通信而设计的,尽管

CDMA-1X和GPRS可以进行数据通信,但实践发现,不仅通信数率比设计速率

低很多,而且数据通信的可靠信也存在一定的问题。而Zigbee网络则是专门为

控制数据的传输而设计的,因而控制数据的传输具有相当的保证。

4.高度的灵活性和低成本:首先,通过使用覆盖距离不同,功能不同的Zigbee

网络节点,以及其它非Zigbee系统的低成本的无线收发模块,建立起一个Zigbee

局部自动化控制网,(这个网络可以是星型,树状,网状及其共同组成的复合网

结构)再通过互联网或移动网与远端的计算机相连,从而实现低成本,高效率的

工业自动化遥测遥控;

5.比起现有的移动网来,尽管Zigbee仅仅只是一个局域网,覆盖区域有限,

但它却可以与现有的移动网,互联网和其它通信网络相连接,将许多Zigbee局

域网相互连成为一个整体。有效的解决移动网的盲区覆盖问题:我们知道,现有

移动网络在许多地方存在盲区,特别是铁路,公路,油田,矿山等野外,更是如

此。而增加一个移动基站或直放站的费用是相当可观的,此时使用Zigbee网络

进行盲区覆盖不仅经济有效,而且往往是现在唯一可行手段。

Zigbee与现有数传电台的比较

1.可靠性高:由于Zigbee模块的集成度远比一般数传电台高,分离元器件

少,因而可靠性更高;

2.使用方便安全:因为集成度高,比起一般数传电台来,Zigbee收法模块

体积可以做得很小,而且功耗低,例如成都西谷公司远距离传输模块(2-5公里),

最大发射电流比一个CDMA手机还要小许多,因而很容易集成或直接安放在到

设备之中,不仅使用方便,而且在户外使用时,不容易受到破坏;

3.抗干扰力强,保密性好,误码率低:Zigbee收发模块使用的是2.4G 直

序扩频技术,比起一般FSK, ASK和跳频的数传电台来,具有更好的抗干扰能力,

和更远的传输距离;参阅我们网站中有关CDMA直序扩频技术的优越性讨论,

和Cypress公司有关实验报道。

4.免费频段:Zigbee使用的是免费频段,而许多数传电台所使用的频段不

仅需要申请,而且每年都需要向国家无委会交纳相当的频率使用费。

5.价格低: Zigbee数传模块的价格只有具有类似功能的数传电台的几分

之一;(2.4G,250kps,3-5公里距离DSSS 数传模块每只不到200元人民币)

提供低成本,高可靠性的无线数传互联网平台(包括软件和硬件),以及相

关技术支持,以满足不同客户的具体需要,就是我们的服务宗旨。

学习Zstack之1

Zstack情况:

本人采用的是TI的Zstack1.4.3协议,据说这个需要IAR7.30B及以上版本,

而目前市面上又没有破解,所以用的人很少,这也是我的机会!呵呵!(傻笑有

点多,关键是WORD里没有表情符号,不能正常表达我此时的心情!)

正式开始:

开始之前在说一句:从TI网站上下载的Zstack的方法就不介绍了。否则就

是从-1开始了而不是从0开始了-----------------我是这么觉得的!

第一步:安装Zstack

从TI官方网站上下载的Zstack为:,我想这个压缩包大家都

认识。解压之后为:文件。这个安装文件大家都会了。

默认安装路径为:C:Texas InstrumentsZStack-1.4.3。安装之后在C:Texas

InstrumentsZStack-1.4.3目录下有各PDF文档为:Getting Started Guide

,不用多说,这个肯定是要看的。既然把它放到这么前面,说明它是

入门中的入门文档。下面就简单介绍下这个文档:

1、介绍了安装需要的硬件软件条件:需要电脑、操作系

统为Windows 2000或 Windows XP。至于更高或更低版本的本人没有尝试。

2、讲了安装流程。这个有点多余了,这年月哪个有电脑的没有安装上百上千次

的软件啊?但是需要强调的是安装路径----默认就好!

3、接下来就是让我们看的第一个文档为:

Start->Programs->Texas Instruments->ZStack-1.4.3->Z-Stack User’s Guide,

既然让我看我就来看看这个文档!!

第二步:Z-Stack 用户指导

这个文档的更新时间为:2007年12月21日----应该还是比较新的版本。由

于本人英文的却有限,就不翻译了,浏览一遍,把大概意思说下就可以了:

1、介绍

1.1、适用范围

本文档适用于CC2430ZigBee开发板----CC2430ZDK。

2、产品包描述(TI提供的CC2430ZDK工具包)

2.1、安装包内容

这个就是上面提到的的安装之后的所有内容了。说白了

就是包含Zstack开发所需要的所有软件和文档资料等。

2.2、开发板介绍

两块 SmartRF04EB 评估版,每个都可以用于CC2430EM评估模块。如图1-1

所示:

Figure 1: Chipcon SmartRF04EB Evaluation Board with CC2430EM

5块CC2430DB 评估板,如图1-2所示:

Figure 2: Chipcon CC2430DB Development Board

10个SOC_BB 评估板,每个都可以用于CC2430EM或CC2431EM。如图1-3

所示:

Figure 3: Chipcon SOC_BB Battery Board

2.3、电缆

也就是包含开发包所需要的电缆,如RS232串口线,USB线等等附属配件。

3、安装配置

3.1、主机配置

一台个人计算机----也就是电脑哈。我想玩嵌入式的应该都有,而现今不过时的

配置就可以:下面是最低配置

.NET 1.1 架构

Windows XP Service Pack 1 (i如果是 Windows XP)

1个串口(也就是RS232接口)s

1 USB接口

个人认为要求已经相当低了,如果你的电脑没有这配置,个人强烈建议马

上扔掉!不过如今笔记本电脑很少有串口的,所以建议使用台式电脑,而且装机

的时候一定要把串口引出,否则就比较麻烦了!

3.2、目标板需求

其实也是开发环境需求--- IAR EW8051。目前需要的版本为7.30B及以上。

要求还是比较高的,因为目前这个版本没有破解的。但是在/

上有30天评估版下载。这个版本使用一定要小心,因为如果30天之后仅仅是卸

载IAR重新安装是没有用的,一般最笨的办法是重新安装操作系统。解决这个

问题最好的办法就是买正版,呵呵,我想绝大多数像我这样的中国人都不会买的。

除此之外最好的办法就是破解,但是目前这个破解极少,都是需要收费的,而且

都是国外网站才有,所以我们就只好期望中国的高人抓紧破解并公开了!当然其

他解决办法就相对来说很多了,比如安装后弄个还原点什么的;或者安装后我不

停地使用(每天24小时),30天之后我觉得你也学会了,就不用IAR这个版本

了,说不定就移植到低版本上去了;等等类似之法我觉得都可以的。本人采用的

是本办法中相对比较聪明的,也是一位高人告诉我的:装个虚拟操作系统,在虚

拟操作系统下时间可以随时更改,让它一直停留在某个时间,主要30天的试用

就比较慢长了,只要你不要忘记改那时间。

4、产品安装过程

4.1、安装Z-Stack

这个也就是安装的过程。

4.2、IAR安装

一般来说安装选择默认路径,但是自定义路径也不会出问题的。注意IAR

版本7.30B及以上版本才可以运行1.4.3协议。

4.3、设备IEEE地址

每个 CC2430DB, CC2430EM,和 CC2431EM都已经排列了一个唯一的64

位物理地址(IEEE地址),这个地址已经写到了CC2430内部FLASH里面,在

CC2430DB, CC2430EM,和 CC2431EM板的底部有这个地址标签。

这个地址被写入到FLASH的0x1FFF8地址中,注意这个地址也可以更改的,

通过些FLASH软件,一般0xFFFFFFFFFFFFFFFF地址被认为是无效地址。

5、配置并试用Z-Stack

5.1、配置Z-Stack

这个详见5.3节。

5.2、逻辑类型

这里主要是介绍了ZIGBEE协议中的三种设备类型:

ZigBee 协调者(ZC):这个设备被配置为初始化并建立一个PAN网络

ZigBee 路由器(ZR):该设备被配置为加入一个存在的网络,可以加入一个协调

求或路由器,然后允许其他设备加入它,在网络中路有数据信息。

ZigBee 终端节点 (ZED):该设备被配置为加入一个存在的网络,可以加入一个

协调求或路由器。

5.3、建立样品应用设备:SampleApp

基本上就是采用SampleApp应用中的Demo例子来演示整个流程,就是采用一

个协调器和一个或多个路由器来形成一个ZigBee网络演示。在该例子中主要通

过SmartRF04EB板上的某些跳线来完成设备类型的选型,当然这个方法在程序

中是需要判断哪个按键被拉低或拉高,对于做个设计的来说应该是相当好理解

的。

申明:由于本人很穷,所以没钱买TI原装开发包,当然也就没有上面提到

的硬件,本人采用的是某家公司(为了避免广告,这里就不说明了)的硬件系统。

5.4、建立一个SampleLight协调器设备

至于提到的硬件连接这里一律省略。

无疑:首先要打开对应工程,如图1-4所示:

图1-4

在工作窗口中选择DemoEB,如图1-5所示:

图1-5

然后选择工程菜单(Project)下的全部编译(Rebuild All)选项,如图1-6所示:

图1-6

然后选择工程菜单(Project)下的调试(Debug)选项,如图1-7所示:

图1-7

下载完之后就可以退出调试状态,通过选中调试菜单下的停止调试选项,如图

1-8所示:

图1-8

按照此种方法下载至少两个CC2430EM模块,就可以进行Demo演示了。

6、 Z-Stack 示范

至于详细的示范流程,这里先不说了,因为本人采用的硬件与原装有点差

异,即使按照这个方法下载仍然不能演示,因为我这个不能用跳线来选择设备类

型。

所以我必须进入程序把跳线判断程序进行简单必要的修改才能演示。

该文档介绍的演示结果及现象都是基于CHIPCON原厂评估板。

和通道(Channel)选择

ZigBee协议规范规定,一个14位的个域网标志符(PAN ID)来标识唯一

的一个网络。Z-Stack可以用两种方式由用户自己选择其PAN ID,当

ZDAPP_CONFIG_PAN_ID值设置不为0xFFFF时,那么设备建立或加入网络的

PAN ID由ZDAPP_CONFIG_PAN_ID指定;如果设置ZDAPP_CONFIG_PAN_ID

为0xFFFF;那么设备就将建立或加入它发现网络中的―最好‖的网络。关于这里

提到的―最好‖的网络,我觉得可能是有些参数评估,只不过这里没有详细的介绍,

在后续文档中应该有介绍的。

在2.4G频段上,IEEE 802.15.4/ZIGBEE规范规定了16各频道。用户可以

通过选择DEFAULT_CHANLIST不同的值可以选择不同的频道,其频道如图1-9

所示。改协议默认频道为0xB及0x00000800。

图1-9

DEFAULT_CHANLIST 和 ZDAPP_CONFIG_PAN_ID都作为IAR IDE中的编译

选项可以进行设置,在应用文件中的…ProjectsToolsCC2430DB目录下的

文件中有相应设置,如图1-10所示。

图1-10

学习Zstack之2

上节基本上初步认识了Zstack的一些情况,今天继续我的学习,打开Sample

例子看看,究竟ZIGBEE是怎么回事。

毫无疑问:如果是第一次打开这个例子工程,肯定很迷糊,因为此时我迷

糊了。对图2-1我简直是相当迷糊。

图2-1

这么多文件夹,打开之后又有那么多文件,从何看起?不要着急,特别是

有些人拿到之后,啥都不知道的人第一个问题就是:我要实现XXX,在哪修改

或者在哪添加我的函数呢?凡是我遇到这样的客户,我就可以肯定他技术部咋

的。就连我这个外行都知道,不把这些弄明白,就是实现XXX只需要修改一个

字母,那也不知道在哪改啊?所以我不急,但是我也理解很多客户,因为有时候

项目催的比较急,毕竟老板都是外行嘛!

两条路:1就是先看主函数,2就是看看TI提供例子说明文档没有。

我这里先看看主函数再说哈!因为我就知道从主函数看起.

没办法大概每个文件夹找啊,主函数的特征还是比较明明显的,见图2-2

所示:

图2-2

下面把主函数复制过来简单看下:

ZSEG int main( void )

{

// Turn off interrupts------------关闭中断

osal_int_disable( INTS_ALL );

// Initialize HAL-----------初始化HAL,关于HAL是什么我想后面会有介绍的。

HAL_BOARD_INIT();

// Make sure supply voltage is high enough to run----电压检测,最好是能保证芯片

能正常工作的电压

zmain_vdd_check();

// Initialize stack memory-------------初始化stack存储区

zmain_ram_init();

// Initialize board I/O------------初始化板载IO

InitBoard( OB_COLD );

// Initialze HAL drivers-------------初始化HAL驱动

HalDriverInit();

// Initialize NV System--------------初始化NV系统,NV是什么后面我想也会有介

绍的

osal_nv_init( NULL );

// Determine the extended address------------确定扩展地址(64位IEEE/物理地址)

zmain_ext_addr();

// Initialize basic NV items----------------初始化基本NV条目

zgInit();

// Initialize the MAC----------------初始化MAC

ZMacInit();

#ifndef NONWK

// Since the AF isn't a task, call it's initialization routine

afInit();

#endif

// Initialize the operating system----------初始化操作系统,看样子这里面还有OS,

麻烦了……..!

osal_init_system();

// Allow interrupts-------------允许中断

osal_int_enable( INTS_ALL );

// Final board initialization------------------最后的版在初始化

InitBoard( OB_READY );

// Display information about this device---------------显示设备信息

zmain_dev_info();

/* Display the device info on the LCD */------------液晶支持显示

#ifdef LCD_SUPPORTED

zmain_lcd_init();

#endif

osal_start_system(); // No Return from here-------------------这里没有返回,大概是进

入OS了。

} // main()

可以看到基本上都是初始化函数,因为函数名称都基本上带了init字样的,

呵呵,个人觉得TI的变成习惯比我好,一看名称就知道大概功能了。所以这里

也奉劝各位像我这样菜鸟级的初学者,一开始一定就要养成规范化编程的习惯,

据说这样维护以及以后升级或者移植兼容性都比较好。我就先不管各个初始化函

数是怎么实现的,我先看看各个功能是什么,现掌握整体功能在细化,我觉得这

样的学习方法比较好,因为代码是在太多了,从一开始就逐句看,我敢保证没几

个人有耐心看完看明白!

幸好每个初始化函数都有一句说明,虽然是英文的,但是理解起来一点都

不难的。关于每个函数的功能我就直接写在上面的程序里面,节省纸张哈!

一句话:主函数的功能就是初始化!

主函数看完了又开始模糊了,又从何看起呢?在无从下手之际,只有去寻

求TI说明文档的帮助了。上节不是漏掉了内容,是关于演示结果的,这里做上

补充,怕因为缺调一点后面遇到什么不理解的就惨了!

Sample例子演示演示现象:

1、认识硬件------------按键和LED

上节提到了EM和DB两个板子,其硬件是不一样的。按键EM就有5各

SW1~SW5,而DB只有1各方向键,但是他们有个对应关系,如图2-3所示.

图2-3

LED数量和颜色也不一样,EM有四个LED,如图2-4;而DB只有两个,

如图2-5。

如图2-4

如图2-5

关于上面几个图2-4/5中出现的LEDx实际上是程序中出现的关键字。

2、初始化64位IEEE地址

实际上在主函数中有这么个初始化函数的:zmain_ext_addr()。这里说如果

地址复位为0xFFFFFFFFFFFFFFFF的话,那么就会不停的闪烁LED1,一直等到

按键SW5按下后程序才能继续运行,意思就是说按下SW5后就把无效的地址初

始化为有效地物理地址了,这个应该是程序上实现的,那么就来看看对应的程序

zmain_ext_addr。

/********************************************************************

*

* @fn zmain_ext_addr

* @brief Makes extended address if none exists.确定扩展地址是有效的

* @return none

********************************************************************

*/

static ZSEG void zmain_ext_addr( void )

{

uint8 i;

uint8 led;

uint8 tmp;

uint8 *xad;

uint16 AtoD;

// Initialize extended address in NV初始化NV里的扩载地址

osal_nv_item_init(ZCD_NV_EXTADDR,Z_EXTADDR_LEN, NULL );

osal_nv_read( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, &aExtendedAddress );

// Check for uninitialized value (erased EEPROM = 0xFF)检查是否为无效值(地址)

xad = (uint8*)&aExtendedAddress;

for (i =0;i < Z_EXTADDR_LEN; i++ )

if(*xad++ != 0xFF ) return;-----如果有一个字节不为0xFF,那么该地址有效返回

#ifdef ZDO_COORDINATOR

tmp = 0x10;

#else

tmp = 0x20;

#endif

// Initialize with a simple pattern----------------简单初始化扩展地址

xad = (uint8*)&aExtendedAddress;

for ( i = 0; i < Z_EXTADDR_LEN; i++ )

*xad++ = tmp++;

// Flash LED1 until user hits SW5 ---------闪烁LED1直到SW5按下

led = HAL_LED_MODE_OFF;

while ( HAL_KEY_SW_5 != HalKeyRead() )---------------------SW5循环检测

{

MicroWait( 62500 );

HalLedSet( HAL_LED_1, led^=HAL_LED_MODE_ON );//Toggle the LED

MicroWait( 62500 );

}

HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF );

// Plug AtoD data into lower bytes

AtoD = HalAdcRead (HAL_ADC_CHANNEL_7, HAL_ADC_RESOLUTION_10);

xad = (uint8*)&aExtendedAddress;

*xad++ = LO_UINT16( AtoD );

*xad = HI_UINT16( AtoD );

#if !defined( ZTOOL_PORT ) || defined( ZPORT ) || defined( NV_RESTORE )

// If no support for Z-Tool serial I/O,

// Write temporary 64-bit address to NV些临时的64位物理地址进入NV

osal_nv_write( ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, &aExtendedAddress );

#endif

}

从程序中可以看出,一开始就检测FLASH中的物理地址,因为这个地址在

FLASH中是固定的存储空间,一旦为有效地址就退出函数,一旦为无效地址

(0xFFFFFFFFFFFFFFFF),那么就对其物理地址进行简单的初始化并检测SW5

按键。还是比较好理解的!

3、运行例子

在这里提到了跳线,由于本人采用的非TI原装硬件,没有该跳线,所以必

须对程序进行修改,否则检测不到跳线,连ZIGBEE的设备类型都不能确定,肯

定不能正常运行了。所以这里就先暂时不说了,这里要说的是一切都正常的情况

下,例子的验尸结果。小小跳跃一下。不然学习一直没有进展很麻烦的!

协调器:上电运行,地址检测如上面介绍的情况,通过之后呢-------就进行

通道扫描,此时LED1闪烁,一旦协调器成功建立网络,此时LED1停止闪烁,

而LED3被点亮。

路由器:上电运行,仍然是地址检测在前。之后就是通道扫描寻求是否又

存在的网络,此时LED1闪烁,一旦检测到存在网络并成功加入该网络,LED1

将停止闪烁,被替换的是LED3别点亮,也就表明路由器成功加入了网络。

那么此时能进行的操作控制是什么呢,也是最简单的表现手法---按键无线

控制LED:

周期(5S)发送信息到网络中每个设备

SW1按下,发送一个信息到组1的设备

SW2按下,退出/加入组1

这个我是经过验证的。如:

按下协调器SW1,路由器的LED1狂闪几下;按下路由器的SW1,那么协

调器的LED1也就狂闪几下;当然我是只有两个节点。

如果按1下协调器的SW2,在按下路由器的SW1,此时协调器就没有反应,

表明协调器已经退出组1;但是再按下协调器SW2在按路由器的SW1就与上一

步类似了。路由器与此类似可以通过SW2退出/加入组1.

终于把演示弄完了,接下来就来看看程序。在此之前还是来看看TI提供的

Sample指导文档。这个文档个人觉得写的不错,要是没看之前就看程序的却很

郁闷的!

但是本人英文很差,所以需要慢慢看,等点时间放上来!

Z-Stack之3

Sample Application分析(上)

1、Z-Stack CC2430DB and CC2430EB Sample Application

1.1、介绍

该文档时介绍TI协议入门的一个例子SampleApp的,适用EM和DB开发

板。

1.1.1、描述

这个例子是非常简单的演示,每个设备都可以发送和接收两个信息

周期信息-----加入该网络的所有设备每隔10S(可能会加上一个随机数的

mS)都发送一个周期信息,该信息的数据载荷为发送信息次数的计数。

闪烁控制信息---------通过按下SW1可以发送一个控制灯闪烁的广播信息,

该广播信息只针对组1的所有设备。

所有设备初始化为加入组1,所以网络一旦成功建立/加入就可以进行闪烁

控制。可以通过按下设备的SW2退出组1,所以可以通过退出组1可以不接受

闪灯信息。通过按下SW2也可以让不在组1的设备加入近组1,从而又可以接

受闪灯信息了。

这个理解应该不困难的,反正我理解没有什么障碍!

1.1.1.1、按键

SW1:发送闪烁信息到组1所有设备

SW2:转换推出/加入组1状态

1.1.2、用户应用开发

这里我基本上能看明白是什么,但是我不打算写出来,因为涉及到一些

ZIGBEE的关键术语,不是很明白。

大概就是简单介绍了下用户怎么利用例子做自己的应用,但是实用价值不

高,说的太笼统,全是概念性的说明。

1.2、OSAL任务

1.2.1、初始化

因为Z-Stack是在OS下运行的,所以在之前必须调用osalAddTasks()初始

化任务。

1.2.2、组织

关于OS的API函数介绍请看文档:Z-Stack OSAL API (F8W-2003-0002),

应该说协议栈的每层或者说每部分都有相关的API说明文档。osalAddTasks()初

始化任务,osalTaskAdd()函数添加任务,都可以到API文档或程序中详细分析函

数功能。

1.2.3、系统服务

OSAL和APL系统服务是唯一的,因为比如按键和串口类似事件处罚就只

能用唯一的一个任务标识。这两个硬件都留给了用户自己定义使用。

1.2.4、应用设计

用户可能为每一个应用对象都创建一个任务,或者为所有的应用对象只创

建一个任务。当选择上述的设计的时候,下面是一些设计思路:

1.2.4.1、为许多应用对象创建一个OSAL任务

下面是正面和反面(pros & cons)的一些叙述:

- Pro:接受一个互斥任务事件(开关按下或串口)时,动作是单一的。

- Pro:需要堆栈空间保存一些OSAL任务结构。

- Con:接收一个AF信息或一个AF数据确认时,动作是复杂的-----在一个

用户任务上,分支多路处理应用对象的信息事件。

- Con:通过匹配描述符(如:自动匹配)去发现服务的处理过程更复杂-----

为了适当的对ZDO_NEW_DSTADDR信息起作用,一个静态标志必须被维持。

1.2.4.2、为一个应用对象创建一个OSAL任务

一对一设计的反面和正面(pros & cons)是与上面一对多设计相反的:

- Pro:在应用对象试图自动匹配时,仅仅一个ZDO_NEW_DSTADDR被接

收。

- Pro:已经被协议栈下层多元处理后的一个AF输入信息或一个AF数据确

认。

- Con:需要堆栈空间保存一些OSAL任务结构。

- Con:如果两个或更多应用对象用同一个唯一的资源,接收一个互斥任务

事件的动作就更复杂。

1.2.5、强制方法

任何一个OSAL任务必须用两种方法执行:一个是初始化,另一个是处理

任务事件。

1.2.5.1、任务初始化

在例子中调用如下函数执行任务初始化:

―Application Name‖_Init(如SAPI_Init)。该任务初始化函数应该完成如下

功能:

变量或相应应用对象特征初始化,为了使OSAL内存管理更有效,在这里

应该分配永久堆栈存储区。

在AF层登记相应应用对象(如:afRegister())。

登记可用的OSAL或HAL系统服务(如:RegisterForKeys())

1.2.5.2、任务事件处理

调用如下函数处理任务事件:

―Application Name‖_ProcessEvent (e.g. SAPI_ProcessEvent()).除了强制的事

件之外,任一OSAL任务能被定义多达15个任务事件。

1.2.6、强制事件

一个任务事件SYS_EVENT_MSG (0x8000), 被保留必须通过OSAL任务设

计。

2.2.6.1、SYS_EVENT_MSG (0x8000)

任务事件管理者应该处理如下的系统信息子集,下面只列出了部分信息,

但是是最常用的几个信息处理,推荐根据例子复制到自己项目中使用。

1.2.6.1.1、AF_DATA_CONFIRM_CMD

调用AF_DataRequest()函数数据请求成功的指示。Zsuccess确认数据请求传

输成功,如果数据请求设置AF_ACK_REQUEST标志位,那么,只有最终目的

地址成功接收后,Zsuccess确认才返回。如果如果数据请求没有设置

AF_ACK_REQUEST标志位,那么,数据请求只要成功传输到下跳节点就返回

Zsuccess确认信息。

1.2.6.1.2、AF_INCOMING_MSG_CMD

AF信息输入指示

1.2.6.1.3、KEY_CHANGE

键盘动作指示

1.2.6.1.4、ZDO_NEW_DSTADDR

匹配描述符请求(Match Deor Request)响应指示。(例如:自动匹配)

1.2.6.1.5、ZDO_STATE_CHANGE

网络状态改变指示

1.3、网络格式化

示例应用程序编译为协调器的在default_chanlist指定的通道上形成一个网

络,协调器将建立一个随机编号源于自身的IEEE地址或由zdapp_config_pan_id

指定的网络PAN ID(如果zdapp_config_pan_id不为0xFFFF)。

示例应用程序编译为路由器或结束设备的将尝试加入网络在

default_chanlist指定的通道上,如果zdapp_config_pan_id没有定义为0 xFFFF ,

路由器将受到限制,只有加入参数zdapp_config_pan_id规定的网络PAN ID。

1.3.1、自动启动

设备自动开始尝试组建或加入网络。如果设备设置为等待计时器或其他外

部事件发生后才启动,那么HOLD_AUTO_START必须被定义。为了稍后以手动

启动方式启动设备,那么需要调用ZDApp_StartUpFromApp(函数

1.3.2、软件启动

为了在形成网络过程中节省所需的设备类型,那么所有的路由器设备可以

被通过soft_star定义作为一个协调器。如果自动启动是需要的话,那么

auto_soft_start必须被定义。

1.3.3、网络恢复

通过设置NV_RESTORE和/或NV_INIT,可以让设备断电或者意外掉电重

新启动后重新回复网络。

1.3.4、加入通告

当设备形成或加入网络后会发通报到ZDO_STATE_CHANGE信息事件。

学Z-Stack之4

Sample Application分析(下)

上节介绍了建立一个应用需要做的几个必须的事情,现在就来通过分析

Sample Application来具体看看需要做哪些事情,才能建立一个ZIGBEE应用功

能。当然这里只是做点简单的必须的工作。

The Sample Application (SampleApp)

1、介绍

主要是介绍一个应用建立的结构及需要进行的程序流程。

1.1、程序流程

1.1.1、初始化

首先需要调用初始化函数SampleApp_Init()。

SampleApp_TaskID = task_id;

初始化应用建立的任务ID号,其实用过OS的人都应该晓得这个是干啥的,

我没用过,不是很理解,但是我知道是必须的,就相当于一个任务的标识,这样

才能区分运行过程中不同任务中的不同事件。我是这么认为的,ID说白了就是

给该任务取了各名字,就向人名字一样,区分不同的人,就是一个代号。人名可

以重复,重复了有时候叫起来就容易混淆;所以才程序中为了避免这种混淆,就

强制性的规定任务ID不能重复。要是哪天国家或者联合国姓名管理委员会规定,

人民不能重复,那么这个人名就需要全球统一管理了。那给娃取个名字就要向联

合国姓名管理委员会申请了。呵呵!

SampleApp_NwkState = DEV_INIT;

初始化应用设备的网络状态。怎么说呢,据说是设备类型的改变都要产生

一个事件,叫ZDO_STATE_CHANGE,从字面理解为ZDO状态发生了改变。所

以在设备初始化的时候一定要把它初始化为什么状态都没有。那么它就要去检测

整个环境,看是否能重新建立或者加入存在的网络。但是有一种情况例外,就是

当NV_RESTORE被设置的时候(NV_RESTORE是把信息保存在非易失存储器

中),那么当设备断电或者某种意外重启时,由于网络状态存储在非易失存储器

中,那么此时就只需要恢复其网络状态,而不需要重新建立或者加入网络了。我

也是从文档中这么理解的,至于为什么只有有待进一步考证。

SampleApp_de = (afAddrMode_t)AddrNotPresent;

SampleApp_nt = 0;

SampleApp_ddr = 0;

看见这几句话从字面理解为:初始化不标设备地址模式及目标设备EP号和

网络地址。从代码可以看出,这些地址或EP均为0。也就是说目标设备为协调

者的ZDO,这个意义就很明显了,就是设备建立后可以直接与协调器的ZDO交

互信息。

SampleApp_nt = SAMPLEAPP_ENDPOINT;

----- SampleApp EP描述符的EP号

SampleApp__id = &SampleApp_TaskID;------ SampleApp EP描述符的

任务ID

SampleApp_Desc =------------------ SampleApp EP简单描述符

SimpleDeionFormat_t *)&SampleApp_SimpleDesc;

SampleApp_yReq = noLatencyReqs;

//在AF层中登记注册改应用EP

afRegister( &SampleApp_epDesc );

这里其实是对SampleApp的EP描述符进行初始化。

本人理解:要对改应用进行初始化并在AF进行登记,告诉应用层有这么一

个EP已经可以使用,那么下层要是有关于改应用的信息或者应用要对下层做哪

些操作,就自动得到下层的配合,至于这个配合是怎么回事,那么就需要好好研

究下层的协议了。当然在这里肯定是没那时间精力和能力研究了!

其实在这个应用中,只是让AF配合SAMPLEAPP_PROFID /

SAMPLEAPP_ENDPOINT这两个应用。那么通过什么呢,通过发送OSAL

SYS_EVENT_MSG消息中的(AF_INCOMING_MSG_CMD)事件到SampleApp任

务ID。

RegisterForKeys( SampleApp_TaskID );

登记按键事件到SampleApp_TaskID,在前面已经说了按键这个是唯一的,

也就是所有任务中有且只有各任务能登记键盘事件。前面还说了还有一个也是唯

一,你猜是什么?

SampleApp_ = 0x0001;

osal_memcpy( SampleApp_, ―Group1‖ );

aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );

闪灯信息被发送到组1,同样也只有在组1的设备才能接收这个信息。设备

启动时已经被设定为组1设备了,但是可以通过按SW1推出/加入组1。这里提

到了组的概念,我反正暂时不是很清楚这个是什么东西,在程序中怎么实现也很

模糊,但是应用中的好处还是不难想象的,不外呼是就是想控制谁可以事先规定

好,还可以动态更改。

1.2、事件处理

玩过OS的人都知道,OS中最重要的概念不外呼就是任务啦,消息啦,事

件啦等。从我们自己平时的工作中也不难想象,如果老板安排了某项工作,那么

我们就需要做的,这个工作可能是预先计划好的,也有可能是临时的,那么这些

预先定好或者临时的工作可以称之为事件。而老板让您做的方式,比如通过文件

下达,或者叫:某某你把XXX做下。那么让老板下达的文件内容或者说的内容

我这里可以称之为消息。老板给了你不同的消息那么就需要干不同的事件,至于

任务可以理解为公司的不同的员工,呵呵!我简直是理解的天才,这样举例居然

也能忽悠通过!!!o(∩_∩)o…哈哈

在Z-Stack中,每个应用任务都通过SampleApp_ProcessEvent()函数来处理

任务中的事件。一旦SampleApp_TaskID任务的某个OSAL事件发生,那么就可

以通过调用SampleApp_ProcessEvent()函数来处理。在SampleApp_ProcessEvent()

中有一个事件处理循环,循环检测是哪个事件发生。

if ( events & SYS_EVENT_MSG )

{

MSGpkt = (afIncomingMSGPacket_t*)osal_msg_receive( SampleApp_TaskID );

while ( MSGpkt )

{

可以看到是通过检测SYS_EVENT_MSG是否有事件信息发生。

switch ( MSGpkt-> )

这里是判断SYS_EVENT_MSG事件类型,不同的SYS_EVENT_MSG类型

需要不同的处理。

case KEY_CHANGE:

SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state,

((keyChange_t *)MSGpkt)->keys );

break;

比如这里判断是否是键盘事件,如果键盘事件就调用键盘处理函数。

如果一个OSAL任务已经被登记组侧,那么任何键盘事件都将接受一个

KEY_CHANGE事件信息。可能有如下几种方式得到键盘事件信息

1)、HAL检测到键盘按下(中断或者查询检测)

2)、HAL的OSAL任务检测到一个键盘状态改变调用回叫函数产生

3)、OSAL键盘改变回叫函数发送一个OSAL系统事件信息

(KEY_CHANGE)。

case AF_DATA_CONFIRM_CMD:

// The status is of ZStatus_t type [defined in ZComDef.h]

// The message fields are defined in AF.h

afDataConfirm = (afDataConfirm_t *)MSGpkt;

sentEP = afDataConfirm->endpoint;

sentStatus = afDataConfirm->;

sentTransID = afDataConfirm->transID;

任何AF_DataRequest()数据请求函数调用后,都通过AF_DATA_CONFIRM_CMD

系统事件信息回叫返回成功Zsuccess。

case ZDO_STATE_CHANGE:

SampleApp_NwkState = (devStates_t)(MSGpkt->);

if ( (SampleApp_NwkState == DEV_ZB_COORD)

||(SampleApp_NwkState == DEV_ROUTER)

||(SampleApp_NwkState == DEV_END_DEVICE) )

{

// Update the LCD’s network indicator

// Start sending "the" message in a regular interval.

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );

}

break;

这里就是前面介绍的设备状态改变事件处理了。

只要网络状态发生改变,那么通过ZDO_STATE_CHANGE事件通知所有的

任务。注意:在这个例子中,一旦设备成功加入网络,是通过定时运行的方式运

行的。一旦网络状态为加入‖JOINED‖,那么它可能不需要任何的认为操作就能绑

定其他设备,因为设置为自动发现并绑定的。

// Release the memory

osal_msg_deallocate( (uint8 *)MSGpkt );

释放存储空间。

if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )

{

// Send "the" message

SampleApp_SendPeriodicMessage();

// Setup to send message again

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_MSG_TIMEOUT );

// return unprocessed events

return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);

}

这里检测事件是否为周期发送信息事件。

在SampleApp.h中定义了:

#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT 0x0001

在这个应用中,调用了osal_start_timer()函数来定时产生发送周期信息事件。而

定时器的运行是设备一旦加入网络就不停的在运行。从上面可以看到,用函数

SampleApp_SendPeriodicMessage()发送周期信息,而用函数

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEN

D_MSG_TIMEOUT )来继续运行定时器定时发送这个周期信息。关于这个

osal_start_timer可以多了解下,第一个参数

SAMPLEAPP_SEND_PERIODIC_MSG_EVT四信息时间,也就是事件到了产生

一个什么事件。第二各参数SAMPLEAPP_SEND_MSG_TIMEOUT是需要定时的

时间,这里就是发送周期信息的时间周期。

1.3、消息流程

通过OSAL定时器,这个应用定时发送一个周期信息:

void SampleApp_SendPeriodicMessage( void )

{

afAddrType_t dstAddr;

dstAddr. addrMode = afAddrBroadcast;

ddr = 0xFFFF; // 广播发送

dstAddr. endpoint = SAMPLEAPP_ENDPOINT;

if ( AF_DataRequest( & dstAddr, &SampleApp_epDesc,

SAMPLEAPP_PERIODIC_CLUSTERID,

(uint8)sampleAppPeriodicCounter++,

(uint8 *)&sampleAppPeriodCounter,

&SampleApp_TransID,

AF_DISCV_ROUTE,

AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )

{

// Successfully requested to be sent.----发送成功处理

}

else

{

// Error occurred in request to send.---发送失败处理

}

}

在这里调用了AF_DataRequest()函数用来发送数据。关于发送数据的具体过

程这里就不做深入研究,不外乎就是把数据从应用层传到网络层,在传到MAC,

在传到无力层,最后通过OTA发送出去。接收数据就是相反的过程了,那么接

收之后,在应用层有什么反应呢,最直观的反应就是会发送一个

AF_INCOMING_MSG_CMD消息事件。

case AF_INCOMING_MSG_CMD:

SampleApp_MessageMSGCB( MSGpkt );

break;

这里表示收到某个信息,然后在里面调用了收到信息的信息处理函数

SampleApp_MessageMSGCB( MSGpkt )。

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

switch ( pkt->clusterId )

{

case SAMPLEAPP_PERIODIC_CLUSTERID:

// Display and increment a counter on the LCD in the periodic space

break;

case SAMPLEAPP_FLASH_CLUSTERID:

flashTime = BUILD_UINT16(pkt->[1], pkt->[2] );

HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );

break;

}

}

这里判断了两种信息:

周期信息

闪灯信息

不同的信息就相当于收到了不同的命令,然后根据不同的命令做出了不同

的处理。是个会写程序都明白!!!!

到这里,我就基本上把这个应用文档看完了,至于理解了多少我迷糊,理

解正确了多少我更加迷糊,反正我按照我自己的方式理解了!

学Z-Stack之5

前面虽然写了不少,但是回头看看大多都是废话,不过也没办法,没有废

话的润色就太枯燥了,太技术化了,这个不是我的本意。不知道前面写的怎么样,

技术含量肯定是不高的。这个本人是相当清楚,但是我最大的期望就是错误不要

太多!

突然想起来前面有个问题没有解决,我想很多人看到那里都很郁闷的。就

是设备类型的选择,在TI原装系统上是通过板载跳线来选择的,但是我这里不

是采用原装,那么就需要通过程序来修改其设备类型,然后编译下载。具体程序

段如下:

#if defined ( SOFT_START )

if ( readCoordinatorJumper() )

zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;

else

zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;

#endif // SOFT_START

这里有个条件编译,其条件编译设置如图5-1。

图5-1

既然这里设置了SOFT_START,那么上段程序就要被编译。那么第一句程序

if ( readCoordinatorJumper() )

就是检测跳线,其实稍微知道编程的都了解怎么修改了,哈哈!

屏蔽:

if ( readCoordinatorJumper() )

zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;

else

这3句,那么就只剩下:zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;

那么编译自然该设备就为路由器了。简单吧!!!!??!

协调器我就不想多说怎么做了哈!!!!!!!!!!!!

还有一个问题需要说下,就是Ti原装的EM板子用到了LCD,所以在程序中

可能在某个地方要对LCD初始化,那么如果没有液晶的板子或者与TI那个不完

全一样的LCD就有可能运行不走,通俗的解决办法是禁止LCD初始化等操作,

Ti在这个方面做的很人性化,禁止LCD功能没有必要在程序中找到LCD相关程

序删除,而是仅仅需要通过条件编译来禁止。显得相当简单,如5-2图就是禁止

LCD的条件编译。

图5-2

解决这个问题后一般都能够运行程序了。也就是说到这里如果还把Demo

程序运行不起来的话,那就证明我所有的东西都白写了,反正我到这里我的Demo

程序已经运行如飞了。

那么接下来就是来看看Z-Stack具体的一些东西了,我打算先这样看起:

1、Z-Stack的结构,因为打开Z-Stack的目录可以看出还是比较复杂的,只

有比较清楚了解其结构之后呢,在程序运行或者修改中才能顺利的找到自己想要

的部分。

2、Z-Stack的应用建立。就是怎么在TI提供的协议(裸协议)上建立一个

应用。这个层次要求就比较高了,我初步的设想是希望能分析完SAMPLE例子

的应用就能自己建立,而不需要太多的去了解下层的协议。但是往往希望与现实

是有偏差的,走一步算一步了。

3、了解硬件相关设定、驱动。也就是说把例子跑通了,毕竟是基于TI的

硬件,或者说基于开发系统的硬件,如果要做自己的应用,那么必须要开发自己

的硬件。怎么把自己的硬件驱动加入协议,这个我想也是需要解决的问题。

4、接下来可能就要深入分析协议了,这个目前我还不清楚从什么地方看起,

因为毕竟对ZIGBEE这个协议本身就不太了解,但是在学习过程中应该会慢慢对

它有认识。所以到了这一步的时候说不定我就已经摸索出一条方法了---毕竟俺是

相当的聪明嘛!

5、需要解决的问题,需要了解的东西很多,对于不太了解这个东西的我来

说,不可能非常有计划并统筹安排这些事,走弯路是必然的,但是我一致认为走

弯路才是经验的积累!

学习Z-Stack之6

--------------Z-Stack指导

首先来看看Z-Stack的结构。

第一次打开工程印象最深刻的就是左边一排文件夹,如图6-1所示。

其实这个还是很容易理解的:

APP(Application Programming):应用层目录,这是用户创建各种不同工程的区域,

在这个目录中包含了应用层的内容和这个项目的主要内容,在协议栈里面一般是以操作系统

的任务实现的。

HAL(Hardware (H/W) Abstraction Layer):硬件层目录,包含有与硬件相关的配置和驱

动及操作函数。

MAC:MAC 层目录,包含了MAC 层的参数配置文件及其MAC 的LIB 库的函数接

口文件。

MT(Monitor Test):实现通过串口可控各层,于各层进行直接交互。

NWK(ZigBee Network Layer):网络层目录,含网络层配置参数文件及网络层库的函

数接口文件,APS层库的函数接口

OSAL(Operating System (OS) Abstraction Layer):协议栈的操作系统。

Profile:AF(Application work)层目录,包含AF层处理函数文件。

Security:安全层目录,安全层处理函数,比如加密函数等。

Services:地址处理函数目录,包括着地址模式的定义及地址处理函数。

Tools:工程配置目录,包括空间划分及ZStack 相关配置信息。

ZDO(ZigBee Device Objects):ZDO 目录。

ZMac: MAC 层目录,包括MAC 层参数配置及MAC 层LIB 库函数回调处理函数。

ZMain:主函数目录,包括入口函数及硬件配置文件。

Output:输出文件目录,这个EW8051 IDE 自动生成的。

那么知道各个文件夹大概是什么功能,分布在ZIGBEE的哪一层,那么在以后的工作

中无论是查询某些功能函数还是修改某些功能函数,甚至是添加或删除某些功能函数就能顺

利的找到在什么地方了,当然要想真的顺利还需要花更多的时间熟悉这个协议栈了!

了解Z-Stack结构后那么就能看看它的功能。

不用问,这个是针对ZIGBEE无线网络写的协议栈,呵呵!那么就要先大概了解下

ZIGBEE这个技术。我这里就不介绍理论了,就从Z-Stack实际的角度介绍些实用的概念。

1、Zigbee网络中的节点

在ZB网络中,每个节点都有指定的配置参数,从而确定其设备类型,不同的设备类型,

在网络中有着不一样网络任务。在属于多跳网络的ZB网络中,两个节点需要完成数据传输,

可能需要经过其他中间节点的协助,所以节点的类型参数配置是非常必要的。

对每个节点有两个任务:

(i)执行指定的网络功能函数

(ii)配置确定的参数到指定的值。

网络功能的设置确定了该节点的类型,参数配置和指定的值确定了堆栈的模式。

节点类型

在ZB中,设备类型分为三类:协调器,路由器和终端设备。

图6-2就是这三种设备类型组成的一个典型网络。

其中黑色节点为协调器

红色节点为路由器

白色节点为终端设备

那么这个就是一个典型的网状网络MESH。

协调器

协调器是一个ZB网络的第一个开始的设备,或者是一个ZB网络的启动或建立网络

的设备。协调器节点选择一个信道和网络标志符(也叫PAN ID),然后开始建立一个网络。

协调器设备在网络中还可以有其他作用,比如建立安全机制、网络中的绑定的建立等等。

注意:协调器主要的作用是建立一个网络和配置该网络的性质参数。一旦这些完成,该协调

器就如同一个路由器,网络中的其他操作并不依赖该协调器,因为ZB是分布式网络。

路由器

一个路由器的功能有(1)作为普通设备加入网络(2)多跳路由(3)辅助其它的子

节点完成通信。

一般来说,路由器需要一直处于工作状态,所以需要主干线供电(区别于电池供电)。

但是在某指定的网络结构中可以采用电池供电,如―串树型‖网络模式中,允许路由器周期的

运行操作,所以可以采用电池供电。

终端设备

为了维持网络最基本的运行,对于终端设备没有指定的责任。也就是说,在一个基本

网络中,终端设备没有必不可缺少性。所以它可以根据自己功能需要休眠或唤醒,因此为电

池供电设备。一般来说,该设备需要的内存较少(特别是内部RAM)

堆栈模式(Stack Profile)

需要被配置为指定值的堆栈参数,连同这些值被称为堆栈模式。这些堆栈模式参数被

ZB联盟定义指定。在同一个网络中的设备必须符合同一个堆栈模式(同一个网络中所有设

备的堆栈模式配置参数必须一致)。

为了互操作性,ZB联盟为06协议栈定义了一个堆栈模式,所有的设备只要遵循该模

式的参数配置,即使在不同厂商买的不同设备同样可以形成网络。

如果应用开发者改变了这些参数配置,那么他的产品将不能与遵循ZB联盟定义模式

的产品组成网络,也就是说该开发者开发的产品具有特殊性,我们称之为―关闭的网络‖,也

就是说它的设备只有在自己的产品中使用,不能与其他产品通信。

该协议模式标志符在设备通信的信标传输中被匹配,如果不匹配,那么该设备将不能

加入网络。―关闭网络‖的堆栈模式有一个0ID,而06协议栈模式有一个1ID。该堆栈模式被

配置在nwk_globals.h文件中的STACK_PROFILE_ID参数。如:

#define STACK_PROFILE_ID HOME_CONTROLS。

2、Zigbee网络中的地址

地址类型

ZB设备有两种地址类型,一个是64位IEEE地址(也可以叫MAC地址或扩展地址),

一个是16位网络地址(也可以叫逻辑地址或短地址)。

64位地址是全球唯一的,作为设备(产品)的终生地址被分配。它通常被开发商或安

装的时候被指定。该地址由IEEE分配指定,该地址的信息和获得该地址的方法见:

/regauth/oui/

16位地址在设备加入网络的时候被分配,由这个网络自动分配。该地址只能用与本网

络中,标志不同的设备间传递信息。

网络地址分配

ZB分布式网络中地址分配是唯一的。为了不使网络中设备混乱,为每个设备指定确

定的地址是非常必要的。

在分配地址之前,一些参数必须被设置:MAX_DEPTH, MAX_ROUTERS 和

MAX_CHILDREN 。

这些参数都是ZB协议模式的一部分,在06ZS模式中这些参数设置为: (MAX_DEPTH

= 5, MAX_CHILDREN = 20, MAX_ROUTERS = 6).

参数设置

MAX_DEPTH决定了网络的最大深度。协调器的深度是0,它的子设备的深度是1,

他们的子设备的深度是2,依次类推。所以MAX_DEPTH参数限制了网络物理上的―长度‖

MAX_CHILDREN参数决定了一个路由器(或一个协调器)能承载子设备的最大数目。

MAX_ROUTERS参数决定了一个路由器(或一个协调器)能承载路由器的最大数目。

这个参数实际上是MAX_CHILDREN参数的一个子集,剩下的

(MAX_CHILDREN-MAX_ROUTERS)地址空间属于终端设备。

开发者自定义

如果开发者想改变这些值,那么需要做如下几步:

首先得保证这些参数新的值是合法的。既然整个地址空间被限制在2-16内,那么这些

参数的大小就已经有了限制。分布在release(在文件夹ProjectszstackTools中)的

文件能校验这些参数是否合法。在键入这些参数的值后大概这个电子表格,如果非法,一个

错误信息将给出。

之后选择合法的值,开发者需要确保不使用标准的协议栈模式,而用指定的协议栈模

式代替(用NETWORK_SPECIFIC替换STACK_PROFILE_ID当前的值)。然后在

―nwk_globals.h‖文件中的MAX_DEPTH参数根据需要设置为适当的值。

另外,nwk_globals.c文件中排列的CskipChldrn和CskipRtrs必须被设置,这些排列是

z-stack中的寻址

为了在网络中发送数据到一个设备,应用层一般用AF_DataRequest()函数。而被发送

的目的设备的地址类型afAddrType_t被定义在―ZComDef.h‖中:

typedef struct

{

union

{

uint16 shortAddr;

ZLongAddr_t extAddr;

} addr;

byte addrMode;

} zAddrType_t;

地址模式参数

注意:除这个网络地址之外,地址模式参数也需要被指定。目的地址模式可能是如下值之一

(AF地址模式被定义在―AF.h‖中):

typedef enum

{

afAddrNotPresent = AddrNotPresent,

afAddr16Bit = Addr16Bit,

afAddrGroup = AddrGroup,

afAddrBroadcast = AddrBroadcast

} afAddrMode_t;

地址模式参数是需要的,因为在ZB中,数据包能被点传输、多点传输或者广播传输。

点传输被发送到单个设备,多点传输一定发送到一组设备,广播传输一般被发送到网络中的

所有设备。如下是更详细的说明。

点到传输 (Unicast)

这是标准地址模式,被用于发送一个数据包到网络中单个已知地址的设备。这个

addrMode参数被设置为Addr16Bit,目的网络地址在数据包中一同被发送。

间接寻址

数据包中的最终目的地址不识别的时候使用。该模式被AddrNotPresent设置,而且目

的地址没有被指定。代替目的地址的是:一个存储在发送设备协议栈的―绑定表格‖,该表格

中有被绑定设备的地址。这个特性被调用是源于绑定。(看后面关于绑定部分)

当被发送的信息包下载到协议栈时,从这个绑定表格中寻找使用的目的地址。然后该信息包

被有规则的处理为点对点数据包。如果有多个(大于1)目的地址在绑定表格中被发现,那

么该数据包将被拷贝成对应的份数分别发送给他们。

在(ZigBee04)版本之前,在协调器中有一个存储绑定表格的选项。因此,发送设备发

送数据包到这个协调器,然后协调器在它的绑定表格中查找最终的目的地址,对数据包进行

在一次发送。该选项特性在协调器绑定被调用

广播传输

该模式在应用层想发送一个数据包到所有网络中的所有设备时被使用。该地址模式被

AddrBroadcast被设置,目的地址被设置为下列值之一:

NWK_BROADCAST_SHORTADDR_DEVALL (0xFFFF)-信息将被发送到网络中的所有设备

(包括休眠的设备)。对于休眠的设备,这个信息将被保持在它的父节点,直到该休眠设备

获得该信息或者该信息时间溢出(在 中的NWK_INDIRECT_MSG_TIMEOUT

选项)。

NWK_BROADCAST_SHORTADDR_DEVRXON (0xFFFD) –该信息将被发送到网络中有接

收器并处于IDLE(RXONWHENIDLE)状态下的所有设备。也就是说,除了休眠模式设备的

所有设备。

NWK_BROADCAST_SHORTADDR_DEVZCZR (0xFFFC) –该信息被发送到所有路由器(包

括协调器) 。

组地址

该模式用于应用层想发送一个数据包到一个设备组的时候。该地址模式被

afAddrGroup设置这个组标志符。

用该特性之前,在网络中,组不得不被定义[看ZStack API文档中的] aps_AddGroup()

注意:组能与间接寻址一起结合使用。该目的地址在绑定表格中发现,可以作为点对点或一

个组地址。也要注意广播地址可以当作是组被提前设置,一个简单的组寻址的特例,。

例子代码对于一个设备添加它自己到一个组标志符1:

aps_Group_t group;

// Assign yourself to group 1

= 0x0001;

[0] = 0; // This could be a human readable string

aps_AddGroup( SAMPLEAPP_ENDPOINT, &group );

重要设备地址

一个应用可以能想知道它自身和父节点的地址,用下面的函数可以得到设备的地址

(被定义在ZStack API文档中):

NLME_GetShortAddr() – 返回该设备的 16 位网络地址

NLME_GetExtAddr() –返回该设备的64 位扩展地址.

用下面的函数可以得到该设备的父节点的地址(被定义在ZStack API文档中)。注意该函数

在协调器中不被涉及到,但是被设备父节点代替(MAC协调器):

NLME_GetCoordShortAddr() – returns this device’s parent’s 16 bit short address.

NLME_GetCoordExtAddr() – returns this device’s parent’s 64 bit extended address.

先介绍这两个概念:节点和地址。其余的就改天继续!

学习Z-Stack之7

--------------Z-Stack指导2

上节介绍了很大一部分Z-Stack的基础知识,这里接着忽悠。虽然说的不是

很专业也不是很通俗,但是我尽力了,希望有人能看明白!本人英文水平有限,

翻译的不好请谅解!

3、绑定

绑定是控制信息从一个应用层到另一个应用层流动的一种机制。在ZB06

版本中,绑定机制在所有的设备中被执行。

绑定允许应用层发送信息不需要带目的地址,APS层确定目的地址从他的

绑定表格中,然后在信息前端加上这个目的地址或组。

注意:在ZB1.0版本中,所有绑定条目存储在协调器中。现在所有绑定条

目存储在发送数据的设备中。

3.1绑定一个绑定表格

有三种方式建立一个绑定表格:

ZDO 绑定请求 – 一个试运转工具能告诉这个设备制作一个绑定报告。

ZDO 终端设备绑定请求 – 2设备能告诉协调器他们想建立绑定表格报告。

该协调器将使协调并在这两个设备上创建绑定表格条目

设备应用 – 在设备上的应用能建立或管理一个绑定表格 。

任何一个设备或应用能在网络中发送一个ZDO信息到另一个设备()建立

一个绑定报告。这是调用绑定帮助并且它将建立一个绑定条目为发送设备。

3.1.1 ZDO 绑定请求

通过调用函数ZDP_BindReq()发送一个绑定请求。第一个参数(dstAddr)

是绑定的源地址的短地址。这之前应该确定允许绑定,在ZDConfig.h 文件中有

参数[ZDO_BIND_UNBIND_REQUEST]允许绑定。能用同样的参数调用函数

ZDP_UnbindReq()移除绑定。

目标设备将调用函数ZDApp_BindRsp()或 ZDApp_UnbindRsp(),反馈绑定

或移除绑定的响应,返回其操作状态为ZDP_SUCCESS, ZDP_TABLE_FULL或

ZDP_NOT_SUPPORTED.

3.1.2 ZDO 终端设备绑定请求

该机制是用一个按钮按下或其他类似的动作来选择设备在指定时间内被绑

定。在规定时间内,该终端设备绑定请求信息被收集到协调器,并创建一个基于

模式(profile) ID 和串(cluster) ID的规定的绑定表格条目。默认的终端设

备绑定超时时间(APS_DEFAULT_MAXBINDING_TIME)为16S(定义在

nwk_globals.h中),但是能被改变

发送绑定请求

在所有的应用例子中有一个处理键盘事件的函数[例如在TransmitApp.c文

件中的TransmitApp_HandleKeys()函数]。在该函数中,调用了函数

ZDApp_SendEndDeviceBindReq()[在ZDApp.c中],它将收集应用的终端设备的

所有信息并调用函数ZDP_EndDeviceBindReq() [ZDProfile.c],发送一个绑定信息

到协调器。或者,在SampleLight 和 SampleSwitch例子中,直接调用

ZDP_EndDeviceBindReq()函数就实现点亮/关闭灯的功能。

接收绑定请求

协调器将接收[ZDP_IncomingData() 在 ZDProfile.c]这些信息并分析处理

[ZDO_ProcessEndDeviceBindReq() 在 ZDObject.c]这些信息并调用函数

ZDApp_EndDeviceBindReqCB() [in ZDApp.c],它将调用

ZDO_MatchEndDeviceBind() [ZDObject.c]处理这个请求

当协调器接收到2个匹配终端色后备的绑定请求时,它将启动在绑定设备

上创建源绑定条目的处理过程。该协调器有如下处理过程:

解除绑定

1. 发送一个ZDO解除绑定请求到第一个设备。终端设备绑定切换处理,所

以解除绑定首先被发送到移除一个存在的绑定条目。

2. 等待ZDO解除绑定响应,如果响应状态为ZDP_NO_ENTRY, 发送一个

ZDO绑定请求,在源设备上制作一个绑定条目 。如果该响应为ZDP_SUCCESS,

为第一个设备继续到move on to the cluster ID for the first device (the unbind

removed the entry – toggle).

3. 等待ZDO绑定响应. When received, move on to the next cluster ID for the

first device.

4. 当第一个设备完成时,对第二个设备做同样的处理。

5. 当第二个设备完成时,发送ZDO 终端设备绑定响应信息到第一个和第

二个设备

3.1.3设备应用绑定管理

在设备上其他进入绑定条目的方式是应用层管理绑定表格。

意思是说,应用层将调用下列函数进入和移除绑定表格条目:

bindAddEntry() –增加绑定表格条目

bindRemoveEntry() – 从绑定表格中移除条目

bindRemoveClusterIdFromList() – 从一个存在的绑定表格项目中移除一个串

ID 。

bindAddClusterIdToList()——向一个已经存在的绑定记录中增加一个群ID

bindRemoveDev()——删除所有地址引用的记录

bindRemoveSrcDev()——删除所有源地址引用的记录

bindUpdateAddr()——将记录更新为另一个地址

bindFindExisting()——查找一个绑定表记录

bindIsClusterIdInList()——在表记录中检查一个已经存在的群ID

bindNumBoundTo()——拥有相同地址(源或者目的)的记录的个数

bindNumEntries()——表中记录的个数

bindCapacity()——最多允许的记录个数

bindWriteNV()——在NV中更新表

3.2 配置源绑定

允许绑定源的编译选项REFLECTOR在文件中。在文件

,中查看这两个绑定配置参数(NWK_MAX_BINDING_ENTRIES &

MAX_BINDING_CLUSTER_IDS)。NWK_MAX_BINDING_ENTRIES绑定表格

中最大的绑定实体数量参数;MAX_BINDING_CLUSTER_IDS 是在每个绑定实

体中最大的串ID数量。

绑定表在静态RAM中(未分配),因此绑定表中记录的个数,每条记录中群

ID的个数都实际影响着使用RAM的数量。每一条绑定记录是8字节多

(MAX_BINDING_CLUSTER_IDS * 2字节)。除了绑定表使用的静态RAM的数

量,绑定配置项目也影响地址管理器中的记录的个数。

4、路由

4.1 预览

在MESH网络中,为了使分布的节点间能够很好的通信,路由是非常重要

的一个环节。

在应用层上路由是完全透明的。一个简单的应用数据发送到任意设备,下

至协议栈,协议栈将负责发现一个路由路线。这个方式,应用层是不知道该操作

在多跳网络中完成的事实。

路由使ZB网络具有―自动复原‖的特性。如果一个无线连接断了,路由功能

将自动的发现一个新的路由路线,该路线是避开(绕过)坏了的那个连接节点。

这就提高了无线网络的可靠性,这也是ZB关键特点之一。

4.2 路由协议

ZB执行的路由协议是基于AODV(Ad hoc On demand Distance Vector)的

路由协议。作为一个简单的应用---传感器网络,ZB路由协议支持环境中的移动

节点,连接失败和丢包功能。

当一个路由器接收到一个点对点信息包时,从他的应用或者从其他设备,

NWK层将继续向前依照下面的进程。如果目的是路由器邻节点(包括它的子设

备)之一,该信息包将直接传输到目的设备。另外的就是,路由器将检查它的路

由表格,检查相应的信息包目的条目。如果在路由表格中有一个活跃的路由路线

到该目的设备,那么该信息包将被转播到下一跳节点地址存储依照路由条目。如

果没有活跃的条目发现,那么一个路由发现被启动并且该信息被缓存直到该过程

完成。

ZB终端设备路由

ZB终端设备不能执行任何路由功能。一个终端设备想发送一个信息包到任

何设备都要向前到它的父设备,然后在由其父设备进行路由操作。类似的,任何

设备想发送信息包到终端设备,都将发起一个路由发现操作,当然该操作都由终

端设备的父设备响应。

注意:ZB地址分配方案使基于它的地址发起一个路由到任何目的成为可

能。在Z-Sstack,这个机制被用于万一正规的路由程序不能被启动,作为一个自

动退却(一般情况是由于路由表格空间不够)。

z-stack路由

在z-stack,执行的路由是已经被优化的路由存储表格。一般情况,对于每

一个目的设备路由表格条目是需要的。但是通过综合携带父节点所有条目的特定

父节点的终端设备的所有条目,没有任何功能丢失的存储已经被优化。

ZB路由器,包括协调器,执行如下路由功能 (i)路由发现和选择 (ii) 路由

维护(iii)

4.2.1路由发现和选择

路由发现是网络设备协作发现和建立路由的一个过程。一个路由操作总是

针对某个目的,通过任何一个路由器启动。该路由发现机制在源设备和目的设备

间搜寻所有可能的路由并试图选择最好的路由路线。

? 路由选择通过选择最小消耗的路由路线。每个设备在连接到邻节点几乎保持不

变的―连接消耗‖。该连接消耗是接收信号的强度的一个典型功能。沿着路由路线

加起所有的连接消耗,就是整个路由的―连接消耗‖。路由算法试图选择这个路由

最小的―路由消耗‖。

路由请求

路由通过请求/响应信息包被发现。一个源设备为了一个目的地址,通过发

送一个广播路由请求(RREQ)信息到它的邻设备请求一个路由。当一个节点接

收到一个RREQ信息时,它将依次转播这个RREQ信息。但是在做这个之前,

它更新RREQ信息的消耗域,通过增加连接消耗为了最后的连接。这样,RREQ

信息将携带向前传输的所有的连接消耗。这个重复过程直到RREQ到达这个目

的设备。RREQ的一些复制可能经过不同的路径重复到达目的设备。该目的设备

选择最好的RREQ信息并发送一个路由答复(RREP)返回到源设备。

路由响应

RREP是沿着唯一的相反的路径返回到最初的请求节点。

作为RREP信息传播回源节点,中间的节点更新他们的路由表格,指出路

由路线到目的设备。

一旦一个路由被创建,数据包能被发送。当一个节点丢失到它下一个节点

的连通性时(发送数据包时,它不能接收一个MAC应答ACK),这个节点通过

发送一个RERR到所有潜在的接收它RREP的节点,使该路由无效。在接收一

个RREQ,RREP或RERR之上,这些节点都将更新他们的路由表格

4.2.2路由维护

MESH网络提供路由维护和自动修复。中间节点保持沿着连接传输失效的

路径。如故一个连接被确定坏了,逆流的节点将启动路由修复那些连接的所有路

由路线。这些工作通过启动路由重新发送被做,为了路由下一次数据包接收。如

果路由重新发现不能启动,或者由于某些原因失败了,一个路由错误(RERR)

信息被发送到这个数据包的源设备,然后重新启动新的路由发现。任意方式都使

得该路由得到重新自动建立。

4.2.3路由终结

为了建立路由,路由表格条目要被维护。如果一段时间没有数据包沿着路

由路线发送,该路由将被做终结记号。终止路由不是删除直到空间需要时。因此

没有被删除直到它完全需要时。自动路由终结时间能被配置―在"文

件中‖。设置ROUTE_EXPIRY_TIME参数为终结时间(秒)。设置0为了关闭路

由终结。

4.3 表格存储

路由功能需要路由器维护一些表格:

路由表格

路由发现表格

4.3.1路由表格

每一个路由器包括协调器都包含一个路由表。设备在路由表中保存数据包

参与路由所需的信息。每一条路由表记录都包含有目的地址,下一级节点和连接

状态。所有的数据包都通过相邻的一级节点发送到目的地址。同样,为了回收路

由表空间,可以终止路由表中的那些已经无用的路径记录。

路由表的容量表明一个设备路由表拥有一个自由路由表记录或者说它已经

有一个与目标地址相关的路由表记录。在文件―‖文件中配置路由表

的大小。将MAX_RTG_ENTRIES设置为表的大小(不能小于4)。

4.3.2路由发现表格

路由器设备致力于路径发现,保持维护路径发现表。这个表用来保存路径

发现过程中的临时信息。这些记录只在路径发现操作期间存在。一旦某个记录到

期,则它可以被另一个路径发现使用。这个值决定了在一个网络中,可以同时并

发执行的路径发现的最大个数。这个可以在文件中配置MAX_

RREQ_ENTRIES。

4.4、路径设置快速参考

设置路由表大小MAX_RTG_ENTRIES,这个值不能小于4 (

文件)

设置路径期满时间ROUTE_EXPIRY_TIME,单位秒。设置为零则关闭路径期满

(文件)

设置路径发现表大小 MAX_RREQ_ENTRIES,网络中可以同时执行的路径

发现操作的个数

学习ZStack之8

近段时间比较忙,几乎都快荒废了Z-Stack的学习了,把以前学的都快忘记

了,这就是非专业技术的痛苦啊!!学习刚好有点眉目,突然意外中断停下,当

再一次学习的时候突然发现:以前学的都忘了8成了!郁闷啊!今天真不知道从

什么地方下手学习了,所以就针对最近客户比较关心的问题做点介绍,这样有针

对性、有目的性的学习可能最适合现在的我了,不然从头把以前那些所谓的笔记

看一遍,可能今天晚上又没了,指不定明晚以及后晚以及后后晚…都没时间,不

然老是看以前的笔记没有进展就麻烦了!呵呵!

今天只解决1个问题:TI提供的例子程序的表演及功能介绍。

因为最近问这些的客户比较多,特别又是刚入手的朋友,对Z-Stack非常迷

糊的时期,如果能够跑通几个例子、看几个演示,那么可以大大提高学习兴趣;

另外如果知道某个例子的大致功能及实现,那么在去看具体实现过程目的性就非

常明确。

首先来看看TI究竟有哪些例子:

可以看出其例子是非常丰富的。

GenericApp,Location,SampleApp,SimpleApp,HomeAutomation,SerialApp,

Transmit,

ZLOAD。这样看来还是不少的。其中SampleApp例子已经在前面的学习中有所

涉及,可以说前面的所有学习都是基于这个例子的,所以这里就不测试它了。

Location是定位的测试例子,这里我的硬件是不够的,所以也不做测试。其他我

都做点测试,能成功的就成功,不能成功的就失败,这个我也没办法,呵

呵!!!!!!!!

1、GenericApp

工程打开等我就不多说了,自己去找,如果连这些我都还说,那么我以前

的东西是白学了。硬件连接中

当我用两个节点分别烧写入DB的协调器和路由器,从我的经验看来,他

们分别能建立网络和加入网络,但是从表象上几乎看不见数传现象,尽管我按了

每个节点的按键,也仅仅是本节点的LED在改变。唯独有点数传感觉的是:按

键右键对方有反应就是了,至于具体什么反映我觉得没必要说明白,大家试试就

知道了。

所以还决定看看程序来判断这个例子的功能。

大约浏览了下,这个例子似乎还与设备的绑定有关系,因为在按建处理程

序中发现:

if ( keys & HAL_KEY_SW_2 )

{

HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );

// Initiate an End Device Bind Request for the mandatory endpoint

de = Addr16Bit;

ddr = 0x0000; // Coordinator

ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(),

GenericApp_nt,

GENERICAPP_PROFID,

GENERICAPP_MAX_CLUSTERS, (cId_t

*)GenericApp_ClusterList,

GENERICAPP_MAX_CLUSTERS, (cId_t

*)GenericApp_ClusterList,

FALSE );

}

很明显这里按键2(右键)是发送绑定请求的命令。

if ( keys & HAL_KEY_SW_4 )

{

HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );

// Initiate a Match Deion Request (Service Discovery)

de = AddrBroadcast;

ddr = NWK_BROADCAST_SHORTADDR;

ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,

GENERICAPP_PROFID,

GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,

GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_ClusterList,

FALSE );

}

显然按键4(左)是初始化一个匹配描述符请求,也就是发现服务,或者叫自动

寻求匹配设备。

这就不怪我按键有反映了!

而且在发送数据和接收数据处理函数发现:

void GenericApp_SendTheMessage( void )

{

char theMessageData[] = "Hello World";

if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,

GENERICAPP_CLUSTERID,

(byte)osal_strlen( theMessageData ) + 1,

(byte *)&theMessageData,

&GenericApp_TransID,

AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) ==

afStatus_SUCCESS )

{

// Successfully requested to be sent.

}

else

{

// Error occurred in request to send.

}

}

居然发送的是一个字符串―Hello World‖。

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

switch ( pkt->clusterId )

{

case GENERICAPP_CLUSTERID:

// "the" message

#if defined( LCD_SUPPORTED )

HalLcdWriteScreen( (char*)pkt->, "rcvd" );

#elif defined( WIN32 )

WPRINTSTR( pkt-> );

#endif

break;

}

}

接收数据处理函数里居然要通过液晶显示,本人这里的液晶暂时没有移植过来,

因为暂时还不具备那个实力,怪不得看不到发送数据的状况!

这里本人就自作聪明的把以前SampleApp例子里面的一句话加过来了:

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

{

switch ( pkt->clusterId )

{

case GENERICAPP_CLUSTERID:

// "the" message

HalLedBlink( HAL_LED_4, 4, 50, (500) );

#if defined( LCD_SUPPORTED )

HalLcdWriteScreen( (char*)pkt->, "rcvd" );

#elif defined( WIN32 )

WPRINTSTR( pkt-> );

#endif

break;

}

}

麽想到啊,这么一加居然就有反应了,o(∩_∩)o…!我不愧是天才的接班人啊!

其实这里很简单的了,就是接收到数据后闪烁4下灯,间隔0.5S。因为从:

if ( events & GENERICAPP_SEND_MSG_EVT )

{

// Send "the" message

GenericApp_SendTheMessage();

// Setup to send message again

osal_start_timerEx( GenericApp_TaskID,

GENERICAPP_SEND_MSG_EVT,

GENERICAPP_SEND_MSG_TIMEOUT );

// return unprocessed events

return (events ^ GENERICAPP_SEND_MSG_EVT);

}

这里可以看出,这个例子很明显仅仅是个发送周期信息的例子。所以LED4就周

期性的闪烁4下,当然是协调器发送,路由器闪烁,路由器发送,协调器闪烁。

但是这例子里体现了绑定的概念,应该说是从基本功能上很齐全的一个例子,而

且在ZSTACK上实现无线网络数传,没有任何多余的功能。所以该例子是一个

典型的ZSTACK模板,也就是为用户提供了一个通用模板可以通过这个建立自

己的应用。关于如何在这个例子上建立、修改成自己的工程和应用项目详细见文

档:

Create New Application For The CC2430DB_F8W-2005-0033_.pdf

这个例子就到此结束了,否则不然就很难把下面的弄玩了!

2、SimpleApp

这个例子我基本跑通了,可是鉴于时间的关系,没有来得及打字了,所以就留到

下一次了,时间真是如流水啊-------------------快!

学习Z-Stack之9

接到昨天的继续忽悠,话说:

2、SimpleApp

―这个例子我基本跑通了,可是鉴于时间的关系,没有来得及打字了,所以就留

到下一次了,时间真是如流水啊-------------------快!….‖

这个例子里面有两个演示:一个是灯与开关的控制实验,一个温度传感器实验。

咱一个个来,不忙。

灯与开关实验

在这个例子中灯对应的工程名字为:SimpleControllerDB;开关对应:

SimpleSwitchDB。严重需要注意的地方,这里选用的是DB。因为从从零开始学

习Z-Stack之1上可以看到DB与EB的区别,而这里用DB的硬件就足以应付。

编译下载我就不继续罗嗦了。

咱关心的几个问题不外乎就是表演过程和表演结果,以及初步看看为什么

会有这样的结果产生,当然就得从程序上简单了解下。

首先打开Controller(也就是灯设备)的电源,那么LED2就会不停的闪烁,

这个时候是设备正在初始化,让您选择设备以哪种类型启动,从程序可以看出:

if ( keys & HAL_KEY_SW_1 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// Key 1 starts device as a coordinator

zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType );

if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )

{

logicalType = ZG_DEVICETYPE_COORDINATOR;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

}

// Do more configuration if necessary and then restart device with

auto-start bit set

// write endpoint to dont pass it in hen reset

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

如果按下S1(UP),那么作为协调器启动。

if ( keys & HAL_KEY_SW_2 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// Key 2 starts device as a router

zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType );

if ( logicalType != ZG_DEVICETYPE_ENDDEVICE )

{

logicalType = ZG_DEVICETYPE_ROUTER;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

}

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

如果按下S2(RIGHT),设备作为路由器启动。

这里由于是第一个启动的设备,所以作为协调器启动,就按下UP,此时灯

会有状态变化,最终结果是:LED2常亮,标示建立网络成功。如果您还有另外

的灯设备就可以按下RIGHT让他们都作为路由器启动,由于本人这里只有两个

节点,所以就只能有个协调器。

现在就来启动开关设备的电源,同样LED2会闪烁让您选择设备,但是在

ZIGBEE中除了协调器和路由器就剩下终端设备了,所以开关就只能作为终端被

启动,但是也需要通过按键来控制,从程序中可以看出:

if ( keys & HAL_KEY_SW_1 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// The Switch device is always an end-device

logicalType = ZG_DEVICETYPE_ENDDEVICE;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

// Do more configuration if necessary and then restart device with auto-start bit

set

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

else

{

// Initiate a binding with null destination

zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID, NULL);

}

}

if ( keys & HAL_KEY_SW_2 )

{

if ( myAppState == APP_INIT )

{

// In the init state, keys are used to indicate the logical mode.

// The Switch device is always an end-device

logicalType = ZG_DEVICETYPE_ENDDEVICE;

zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),

&logicalType);

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

startOptions = ZCD_STARTOPT_AUTO_START;

zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),

&startOptions );

zb_SystemReset();

}

else

{

// Send the command to toggle light

zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,

(uint8 *)NULL, myAppSeqNumber, 0, 0 );

}

}

无论是按下S1还是S2(UP或者RIGHT),开关设备均作为终端设备启动。

启动之后呢,灯的状态同样会发生一些变化,最终结果是:LED2快速闪烁,表

明此时开关已经成功加入刚才灯设备建立的那个网络了。

那么接下来就要看这个例子的核心部分----------绑定!

首先按下灯设备(这里为协调器,如果有路由器也可以)的UP,那么程序

中调用了:

zb_AllowBind( myAllowBindTimeout );

函数,允许绑定,这个允许的时间据说只有10S,当然这个时间是可以调整

的,因为这里的参数为:static uint8 myAllowBindTimeout = 10;至于这个时间怎么

计算的就需要到某个函数zb_AllowBind里去分析了。zb_AllowBind规定这个参

数为1~64,如果为0,表示为假,就是不允许绑定的意思。如果大于64的话,

就一直为真,就是一直都允许绑定。好像似乎是这个意思。至于这个10S是怎么

制定的呢,在这个函数内部调用了:

osal_start_timerEx(sapi_TaskID, ZB_ALLOW_BIND_TIMER, timeout*1000);

因为osal_start_timerEx定时函数最小单位为mS,所以*1000就表示S了。

而在SAPI_ProcessEvent事件处理函数中ZB_ALLOW_BIND_TIMER事件处理如

下:

if ( events & ZB_ALLOW_BIND_TIMER )

{

afSetMatch(sapi_Desc->EndPoint, FALSE);

return (events ^ ZB_ALLOW_BIND_TIMER);

}

也就是定时取消绑定状态!!!

如果有人看着这些看不明白,那就把这个例子多看几遍,多跑几遍。一般

如果您每天花费4个小时看这个例子,那么只需要一周事件,我想到时比我还精

通明白的!

所以在10S之内,开关必须发起绑定,此时同样按下开关设备的UP,那么

开关设备就调用了函数:zb_BindDevice(TRUE, TOGGLE_LIGHT_CMD_ID,

NULL);发送一个绑定请求去寻求绑定设备。

一个设备允许绑定,一个设备发起绑定请求,两个是您情我愿的,所以就

一拍即合,相当的登对!当然没有这么简单的哈,就如同两个人谈恋爱,至少也

需要是一男一女啊,两个都是男或女那就太不正常了,ZIGBEE是个国际化的标

准,当然不能有这种变态行为,所以也需要两个命令的属性是相反的,就例如这

里的控制灯开关的命令,对于灯来说这个命令为输入,而对于开关来说这个命令

是输出。所以一入一出刚好就登对。呵呵!!

绑定成功的表象是:开关设备的LED1快速闪烁。

void zb_AllowBindConfirm( uint16 source )

{

// Flash LED

HalLedSet( HAL_LED_1, HAL_LED_MODE_BLINK );

}

绑定成功了就可以发送灯控制命令了。按下RIGHT,调用了函数:

zb_SendDataRequest( 0xFFFE, TOGGLE_LIGHT_CMD_ID, 0,

(uint8 *)NULL, myAppSeqNumber, 0, 0 );

可以看出发送了一个数据请求,显然是广播发送的,而命令为切换灯状态的

TOGGLE_LIGHT_CMD_ID。当灯收到这命令,就有处理函数了:

void zb_ReceiveDataIndication( uint16 source, uint16 command, uint16 len, uint8

*pData )

{

if (command == TOGGLE_LIGHT_CMD_ID)

{

// Received application command to toggle the LED

HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE);

}

}

所以LED1显示状态发生改变。

此时这个例子已经接近尾声了,因为绑定成功开关能够控制灯了,但是既然可以

绑定那么也可以接触绑定的,如果按下开关的DOWN,那么同样调用了发送绑

定请求函数:

zb_BindDevice(FALSE, TOGGLE_LIGHT_CMD_ID, NULL);

只是这里第一个参数为FALSE,所以就能解除绑定。如果某个开关被解除了绑

定,那么此时就不能控制灯了。

在这个例子最后做个小结------绑定的好处。

绑定了之后,发送数据或者命令,就不需要设备的地址,因为这个命令只能在建

立绑定间的设备中传输。------------绝对是我的理解!

还有,一个开关可以绑定多个灯,同样,一个灯可以同时与多个开关发生

绑定。这个不代表本人观点,本人强力反对脚踏N只船!!!!!!

现在来简单分析下传感器的例子,由于前面灯的例子说的比较多,这里我

就说少点。

中心节点对应SimpleCollectorEB ,传感器节点对应SimpleSensorEB。这里

用到了EB,主要是因为DB没有串口硬件,而EB有,这个例子需要用到串口。

传感器的例子效果是:协调器可以收集传感器节点的温度信息并通过串口传输到

PC机,如下图所示:

可以看到能够看到节点的温度和电源电压。

具体实现与灯的例子稍区别,但是本质的原理是一样的,先选择设备类型,然后

建立绑定,最后收集信息。这里建立绑定的区别在于,只要中心节点允许绑定(与

前面操作一样),然后传感器节点是自动发送绑定请求的:

osal_start_timerEx( sapi_TaskID, MY_FIND_COLLECTOR_EVT,

myBindRetryDelay );

定时去产生发MY_FIND_COLLECTOR_EVT事件:

if ( event & MY_FIND_COLLECTOR_EVT )

{

// Find and bind to a collector device

zb_BindDevice( TRUE, SENSOR_REPORT_CMD_ID, (uint8 *)NULL );

}

这个事件就是发送绑定请求的。

至于绑定后的现象与前面一样了。

最后通过串口调试工具就能看到前面那个图的效果了!!!!!!!!!!!!!

这里的温度为42,这个肯定不可能的,不然我就被蒸发掉了哈!因为采用的是

芯片内部集成的温度传感器,这个传感器做实验还可以,因为可以看见温度的变

化,但是其准确性是在不敢恭维。TI也是的,做了温度传感器,还超级不准确,

还不如不做,只有还可以降低硬件成本,几乎没有任何使用价值!!!

发布评论

评论列表 (0)

  1. 暂无评论