首页 理论教育 实验十六:ZigBee协议组网通信实验-物联网实验教程

实验十六:ZigBee协议组网通信实验-物联网实验教程

时间:2023-10-21 理论教育 版权反馈
【摘要】:JZS_u32InitSystem():用于初始化Jennic的ZigBee协议栈。函数返回的数据被ZigBee协议栈用来构造一个KVP回应帧。KVP和MSG分别是ZigBee协议定义的两种不同的数据格式。

实验十六:ZigBee协议组网通信实验-物联网实验教程

1.实验目的

本实验介绍了使用IOT-ZBJ节点实现一个基于ZigBee协议的环境检测程序。通过本实验的学习读者能了解ZigBee协议的基本原理,掌握IOT-ZBJ节点的程序设计方法,并能够将二者结合实现一个简单的监测环境的光强度、温湿度的程序。

2.实验设备

(1)硬件

● ZigBee协议实验节点(IOT-ZBJ)10个。

● PC1台。

(2)软件

● Code::Blocks软件。

● Jennic Flash Programmer烧写程序软件。

3.实验原理

本实验实现了一个简单的环境监测程序,即由终端设备定时地收集温湿度等环境监测数据,并通过ZigBee协议建立网络,将监测数据汇集到协调器。为了对实验有更深入的了解,下面首先介绍Jennic提供的ZigBee协议栈的接口,包括实验中所用到的计时器传感器数据采集接口、数据的发送以及串口等;然后对如何使用Jennic开发环境开发基于ZigBee的IOT-ZBJ节点应用程序进行简单的说明。

(1)Jennic开发环境介绍

1)ZigBee协议栈的开发接口API。任何一个Jennic ZigBee应用程序,都必须定义下面这些函数,即使有些函数用不到。首先是程序的入口函数AppColdStart()、AppWarmStart(),以及JZA_boAppStart()、JZA_vStackEvent()、JZA_vPeripheralEvent()、JZA_vAppEvent-Handler()、JZA_vAppDefineTasks()、JZA_bAfKvpObject()、JZA_vAfKvpResponse()、JZA_bAfMsgObject()和JZA_vZdpResponse()9个函数。

还有两个必须在上述函数中调用用来分别初始化协议栈和启动协议栈的两个函数JZS_u32InitSystem()和JZS_vStartStack()。下面对每个函数做简单说明。

AppColdStart():用户应用程序的入口。设备上电或从睡眠状态苏醒后应用程序从这个函数开始运行。一般在这个函数中应该调用协议栈和BOS(Jennic的一个简单调度器。它采用非抢先式调度机制,且所有任务具有相同的优先权)的初始化函数。

AppWarmStart():当设备从内存供电的休眠模式唤醒的时候将进入这个函数重新启动用户应用程序。在这种情况下,所有内存数据都不会丢失。如果设备不需要休眠唤醒,这个函数可以为空。

JZS_u32InitSystem():用于初始化Jennic的ZigBee协议栈。

JZS_vStartStack():用于启动协议栈,并决定设备启动时作为协调器、路由器、终端中的哪一种启动。设备的网络角色在makefile中指定。如果是协调器将试着启动网络,是路由器或终端则试着找寻并加入网络。

JZA_boAppStart():允许用户应用程序在协议栈启动前注册端点的描述信息。一般在这个函数中调用JZS_vStartStack()启动协议栈。

JZA_vStackEvent():协议栈通过这个回调函数反馈网络层的一些网络事件,比如网络启动成功或者节点加入成功,或者数据发送完成等。

JZA_vPeripheralEvent():主要用来处理外部的硬件(如时钟或者串口等)中断。

JZA_vAppEventHandler():用户的应用函数,不需要任何特殊事件的触发而被BOS规则地调用。可以用来处理用户的主要任务或处理外部的硬件中断。此函数只能在短时间内处理后就必须返回,这样使BOS有时间处理其他的事件。因此在此函数中不要处理需要长时间等待的事件。

JZA_vAppDefineTasks():向BOS注册用户任务。很少被用到。在应用开始时只被调用一次。

JZA_bAfKvpObject():用来接收其他节点发送过来的KVP数据。函数返回的数据被ZigBee协议栈用来构造一个KVP回应帧。

