文档库 最新最全的文档下载
当前位置:文档库 › 学习ZigBee入门

学习ZigBee入门

学习ZigBee入门

申明:学习zigbee入门,参考了零基础学zigbee文档资料等。

Zstack 情况:

采用TI 的Zstack1.4.3 协议,IAR7.30B版本

第一步:安装Zstack

从TI 官方网站上下载的Zstack 为:swrc072c.zip,我想这个压缩包大家都认识。解压之后为:ZStack- CC2430-1.4.3.exe 文件。这个安装文件大家都会了。默认安装路径为:C:\Texas Instruments\ZStack-1.4.3。安装之后在C:\Texas Instruments\ZStack-1.4.3 目录下有各PDF 文档为:Getting Started GuideCC2430.pdf,不用多说,这个肯定是要看的。既然把它放到这么前面,说明它是入门中的入门文档。下面就简单介绍下这个文档(注意哦,结合了我的开发套件):

1、介绍了安装ZStack-CC2430-1.4.3.exe 需要的硬件软件条件:需要电脑、操作系统为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、适用范围

本文档适用于CC2430开发板(具体的板子不同也会有差别)

2、产品包描述

2.1、安装包内容

这个就是上面提到的的ZStack-CC2430-1.4.3.exe 安装之后的所有内容了。说白了就是包含Zstack 开发所需要的所有软件和文

档资料等。

2.2、开发板介绍

C51RF-M套件,由一个网管,4个电池板(节点)组成一个zigbee硬件系统,当然了,还需要仿真板子,USB下载线,这样就OK了,可以玩zigbee了。

2.3、电缆

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

3、安装配置

3.1、主机配置

一台个人计算机,含有串口,USB接口就ok了

3.2、目标板需求

其实也是开发环境需求--- IAR EW8051。目前需要的版本为7.30B 及以上。要想开发好点的话,就要弄一点上位机软件来配套使用,Z-TOOLS等(我就用了无线龙公司的C51RF-WSN监控软件V3.00)

4、产品安装过程

4.1、安装Z-Stack

这个也就是安装ZStack-CC2430-1.4.3.exe 的过程。

4.2、IAR 安装

一般来说安装选择默认路径,但是自定义路径也不会出问题的。注意IAR 版本7.30B 及以上版本才可以运行 1.4.3 协议。

4.3、设备IEEE 地址

每个CC2430DB, CC2430EM,和CC2431EM 都已经排列了一个唯一的64 位物理地址(IEEE 地址),这个地址通过软件

SmartRF04 Flash Programmer已经写到了CC2430 内部FLASH 里面,用户也可以修改的,这个地址被写入到FLASH 的0x1FFF8 地址中,注意这个地址也可以更改的,通过些FLASH 软件,一般xFFFFFFFFFFFFFFFF 地址被认为是无效地址。

5、配置并试用Z-Stack

5.1、配置Z-Stack

这个详见 5.3 节。

5.2、逻辑类型

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

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

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

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

ZigBee 终端节点(ZED):该设备被配置为加入一个存在的网络,可以加入一个协调求或路由器。

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

基本上就是采用SampleApp 应用中的例子来演示整个流程,就是采用一个协调器和一个或多个路由器来形成一个ZigBee 网络演示。在该例子中主要通过我手中的一套C51RF-M套件来完成,配合一点外围设备。

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

首先要打开对应工程,C:\Texas Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\SampleApp\CC2430DB

\SampleApp,在工作窗口中选择CoordinatorEB,然后选择工程菜单(Project)下的全部编译(Rebuild All)选项,

然后选择工程菜单(Project)下的调试(Debug)选项,下载完之后就可以退出调试状态,通过选中调试菜单下的停止调试选项,按照此种方法下载至少两个RouterEB模块,就可以进行演示了。

6、Z-Stack 示范

详细的示范流程,这里先不说了,因为本人采用的硬件与原装有点差异,即使按照这个方法下载仍然不能演示,所以我必须进入程序把跳线判断程序进行简单必要的修改才能演示。该文档介绍的演示结果及现象都是基于CHIPCON 原厂评估板。