JZA_bAfMsgObject():用来接收其他节点发送过来的MSG数据。当远程节点发送数据时根据具体的需求选择发送KVP数据还是MSG数据。KVP和MSG分别是ZigBee协议定义的两种不同的数据格式。其中,KVP(KeyValuePair)是ZigBee协议中规定的一种特殊的数据传输机制,是专用的规范的信息格式,采用键值对的形式,也即按一种规定的格式进行数据传输,主要用于传输较简单的变量值格式;MSG(Message Service Type)是ZigBee协议中规定的一种特殊的数据传输机制,没有具体格式上的规定,通常用于多信息、复杂信息的传输,在实践中一般采用MSG模式。

JZA_vAfKvpResponse():接收发送出去的KVP包后的回应消息,该回应消息由远程节点发出。

JZA_vZdpResponse():接收发送出去的ZDP请求的回应消息,如Binding。

2)使用BOS计时器。在JN5121和JN513x设备上,由于协议栈使用了tick-timer,用户应用程序如果使用tick-timer将会使BOS或协议栈功能异常。因此,用户必须使用协议栈提供的BOS计时器来进行相关定时操作。BOS计时器通过软件实现,其应用通过函数调用创建。计数器启动函数的原型为:

相关的参数为:

*pfvTimerHandler表示指向当计时器规定时间到后,被BOS调用的回调函数;

*pvMsg表示指向传给计时器的消息;

u8MsgSize表示消息长度

u32Delay表示计时器工作时间,其值乘以10ms就是计时器工作时间,例如定时器定时50ms,其值就为5;

*pu8TimerId表示指向接收创建计时器的ID的地址

BOS计时器不能重复、连续工作,即当计时器规定的时间到了之后,指定的相应事件只发生一次,之后计时器失效。如果想使指定的事件每隔一段时间就发生的话,必须在计时器的回调函数中再次重新启动计时器。例如:

3)温湿度数据采集。首先初始化湿度和温度联合感应器,接口函数为vHtsReset(),必须在使用湿度和温度联合感应器前调用这个初始化函数。函数原型为:

之后就可以调用温湿度的读取函数vHtsStartReadTemp()和vHtsStartReadHumidity()获取温度。其函数原型分别为:

这两个函数只是发起读取的操作,在温湿度数据获取完毕之后,系统会调用相应的回调函数i16HtsReadTempResult()和u16HtsReadHumidityResult()返回数据。在发起读取操作之后而读取尚未完成之前,系统会一直阻塞程序,这样BOS就不能处理其他事件。因此读取前需要使用if((u32AHI_DioReadInput()&HTS_DATA_DIO_BIT_MASK)==0)语句判断读取是否已经完成。u32AHI_DioReadInput()为读取每个输入引脚值的函数。读取完成后可以读取到温度或湿度的值。其函数原型分别为:

函数返回-40~124度之间的值。

函数返回0%~160%之间的值。

温湿度的读取是使用了一个简单的状态机实现的,相关代码如下:

4)光传感数据采集。同温湿度传感器类似,读取光传感器的值首先也需要初始化光传感器,初始化接口函数原型为:

然后初始化读取光,初始化时需要选择一个读取的通道。函数原型为:

输入:u8Channel 0表示通道既可以感知可见光,又可以感知红外线光;

1表示通道只感知红外线光。

调用了这个函数后设备会连续启动进行采集,因此不需要重复调用这个函数。之后就可以读取特定通道的光值了,函数u16AlsReadChannelResult()就是读取最近读取的光级值。函数原型为:

返回范围为0~4015的光级值。

读取两个通道的代码如下:

5)发送数据。在Jennic ZigBee协议栈API中节点发送数据的函数为afdeDataRequest()。其函数原型请参考JN-RM-2018。

使用函数afdeDataRequest()发送数据之前,先将要发送的数据存储在AF_Transaction_s类型的结构中。afdeDataRequest()主要指定了目的地址、目的端口、源端口、发送的消息类型、存储数据的AF_Transaction_s类型变量。

6)使用串口与PC通信。Jennic的ZigBee协议栈提供了类似printf的函数来向串口输出信息,该函数封装在printf.c、printf.h中,将这两个文件加入到工程,然后在主程序的头部加入头文件#include"..\..\..\Chip\Common\Include\Printf.h",即可调用相关的函数向串口发送信息了。