7. PanID 和通道(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 不同的值可以选择不同的频道,其频道如下所示。改协议默认-DDEFAULT_CHANLIST=0x00000800 // 11 - 0x0B

/* Default channel is Channel 11 - 0x0B */

// Channels are def ined in the following:

// 0 : 868 MHz 0x00000001

// 1 - 10 : 915 MHz 0x000007FE

// 11 - 26 : 2.4 GHz 0x07FFF800

//

//-DMAX_CHANNELS_868MHZ 0x00000001

//-DMAX_CHANNELS_915MHZ 0x000007FE

//-DMAX_CHANNELS_24GHZ 0x07FFF800

//-DDEFAULT_CHANLIST=0x04000000 // 26 - 0x1A

//-DDEFAULT_CHANLIST=0x02000000 // 25 - 0x19

//-DDEFAULT_CHANLIST=0x01000000 // 24 - 0x18

//-DDEFAULT_CHANLIST=0x00800000 // 23 - 0x17

//-DDEFAULT_CHANLIST=0x00400000 // 22 - 0x16

//-DDEFAULT_CHANLIST=0x00200000 // 21 - 0x15

//-DDEFAULT_CHANLIST=0x00100000 // 20 - 0x14

//-DDEFAULT_CHANLIST=0x00080000 // 19 - 0x13

//-DDEFAULT_CHANLIST=0x00040000 // 18 - 0x12

//-DDEFAULT_CHANLIST=0x00020000 // 17 - 0x11

//-DDEFAULT_CHANLIST=0x00010000 // 16 - 0x10

//-DDEFAULT_CHANLIST=0x00008000 // 15 - 0x0F

//-DDEFAULT_CHANLIST=0x00004000 // 14 - 0x0E

//-DDEFAULT_CHANLIST=0x00002000 // 13 - 0x0D

//-DDEFAULT_CHANLIST=0x00001000 // 12 - 0x0C

-DDEFAULT_CHANLIST=0x00000800 // 11 - 0x0B

/* Define the default PA N ID.

* Setting this to a v alue other than 0xFFFF causes

* ZDO_COORD to use this v alue as its PAN ID and

* Routers and end dev ices to join PAN with this ID

*/

//-DZDAPP_CONFIG_PAN_ID=0xFFFF

-DZDAPP_CONFIG_PAN_ID=0xFFFF

DEFAULT_CHANLIST 和ZDAPP_CONFIG_PAN_ID 都作为IAR IDE 中的编译选项可以进行设置,在应用文件中

的…\Projects\Tools\CC2430DB 目录下的f8wConf ig.cf g 文件中有相应设置。

Sample 例子演示

上节基本上初步认识了Zstack 的一些情况,今天继续我的学习,打开Sample例子看看,究竟ZIGBEE 是怎么回事。毫无疑问:如果是第一次打开这个例子工程,肯定很迷糊,因为此时我迷糊了。很多的文件夹,很多层,这么多文件夹,打开之后又有那么多文件,从何看起?不要着急,特别是有些人拿到之后,啥都不知道的人第一个问题就是:我要实现XXX,在哪修改或者在哪添加我的函数呢?凡是我遇到这样的客户,我就可以肯定他技术部咋的。就连我这个外行都知道,不把这些弄明白,就是实现XXX 只需要修改一个字母,那也不知道在哪改啊?所以我不急,但是我也理解很多客户,因为有时候项目催的比较急,毕竟老板都是外行嘛!两条路:1 就是先看主函数,2 就是看看TI 提供例子说明文档没有。我这里先看看主函数再说哈!因为我就知道从主函数看起. 没办法大概每个文件夹找啊,主函数的特征还是比较明明显的。

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

ZSEG int main( void )

{

// Turn off interrupts --关闭中断

osal_int_disable( INTS_ALL );

// Initialize HAL --初始化HAL(硬件相关的)

HAL_BOARD_INIT();

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

zmain_v dd_check();

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

zmain_ram_init();

// Initialize board I/O --初始化板载的I O口

InitBoard( OB_COLD );

// Initialze HAL driv ers --初始化HAL驱动

HalDriv erInit();

// Initialize NV System --初始化NV条目

osal_nv_init( NULL );

// Determine the extended address 决定长地址

zmain_ext_addr();

// Initialize basic NV items --初始化NV系统

zgInit();

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

ZMacInit();

#if ndef NONWK

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

afInit();

#endif

#if def LCD_SUPPORTED

HalLcdInit();

#endif

// Initialize the operating sy stem --初始化操作系统

osal_init_system();

// Allow interrupts --允许中断

osal_int_enable( INTS_ALL );

// Final board initialization --在初始化板子

InitBoard( OB_READY );

//HalLcdInit();

// Display inf ormation about this dev ice 显示设备信息

zmain_dev_inf o();

/* Display the dev ice inf o on the LCD */

#if def LCD_SUPPORTED

zmain_lcd_init();

#endif

osal_start_sy stem(); // No Return f rom here 没有反映了,进入OS操作系统了

} // main()

可以看到基本上都是初始化函数,因为函数名称都基本上带了init 字样的,呵呵,个人觉得TI 的变成习惯比我好,一看名称就知道大概功能了。所以这里也奉劝各位像我这样菜鸟级的初学者,一开始一定就要养成规范化编程的习惯,据说这样维护以及以后升级或

者移植兼容性都比较好。我就先不管各个初始化函数是怎么实现的,我先看看各个功能什么,现掌握整体功能在细化,我觉得这样的学习方法比较好,因为代码是在太多了,从一开始就逐句看,我敢保证没几个人有耐心看完看明白!幸好每个初始化函数都有一句说明,虽然是英文的,但是理解起来一点都不难的。关于每个函数的功能我就直接写在上面的程序里面,节省纸张哈!

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

主函数看完了又开始模糊了,又从何看起呢?在无从下手之际,只有去寻求TI说明文档的帮助了。上节不是漏掉了内容,是关于演示结果的,这里做上补充,怕因为缺调一点后面遇到什么不理解的就惨了!

Sample 例子演示演示现象:

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

上节提到了EM 和DB 两个板子,其硬件是不一样的。按键的定义---hal_key.h中,具体的功能定义在hal_key.c中

/-------------------hal_key.h---------------------/

/* Interrupt option - Enable or disable */

#def ine HAL_KEY_INTERRUPT_DISABLE 0x00 //--禁止中断

#def ine HAL_KEY_INTERRUPT_ENABLE 0x01 //--中断使能

/* Key state - shift or nornal */

#def ine HAL_KEY_STATE_NORMAL 0x00

#def ine HAL_KEY_STATE_SHIFT 0x01

/* Switches (keys) */

#def ine HAL_KEY_SW_1 0x01 // Joystick up

#def ine HAL_KEY_SW_2 0x02 // Joystick right

#def ine HAL_KEY_SW_5 0x04 // Joystick center

#def ine HAL_KEY_SW_4 0x08 // Joystick left

#def ine HAL_KEY_SW_3 0x10 // Joystick down

#def ine HAL_KEY_SW_6 0x20 // Button S1 if av ailable

#def ine HAL_KEY_SW_7 0x40 // Button S2 if av ailable

/* Joy stick */ //---游戏杆

#def ine HAL_KEY_UP 0x01 // Joy stick up

#def ine HAL_KEY_RIGHT 0x02 // Joy stick right

#def ine HAL_KEY_CENTER 0x04 // Joystick center

#def ine HAL_KEY_LEFT 0x08 // Joystick left

#def ine HAL_KEY_DOWN 0x10 // Joy stick down

//--------------------hal_key.c-----------------------------//

#def ine HAL_KEY_DEBOUNCE_VALUE 25 //--去抖动值

#def ine HAL_KEY_POLLING_VALUE 100 //--查询值

#if defined (HA L_BOA RD_CC2430EB) || defined (HA L_BOA RD_CC2430BB) //--EB/BB P0.6

#def ine HAL_KEY_SW_6_ENABLE

#def ine HAL_KEY_SW_6_PORT P0 /* Port location of SW1 */

#def ine HAL_KEY_SW_6_BIT HAL_KEY_BIT1 /* Bit location of SW1 */ //--SW1

#def ine HAL_KEY_SW_6_SEL P0SEL /* Port Select Register f or SW1 */

#def ine HAL_KEY_SW_6_DIR P0DIR /* Port Direction Register f or SW1 */

#def ine HAL_KEY_SW_6_IEN IEN1 /* Interrupt Enable Register f or SW1 */

#def ine HAL_KEY_SW_6_IENBIT HAL_KEY_BIT5 /* Interrupt Enable bit f or SW1 */

#def ine HAL_KEY_SW_6_EDGE HAL_KEY_RISING_EDGE /* T y pe of interrupt f or SW1 */

#def ine HAL_KEY_SW_6_EDGEBIT HAL_KEY_BIT0 /* EdgeTy pe enable bit SW1 */

#def ine HAL_KEY_SW_6_ICTL PICTL /* Port Interrupt Control f or SW1 */

#def ine HAL_KEY_SW_6_ICTLBIT HAL_KEY_BIT3 /* Interrupt enable bit f or SW1 */

#def ine HAL_KEY_SW_6_PXIFG P0IFG /* Port Interrupt Flag for SW1 */

#def ine HAL_KEY_P0INT_LOW_USED HAL_KEY_SW_6_BIT /* P0 can only be enabled/disabled as group of high or low nibble */

#endif //--注意条件编译的灵活使用

#if def ined (HAL_BOARD_CC2430BB) //--BB

#def ine HAL_KEY_POINT_HIGH_USED 0

#endif

#if def ined (HAL_BOARD_CC2430EB) //--EB

#def ine HAL_KEY_JOYSTICK_ENABLE

#def ine HAL_KEY_JOY_CHN HAL_ADC_CHANNEL_6 //--ADC采样的通道6

#def ine HAL_KEY_SW_5_ENABLE

#def ine HAL_KEY_SW_5_PORT P0 /* Port location of SW5 */

#def ine HAL_KEY_SW_5_BIT HAL_KEY_BIT5 /* Bit location of SW5 */

#def ine HAL_KEY_SW_5_SEL P0SEL /* Port Select Register f or SW5 */

#def ine HAL_KEY_SW_5_DIR P0DIR /* Port Direction Register f or SW5 */

#def ine HAL_KEY_SW_5_INP P0INP /* Port Input Mode Register f or SW5 */

#def ine HAL_KEY_SW_5_IEN IEN1 /* Interrupt Enable Register f or SW5 */

#def ine HAL_KEY_SW_5_IENBIT HAL_KEY_BIT5 /* Interrupt Enable bit f or SW5 */

#def ine HAL_KEY_SW_5_EDGE HAL_KEY_RISING_EDGE /* T y pe of interrupt f or SW5 */

#def ine HAL_KEY_SW_5_EDGEBIT HAL_KEY_BIT2 /* EdgeTy pe enable bit SW5 */

#def ine HAL_KEY_SW_5_ICTL PICTL /* Port Interrupt Control f or SW5 */

#def ine HAL_KEY_SW_5_ICTLBIT HAL_KEY_BIT4 /* Interrupt enable bit f or SW5 */

#def ine HAL_KEY_SW_5_PXIFG P0IFG /* Port Interrupt Flag for SW5 */

#def ine HAL_KEY_POINT_HIGH_USED HAL_KEY_SW_5_BIT /* P0 can only be enabled/disabled as group of high or low nibble */

#endif

/**************************************----LED定义相关----*****************************/

//----------------------------hal_led.h-------------------------------

/* LEDS - The LED number is the same as the bit position */

#def ine HAL_LED_1 0x01

#def ine HAL_LED_2 0x02

#def ine HAL_LED_3 0x04

#def ine HAL_LED_4 0x08

#def ine HAL_LED_ALL (HAL_LED_1 | HAL_LED_2 | HAL_LED_3 | HAL_LED_4)

/* Modes */

#def ine HAL_LED_MODE_OFF 0x00

#def ine HAL_LED_MODE_ON 0x01

#def ine HAL_LED_MODE_BLINK 0x02

#def ine HAL_LED_MODE_FLASH 0x04

#def ine HAL_LED_MODE_TOGGLE 0x08

/* Def aults */

#def ine HAL_LED_DEFAULT_MAX_LEDS 4

#def ine HAL_LED_DEFAULT_DUTY_CYCLE 5

#def ine HAL_LED_DEFAULT_FLASH_COUNT 50

#def ine HAL_LED_DEFAULT_FLASH_TIME 1000

//-------------------------hal_board_cfg.h-------------------------------//

//-----------LED Conf iguration

#def ine HAL_NUM_LEDS 2

#def ine HAL_LED_BLINK_DELAY() st( { volatile uint32 i; f or (i=0; i<0x5800; i++) { }; } )

/* 1 - Green */

#def ine LED1_BV BV(0)

#def ine LED1_SBIT P1_0

#def ine LED1_DDR P1DIR

#def ine LED1_POLARITY ACTIVE_LOW

/* 2 - Red */

#def ine LED2_BV BV(1)

#def ine LED2_SBIT P1_1

#def ine LED2_DDR P1DIR

#def ine LED2_POLARITY ACTIVE_LOW

/* 3 - Yellow */

#def ine LED3_BV BV(1)

#def ine LED3_SBIT P1_1

#def ine LED3_DDR P1DIR

#def ine LED3_POLARITY ACTIVE_LOW

/* 4 - Blue */

#def ine LED4_BV BV(0)

#def ine LED4_SBIT P1_0

#def ine LED4_DDR P1DIR

#def ine LED4_POLARITY ACTIVE_LOW

关于上面出现的LEDx 实际上是程序中出现的关键字。

2、初始化64 位IEEE 地址--很重要哦

实际上在主函数中有这么个初始化函数的:zmain_ext_addr()。这里说如果地址复位为0xFFFFFFFFFFFFFFFF 的话,那么就会不停的闪烁LED1,一直等到按键SW5 (P0_5)按下后程序才能继续运行,意思就是说按下SW5 后就把无效的地址初始化为有效地物理地址了,这个应该是程序上实现的,那么就来看看对应的程序zmain_ext_addr。

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

* @f n 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 f or uninitialized v alue (erased EEPROM = 0xFF)检查是否为无效值(地址)

xad = (uint8*)&aExtendedAddress;

f or ( i = 0; i < Z_EXTADDR_LEN; i++ )

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

tmp = 0x10;

#else

tmp = 0x20;

#endif

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

xad = (uint8*)&aExtendedAddress;

f or ( 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 != HalKey Read() )---------------------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 !def ined( ZTOOL_POR T ) || def ined( ZPORT ) || def ined( NV_RESTORE)

// If no support f or 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、运行例子及现象观察

协调器:上电运行,地址检测如上面介绍的情况,通过之后呢---就进行通道扫描(channl 和PANID),此时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 指导文档。这个文档个人觉得写的不错,要是没看之前就看程序的却很郁闷的!

Sample A pplication 分析-上

1、Z-Stack CC2430DB and CC2430EB Sample Application

1.1、介绍

该文档时介绍TI 协议入门的一个例子SampleApp 的,适用EB开发板。

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()初始化任务(特别说明一下osalAddTasks()函数在ZStack-1.4.3-1.2.1中被省略掉了)

1.2.2、组织

关于OS 的API 函数介绍请看文档:Z-Stack OSA L A PI (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(如SampleApp_Init)。该任务初始化函数应该完成如下功能:变量或相应应用对象特征初始化,为了使OSAL 内存管理更有效,在这里应该分配永久堆栈存储区;在AF 层登记相应应用对象(如:

af Register());登记可用的OSAL 或HAL 系统服务(如:RegisterForKey s())

1.2.5.2、任务事件处理

调用如下函数处理任务事件:―Application Name‖_ProcessEv ent (e.g. SampleApp_ProcessEv ent()).除了强制的事件之外,任一OSAL 任务能被定义多达15 个任务事件。

1.2.6、强制事件

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

1.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.26.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_AU TO_STAR T 必须被定义。为了稍后以手动启动方式启动设备,那么需要调用

ZDApp_StartUpFromApp()函数

1.3.2、软件启动

为了在形成网络过程中节省所需的设备类型,那么所有的路由器设备可以被通过SOFT_START定义作为一个协调器。如果自动启动是需要的话,那么AUTO_SOFT_STAR T必须被定义。

1.3.3、网络恢复

通过设置NV_RESTORE 和/或NV_INIT,可以让设备断电或者意外掉电重新启动后重新回复网络。

1.3.4、加入通告

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

Sample Application 分析(下)

上节介绍了建立一个应用需要做的几个必须的事情,现在就来通过分析SampleApplication 来具体看看需要做哪些事情,才能建立一个ZIGBEE 应用功能。当然这里只是做点简单的必须的工作。

The Sample A pplication (SampleA pp)

1、介绍

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

1.1、程序流程

1.1.1、初始化

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

SampleApp_TaskID = task_id;

初始化应用建立的任务ID 号,这是工作的ID ,SampleApp必须使用自己设置一个定时器,来为自己制定了一个事件,或者发OS 信息本身。上述行动的任何一个可能做是为了分裂一大块加工成较小的连续上执行―时段的,而不是采取单一的时间段太多时间OS‖块了。当一个任务划分成更小的是每次执行一个插槽大块大块的工作,任务是以进行―合作‖行为的OS任务设计的必要条件。

SampleApp_N wkState = DEV_INIT;

初始化应用设备的网络状态。怎么说呢,据说是设备类型的改变都要产生一个事件,叫ZDO_STATE_CHANGE,从字面理解为ZDO 状态发生了改变。所以在设备初始化的时候一定要把它初始化为什么状态都没有。那么它就要去检测整个环境,看是否能重新建立或者加入存在的网络。但是有一种情况例外,就是当NV_RESTORE 被设置的时候(NV_RESTORE 是把信息保存在非易失存储器中),那么当设备断电或者某种意外重启时,由于网络状态存储在非易失存储器中,那么此时就只需要恢复其网络状态,而不需要重新建立或者加入网络了。我也是从文档中这么理解的,至于为什么只有有待进一步考证。

SampleApp_DstAddr.addrMode = (af AddrMode_t)AddrNotPresent;

SampleApp_DstAddr.endPoint = 0;

SampleApp_DstAddr.addr.shortAddr = 0;

看见这几句话从字面理解为:初始化不标设备地址模式及目标设备EP号和网络地址。从代码可以看出,这些地址或EP均为0。也就是说目标设备为协调者的ZDO,这个意义就很明显了,就是设备建立后可以直接与协调器的ZDO交互信息。

SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;//--SampleApp EP描述符的EP号

SampleApp_epDesc.task_id = &SampleApp_TaskID; //-- SampleApp EP描述符的任务ID

SampleApp_epDesc.simpleDesc = //-- SampleApp EP简单描述符

SimpleDeionFormat_t *)&SampleApp_SimpleDesc;

SampleApp_https://www.wendangku.net/doc/0e16535395.html,tency Req = noLatency Reqs;

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

af Register( &SampleApp_epDesc );

这里其实是对SampleApp的EP描述符进行初始化.本人理解:要对改应用进行初始化并在AF进行登记,告诉应用层有这么一个

EP已经可以使用,那么下层要是有关于改应用的信息或者应用要对下层做哪些操作,就自动得到下层的配合,至于这个配合是怎么回事,那么就需要好好研究下层的协议了。当然在这里肯定是没那时间精力和能力研究了!其实在这个应用中,只是让AF配合SAMPLEAPP_PROFID / SAMPLEAPP_ENDPOINT这两个应用。那么通过什么呢,通过发送OSAL SYS_EVENT_MSG消息中的(AF_INCOMING_MSG_CMD)事件到SampleApp任务ID。

RegisterForKey s( SampleApp_TaskID );

登记按键事件到SampleApp_TaskID,在前面已经说了按键这个是唯一的,也就是所有任务中有且只有各任务能登记键盘事件。前面还说了还有一个也是唯一,你猜是什么??

SampleApp_Group.ID = 0x0001;

osal_memcpy( SampleApp_https://www.wendangku.net/doc/0e16535395.html,, ―Group1‖ );

aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );

闪灯信息被发送到组1,同样也只有在组1的设备才能接收这个信息。设备启动时已经被设定为组1设备了,但是可以通过按SW1推出/加入组1。这里提到了组的概念,我反正暂时不是很清楚这个是什么东西,在程序中怎么实现也很模糊,但是应用中的好处还是不难想象的,不外呼是就是想控制谁可以事先规定好,还可以动态更改。

1.2、事件处理

玩过OS 的人都知道,OS 中最重要的概念不外呼就是任务啦,消息啦,事件啦等。从我们自己平时的工作中也不难想象,如果老板安排了某项工作,那么我们就需要做的,这个工作可能是预先计划好的,也有可能是临时的,那么这些预先定好或者临时的工作可以称之为事件。而老板让您做的方式,比如通过文件下达,或者叫:某某你把XXX 做下。那么让老板下达的文件内容或者说的内容我这里可以称之为消息。老板给了你不同的消息那么就需要干不同的事件,至于任务可以理解为公司的不同的员工,呵呵!我简直是理解的天才,这样举例居然也能忽悠通过!!!o(∩_∩)o…哈哈言归正传在Z-Stack 中,每个应用任务都通过SampleApp_ProcessEv ent()函数来处理任务中的事件。一旦SampleApp_TaskID 任务的某个OSAL 事件发生,那么就可以通过调用SampleApp_ProcessEv ent()函数来处理。在SampleApp_ProcessEv ent()中有一个事件处理循环,循环检测是哪个事件发生。

if ( ev ents & SYS_EVENT_MSG )

{

MSGpkt = (af IncomingMSGPacket_t*)osal_msg_receiv e( SampleApp_TaskID );

while ( MSGpkt )

{ …………………………………..

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

switch ( MSGpkt->hdr.ev ent )

这里是判断SYS_EVENT_MSG 事件类型,不同的SYS_EVEN T_MSG 类型需要不同的处理。

case KEY_CHANGE:

SampleApp_HandleKey s( ((key Change_t *)MSGpkt)->state,

((keyChange_t *)MSGpkt)->key s );

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 ty pe [def ined in ZComDef.h]

// The message f ields are def ined in AF.h

af DataConf irm = (afDataConf irm_t *)MSGpkt;

sentEP = afDataConf irm->endpoint;

sentStatus = afDataConf irm->hdr.status;

sentTransID = af DataConf irm->transID;

任何AF_DataRequest()数据请求函数调用后,都通过AF_DATA_CONFIRM_C MD 系统事件信息回叫返回成功Zsuccess。

case ZDO_STATE_CHANGE:

SampleApp_N wkState = (dev States_t)(MSGpkt->hdr.status);

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 interv al.

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_PERIODIC_MSG_TI MEOU T );

}

break;

这里就是前面介绍的设备状态改变事件处理了。只要网络状态发生改变,那么通过ZDO_STATE_CHANGE 事件通知所有的任务。注意:在这个例子中,一旦设备成功加入网络,是通过定时运行的方式运行的。一旦网络状态为加入‖JOINED‖,那么它可能不需要任何的认为操作就能绑定其他设备,因为设置为自动发现并绑定的。

// Release the memory

osal_msg_deallocate( (uint8 *)MSGpkt );

释放存储空间。

if ( ev ents & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )

{

// Send "the" message

SampleApp_SendPeriodic Message();

// Setup to send message again

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

SAMPLEAPP_SEND_MSG_TIMEOUT );

// return unprocessed ev ents

return (ev ents ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);

}

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

在SampleApp.h 中定义了:

#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT 0x0001

在这个应用中,调用了osal_start_timer()函数来定时产生发送周期信息事件。而定时器的运行是设备一旦加入网络就不停的在运行。从上面可以看到,用函数SampleA pp_SendPeriodicMessage()发送周期信息,而用函数

osal_start_timer( SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_MSG_TIMEOUT )来继续运行定时器定时发送这个周期信息。关于这个osal_start_timer 可以多了解下,第一个参数SAMPLEAPP_SEND_PERIODIC_MSG_EVT 是信息时间,也就是事件到了产生一个什么事件。第二各参数SAMPLEAPP_SEND_MSG_TI MEOUT 是需要定时的时间,这里就是发送周期信息的时间周期。

1.3、消息流程

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

v oid SampleApp_SendPeriodic Message( v oid )

{

af AddrTy pe_t dstAddr;

dstAddr. addrMode = af AddrBroadcast;

dstAddr.addr.shortAddr = 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 ) == af Status_SUCCESS )

{

// Successf ully 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 )。

v oid SampleApp_MessageMSGCB( af IncomingMSGPacket_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:

f lashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );

HalLedBlink( HAL_LED_4, 4, 50, (f lashTime / 4) );

break;

}

}

这里判断了两种信息:周期信息闪灯信息不同的信息就相当于收到了不同的命令,然后根据不同的命令做出了不同的处理。是个会写程序都明白!到这里,我就基本上把这个应用文档看完了,至于理解了多少我迷糊,理解正确了多少我更加迷糊,反正我按照我自己的方式理解了!