在程序中,首先需要初始化串口,在代码的初始化设备的函数里加入vUART_printInit(),待初始化完成之后,可以使用VPrintf来向串口输出信息。其函数原型为:

例如:

也可以使用函数vPutC向串口发送一个8位的信息。函数原型为:

(2)环境监测程序的实现(www.xing528.com)

实验需要完成3个设备Coordinator、Router和End Device节点的程序。Coordinator负责发起网络,等待Router和End Device节点的加入,它本身不采集任何数据,只接收其他节点发送的数据,并将这些数据定期发送给PC的串口中。数据主要包括发送帧的源设备16位短地址,设备采集的传感器的数据。Router负责加入网络并采集传感器数据,定期将这些数据发送给Coordinator,并可以转发其他节点的数据。End Device负责加入网络,并采集数据,将采集的数据发送出去完成后进入休眠期,经过固定的时间后苏醒,开始采集数据,如此循环。End Device只具有收发数据的功能,不能转发数据。

实验通过这3种节点组成Mesh网络,由于存在Router节点,因此可以实现多跳的功能。

1)程序包含以下4个文件。

● WSN_Profile.h:此头文件主要定义了网络和设备的一些参数设置,比如PANID、网络所在的通道、设备端点、端点使用的Cluster。

● WSN_Coordinator.c:此文件为节点Coordinator的源代码

● WSN_Router.c:此文件为节点Router的源代码。

● WSN_EndDevice.c:此文件为节点End Device的源代码。

2)程序的主要函数。Jennic程序由bootloader来启动和引导,引导完成后将自动调用AppColdStart函数,因此AppColdStart是所有Jennic程序的入口函数,相当于C语言中的函数main()。主要用来设置网络信息PANID和网络的通道。调用函数vInit()完成其他初始化设置。

在WSN_Coordinator.c中,vInit()用来初始化ZigBee协议栈、初始化指示灯、初始化Uart、启动BOS。

在WSN_Router.c和WSN_EndDevice.c中,vInit()用来初始化ZigBee协议栈、初始化指示灯、调用函数vInitSensors()初始化传感器、启动BOS。

其他函数的功能为:

PRIVATEvoidvTxSerialDataFrame()用来向Uart发送数据的节点的16位短地址、消息序号、接收到的温度值、接收到的湿度值、节点的电压值、通道0、通道1的光级值和发送数据的节点的IEEE地址。函数中用到的函数vPutC(),用来向Uart发送一个8位的数据,因此若发送一个16位的数据,则将数据分为高8位、低8位分别发送。例如:

PRIVATE void vInitSensors()初始化了温湿度、光传感器,初始化并配置了ADC。

PRIVATE void vAppTick()为WSN_Router.c和WSN_EndDevice.c程序的核心内容,完成了整个程序的主要工作,包括:读取各个传感器的值、电压值,控制指示灯的闪烁,最后将数据发送到协调器。这个函数是一个时钟周期性调用的函数,在BOS计时器失效后,函数在最后又创建一个BOS计时器,以便在固定的周期后调用自己。因此,这个函数被周期性地调用。

PRIVATE voidv ReadBatteryVoltage()用来读取电压值。关于如何使用ADC采样电压值前面已经做了介绍。

PRIVATE void vReadTempHumidity()用来读取传感器温度、湿度值。

PRIVATE void vReadAls0()用来读取通道0的光级值。

PRIVATE void vReadAls1()用来读取通道1的光级值。

PRIVATE void vSendData()将读取到的数据通过数据包发送给协调器。

3)WSN_Coordinator.c流程:

● 进入AppColdStart(),初始化串口、协议栈、启动BOS。

● BOS调用函数JZA_boAppStart(),启动协议栈。

● 设备试着创建网络,产生JZS_EVENT_NWK_STARTED协议栈事件。

● 协议栈调用JZA_vStackEvent(),为端点注册简单描述。

● BOS启动后,规则的调用函数JZA_vAppEventHandler()周期性的闪烁指示灯,表示节点正在工作。

● 只要收到MSG消息,协议栈调用函数JZA_bAfMsgObject()接收数据,并将收到的数据发送到串口。