前面虽然写了不少,太技术化了,这个不是我的本意。不知道前面写的怎么样,技术含量肯定是不高的。这个本人是相当清楚,但是我最大的期望就是错误不要太多!突然想起来前面有个问题没有解决,我想很多人看到那里都很郁闷的。就是设备类型的选择,在TI 原

装系统上是通过板载跳线来选择的,但是我这里不是采用原装,那么就需要通过程序来修改其设备类型,然后编译下载。具体程序段如下:

#if def ined ( SOFT_ST ART )

if ( readCoordinatorJumper() )

zgDev iceLogicalT y pe = ZG_DEVICETYPE_COORDINATOR;

else

zgDev iceLogicalT y pe = ZG_DEVICETYPE_ROUTER;

#endif // SOFT_ST ART

这里有个条件编译,其条件编译设置如下:C/C++ Compiler /Preprocessor /Def ined sy mblos (进行删除和添加操作即可),既然这里设置了SOFT_START,那么上段程序就要被编译。那么第一句程序

if ( readCoordinatorJumper() )

就是检测跳线(开发板上带有的),其实稍微知道编程的都了解怎么修改了,哈哈!

屏蔽:/*

if ( readCoordinatorJumper() )

zgDev iceLogicalT y pe = ZG_DEVICETYPE_COORDINATOR;

else */

这 3 句,那么就只剩下:zgDev iceLogicalT y pe = ZG_DEVICETYPE_ROUTER;了那么编译自然该设备就为路由器了。简单吧!协调器我就不想多说怎么做了哈,同样道理的!还有一个问题需要说下,就是Ti 原装的EM 板子用到了LCD,所以在程序中可能在某个地方要对LCD 初始化,那么如果没有液晶的板子或者与TI 那个不完全一

样的LCD 就有可能运行不走,通俗的解决办法是禁止LCD 初始化等操作,Ti 在这个方面做的很人性化,禁止LCD 功能没有必要在程序中找到LCD 相关程序删除,而是仅仅需要通过条件编译来禁止。显得相当简单,C/C++ Compiler /Preprocessor /Def ined sy mblos ,删除LCD 的条件编译。解决这个问题后一般都能够运行程序了。也就是说到这里如果还把演示程序运行不起来的话,那就证明我所有的东西都白写了,反正我到这里我的演示程序已经运行如飞了。

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

1、Z-Stack 的结构,因为打开Z-Stack 的目录可以看出还是比较复杂的,只有比较清楚了解其结构之后呢,在程序运行或者修改中才能顺利的找到自己想要的部分。

2、Z-Stack 的应用建立。就是怎么在TI 提供的协议(裸协议)上建立一个应用。这个层次要求就比较高了,我初步的设想是希望能分析完SAMPLE 例子的应用就能自己建立,而不需要太多的去了解下层的协议。但是往往希望与现实是有偏差的,走一步算一步了。