4)WSN_Router.c流程:

● 进入AppColdStart(),初始化传感器、ADC、协议栈、启动BOS。

● BOS调用函数JZA_boAppStart(),启动协议栈。

● 设备试着加入网络,产生JZS_EVENT_NWK_JOINED_AS_ROUTER协议栈事件。

● 协议栈调用函数JZA_vStackEvent()。

● BOS启动后,规则的调用函数JZA_vAppEventHandler(),从而周期性地调用函数vAppTick(),即周期性执行以下操作:读取温湿度传感器值;读取节点电压值;读取通道0和通道1的光级值;当读取全部完成时,闪烁指示灯提示节点正常工作。

● 调用函数vSendData()生产数据包,将读取的值发送给协调器。

5)WSN_EndDevice.c流程:

其所有流程和WSN_Router.c的一样,只是在调用函数vSendData()发送数据后,产生JZS_EVENT_APS_DATA_CONFIRM事件后,调用函数JZA_vStackEvent(),定义一个计时器,30s后将休眠的节点唤醒。节点进入休眠,30s后节点被唤醒,将从函数vAppWarmStart()重新启动程序。

4.实验内容

阅读ZigBee协议,学习协议的运行机制以及协议中各层的数据包格式。

初步掌握Jennic ZigBee协议栈的使用方法,能够结合IOT-ZBJ节点进行简单的基于ZigBee的应用的开发。

5.实验步骤

1)启动软件Code::Blocks,在C:\Jennic\cygwin\Jennic\SDK\Application路径下新建文件夹ZigBeeWSN。在此文件夹中新建工程WSN_Coordinator.cbp,工程类型选择ZigBee Coordinator。

2)在新建工程中的JN51xx_JZ_Coord.c文件里编辑代码或直接将此文件从工程中删除,然后在工程中加入WSN_Coordinator.c、printf.c和WSN_Profile.h。这些文件在所附光盘中可以找到。然后编译源程序

3)目标文件WSN_Coordinator.bin生成在目录C:\Jennic\cygwin\Jennic\SDK\Application\ZigBeeWSN\JN5139_Build\Release下。

4)重复上面的步骤,将步骤1)中的工程类型改为ZigBeeRouter,新建WSN_Router.cbp工程,步骤2)中只需要加入文件WSN_Router.c和WSN_Profile.h,然后编译,在工程文件Realse目录下产生WSN_Router.bin文件。

5)同样,将步骤1)中的工程类型改为ZigBeeEndDevice,新建WSN_EndDevice.cbp工程,步骤2)中只需要加入文件WSN_EndDevice.c和WSN_Profile.h,然后编译,生成WSN_EndDevice.bin文件。

6)将串口线连接到节点,打开Jennic Flash Programmer软件,然后给节点上电,下载程序到节点上,不同的设备下载不同的目标程序。注意:烧写程序时,一定要在打开Jennic Flash Programmer软件后,才能给节点上电。

7)关闭Jennic Flash Programmer软件,重启节点。先给Coordinator节点上电,Coordinator节点上的LED1闪烁,表示发起网络成功。给Router节点和End device节点上电,加入网络后,它们的LED1闪烁。其中End Device节点的LED1闪烁一下后熄灭,经过30s后LED1再亮一次,如此重复。

8)将串口线连接到Coordinator节点,打开串口调试助手,波特率设置为115200bit/s,可以收到节点发来的数据。下面是一个典型的数据包:

其中,“0016”为包序号;“00 15 8D 00 00 09 10 1D”为发送节点的长地址;“00 01”为Coordinator分配的临时短地址;“00 0F”为湿度值;“00 1D”为温度值;“00 DB”为通道0的光强值;“00 39”为通道1的光强值;“0A3E”为节点电压值;“FFFF”为包尾。此时用手按住某End Device或者Router的温度传感器,可以发现收到的数据包中温湿度值会相应地发生变化。

6.思考题

1)如何将End Device节点休眠的时间改为10s?

2)如何改变节点发送数据的周期?

7.补充阅读

[1]徐勇军,刘峰,等.低速无线个域网实验教程[M].北京:北京理工大学出版社,2008.

[2]ZigBee Application Framework API Reference Manual.Jennic,2008.

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