3、了解硬件相关设定、驱动。也就是说把例子跑通了,毕竟是基于TI 的硬件,或者说基于开发系统的硬件,如果要做自己的应用,那么必须要开发自己的硬件。怎么把自己的硬件驱动加入协议,这个我想也是需要解决的问题。

4、接下来可能就要深入分析协议了,这个目前我还不清楚从什么地方看起,因为毕竟对ZIGBEE 这个协议本身就不太了解,但是在学习过程中应该会慢慢对它有认识。所以到了这一步的时候说不定我就已经摸索出一条方法了---毕竟俺是相当的聪明嘛!?

5、需要解决的问题,需要了解的东西很多,对于不太了解这个东西的我来说,不可能非常有计划并统筹安排这些事,走弯路是必然的,但是我一致认为走弯路才是经验的积累!--------------------------------

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

第一次打开工程印象最

深刻的就是左边一排文件夹,如图所示。其实这个还是很容易理解的:APP(Application Programming):应用层目录,这是用户创建各种不同工程的区域,在这个目录中包含了应用层的内容和这个项目的主要内容,在协议栈里面一般是以操作系统的任务实现的。HA L(Hardware (H/W) Abstraction Lay er):硬件层目录,包含有与硬件相关的配置和驱动及操作函数。

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

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

NWK(ZigBee Network Lay er):网络层目录,含网络层配置参数文件及网络层库的函数接口文件,APS 层库的函数接口

OSA L(Operating Sy stem (OS) Abstraction Lay er):协议栈的操作系统。

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

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

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

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

ZDO(ZigBee Dev ice 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 中,设备类型分为三类:协调器,路由器和终端设备。

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

其中黑色节点为协调器,红色节点为路由器,白色节点为终端设备

那么这个就是一个典型的网状网络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 参数。如:#def ine

STACK_PROFILE_ID HOME_CONTROLS。

2、Zigbee 网络中的地址

地址类型

ZB 设备有两种地址类型,一个是64 位IEEE 地址(也可以叫MAC 地址或扩展地址),一个是16 位网络地址(也可以叫逻辑地址或短地址)。64 位地址是全球唯一的,作为设备(产品)的终生地址被分配。它通常被开发商或安装的时候被指定。该地址由IEEE 分配指定,该地址的信息和获得该地址的方法见:https://www.wendangku.net/doc/0e16535395.html,/regauth/oui/index.shtml,16位地址在设备加入网络的时候被分配,由这个网络自动分配。该地址只能用与本网络中,标志不同的设备间传递信息。

网络地址分配

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

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

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

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

参数设置

MAX_DEPTH 决定了网络的最大深度。协调器的深度是0,它的子设备的深度是1,他们的子设备的深度是2,依次类推。所以MAX_DEPTH 参数限制了网络物理上的―长度‖,MAX_CHILDREN 参数决定了一个路由器(或一个协调器)能承载子设备的最大数目。MAX_ROU TERS 参数决定了一个路由器(或一个协调器)能承载路由器的最大数目。这个参数实际上是MAX_CHILDREN 参数的一个子集,剩下的

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

开发者自定义

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

首先得保证这些参数新的值是合法的。既然整个地址空间被限制在2-16 内,那么这些参数的大小就已经有了限制。分布在release(在文件夹Projects\zstack\Tools 中)的Cskip.xls 文件能校验这些参数是否合法。在键入这些参数的值后大概这个电子表格,如果非法,一个错误信息将给出。之后选择合法的值,开发者需要确保不使用标准的协议栈模式,而用指定的协议栈模式代替(用NETWORK_SPECIFIC 替换STACK_PROFILE_ID 当前的值)。然后在―nwk_globals.h‖文件中的MAX_DEPTH 参数根据需要设置为适当的值。另外,nwk_globals.c文件中排列的CskipChldrn 和CskipRtrs 必须被设置,这些排列是z-stack 中的寻址为了在网络中发送数据到一个设备,应用层一般用AF_DataRequest()函数。而被发送的目的设备的地址类型af AddrTy pe_t 被定义在―ZComDef.h‖中:

ty pedef struct

{

union

{

uint16 shortAddr;

ZLongAddr_t extAddr;

} addr;

byte addrMode;

} zAddrTy pe_t;

地址模式参数

注意:除这个网络地址之外,地址模式参数也需要被指定。目的地址模式可能是如下值之一(AF 地址模式被定义在―AF.h‖中):

ty pedef enum

{

af AddrNotPresent = AddrNotPresent,

af Addr16Bit = Addr16Bit,

af AddrGroup = AddrGroup,

af AddrBroadcast = AddrBroadcast

} af AddrMode_t;

地址模式参数是需要的,因为在ZB 中,数据包能被点传输、多点传输或者广播传输。点传输被发送到单个设备,多点传输一定发送到一组设备,广播传输一般被发送到网络中的所有设备。如下是更详细的说明。

点到传输(Unicast)

这是标准地址模式,被用于发送一个数据包到网络中单个已知地址的设备。这个addrMode 参数被设置为Addr16Bit,目的网络地址在数据包中一同被发送。

间接寻址

数据包中的最终目的地址不识别的时候使用。该模式被AddrNotPresent 设置,而且目的地址没有被指定。代替目的地址的是:一个存储在发送设备协议栈的―绑定表格‖,该表格中有被绑定设备的地址。这个特性被调用是源于绑定。(看后面关于绑定部分)当被发送的信息包下载到协议栈时,从这个绑定表格中寻找使用的目的地址。然后该信息包被有规则的处理为点对点数据包。如果有多个(大于1)目的地址在绑定表格中被发现,那么该数据包将被拷贝成对应的份数分别发送给他们。在(ZigBee04)版本之前,在协调器中有一个存储

绑定表格的选项。因此,发送设备发送数据包到这个协调器,然后协调器在它的绑定表格中查找最终的目的地址,对数据包进行在一次发送。该选项特性在协调器绑定被调用

广播传输

该模式在应用层想发送一个数据包到所有网络中的所有设备时被使用。该地址模式被AddrBroadcast 被设置,目的地址被设置为下列值之一:

NWK_BROADCAST_SHORTADDR_DEVALL (0xFFFF)-信息将被发送到网络中的所有设备(包括休眠的设备)。对于休眠的设备,这个信息将被保持在它的父节点,直到该休眠设备获得该信息或者该信息时间溢出(在f8wConf ig.cf g 中的NWK_INDIRECT_MSG_TI MEOU T 选项)。

NWK_BROADCAST_SHORTADDR_DEVR XON (0xFFFD) –该信息将被发送到网络中有接收器并处于IDLE(R XONWHENIDLE)状态下的所有设备。也就是说,除了休眠模式设备的所有设备。

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

组地址

该模式用于应用层想发送一个数据包到一个设备组的时候。该地址模式被af AddrGroup 设置这个组标志符。用该特性之前,在网络中,组不得不被定义[ 看ZStack API 文档中的] aps_AddGroup() 注意:组能与间接寻址一起结合使用。该目的地址在绑定表格中发现,可以作为点对点或一个组地址。也要注意广播地址可以当作是组被提前设置,一个简单的组寻址的特例。例子代码对于一个设备添加它自己到一个组标志符1:

aps_Group_t group;

// Assign y ourself to group 1

group.ID = 0x0001;

https://www.wendangku.net/doc/0e16535395.html,[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() –返回本设备的父亲设备的16位网络地址

NLME_GetCoordExtAddr() –返回本设备的父亲设备的64位扩展地址

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

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

上节介绍了很大一部分Z-Stack 的基础知识,这里接着忽悠。虽然说的不是很专业也不是很通俗,但是我尽力了,希望有人能看明白!本人英文水平有限,翻译的不好请谅解!

3、绑定

绑定是控制信息从一个应用层到另一个应用层流动的一种机制。在zigbee06 版本中,绑定机制在所有的设备中被执行。绑定允许应用层发送信息不需要带目的地址,APS 层确定目的地址从他的绑定表格中,然后在信息前端加上这个目的地址或组。注意:在zigbee1.0 版本中,所有绑定条目存储在协调器中。现在所有绑定条目存储在发送数据的设备中。

3.1 绑定一个绑定表格

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

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

ZDO 终端设备绑定请求--一个设备能告诉协调器他们想建立绑定表格报告。该协调器将使协调并在这两个设备上创建绑定表格条目

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

任何一个设备或应用能在网络中发送一个ZDO 信息到另一个设备,用来建立一个绑定报告。这是调用绑定帮助并且它将建立一个绑定条目为发送设备。

3.1.1 ZDO 绑定请求

通过调用函数ZDP_BindReq()(在ZDProf ile.h)发送一个绑定请求。第一个参数(dstAddr)是绑定的源地址的短地址。这之前应该确定允许绑定,在ZDConf ig.h 文件中有参数[ZDO_BIND_UNBIND_REQUEST]允许绑定。能用同样的参数调用函数

ZDP_UnbindReq()移除绑定。目标设备将调用函数ZDApp_BindRsp()或ZDApp_UnbindRsp(),反馈绑定或移除绑定的响应,返回其操作状态为ZDP_SUCCESS, ZDP_TABLE_FULL 或ZDP_NOT_SUPPOR TED.

3.1.2 ZDO 终端设备绑定请求

该机制是用一个按钮按下或其他类似的动作来选择设备在指定时间内被绑定。在规定时间内,该终端设备绑定请求信息被收集到协调器,并创建一个基于模式(prof ile)ID 和串(cluster)ID 的规定的绑定表格条目。默认的终端设备绑定超时时间

(APS_DEFAULT_MAXBINDING_TIME)为16000(定义在ZGlobals.h中),但是能被改变

发送绑定请求

在所有的应用例子中有一个处理键盘事件的函数[例如在TransmitApp.c 文件中的TransmitApp_HandleKey s()函数]。在该函数中,调用了函数ZDApp_SendEndDev iceBindReq()[在ZDApp.c 中],它将收集应用的终端设备的所有信息并调用函数

ZDP_EndDev iceBindReq() [ZDProf ile.c],发送一个绑定信息到协调器。或者,在SampleLight 和SampleSwitch 例子中,直接调用ZDP_EndDev iceBindReq()函数就实现点亮/关闭灯的功能。(严重注意:我在协议里面搜索TransmitA pp_HandleKeys函数,根本搜索不到?,协议栈似乎没有包含TransmitA pp.c函数进来)

接收绑定请求

协调器将接收[ZDP_IncomingData() 在ZDProf ile.c]这些信息并分析处理[ZDO_ProcessEndDev iceBindReq() 在ZDObject.c]这些信息并调用函数ZDApp_EndDev iceBindReqCB() [in ZDApp.c],它将调用ZDO_MatchEndDev iceBind() [ZDObject.c]处理这个请求, 当协调器接收到 2 个匹配终端色后备的绑定请求时,它将启动在绑定设备上创建源绑定条目的处理过程。该协调器有如下处理过程:

解除绑定

1. 发送一个ZDO 解除绑定请求到第一个设备。终端设备绑定切换处理,所以解除绑定首先被发送到移除一个存在的绑定条目。

2. 等待ZDO 解除绑定响应,如果响应状态为ZDP_NO_EN TRY, 发送一个ZDO 绑定请求,在源设备上制作一个绑定条目。如果该响应为ZDP_SUCCESS, 为第一个设备继续到mov e on to the cluster ID f or the first dev ice (the unbind remov ed the entry – toggle)。

3. 等待ZDO 绑定响应. When receiv ed, mov e on to the next cluster IDf or the first dev ice。

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

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

3.1.3 设备应用绑定管理

在设备上其他进入绑定条目的方式是应用层管理绑定表格。意思是说,应用层将调用下列函数进入和移除绑定表格条目:bindAddEntry() ——增加绑定表格条目

bindRemov eEntry() ——从绑定表格中移除条目

bindRemov eClusterIdFromList() ——从一个存在的绑定表格项目中移除一个串ID 。

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

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

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

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

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

相关文档
相关文档 最新文档