Z—Stack节点电压数据采集实验的极速开发与实现
2015-09-11王荣
王荣
摘要:Z-Stack是目前非常常用的ZigBee协议栈。如何基于Z-Stack开发出各种通信系统是现在的研究热门。该文从一个典型的单播通信实验出发,给出了基于Z-Stack快速开发出数据采集无线通信的实现过程。文中给出了关键代码片段的实现,争取以最简练的方式剖析Z-Stack的无线数据采集开发流程。
关键词:Z-Stack;协议栈;无线数据采集;快速开发;ZigBee
中图分类号:TP393 文献标识码:A 文章编号:1009-3044(2015)17-0226-03
自从2007年TI公司宣布推出ZigBee的协议栈Z-Stack以来,已经有8个年头[1]。在此期间对于Z-Stack的开发研究层出不穷,各类期刊论文如雨后春笋般冒出。纵观各文献,大体分为两类:第一类为设计类,主要介绍各种应用系统的设计开发,内容多为框架结构的介绍,很少涉及到实现过程;第二类为算法类,主要研究某一层次的通信算法优化,难度较深,令不少学者望而却步。正因为如此,本文立足于一个基本数据采集实验,着重描述最细节的代码实现过程,旨在用最深入浅出的方式为想要快速开发Z-Stack的读者抛砖引玉。
1 系统框架结构
1.1 系统功能
本实验系统仅采用2个节点,节点芯片采用TI公司的无线射频芯片CC2530。一个节点用作协调器,另一个为路由节点(也可以是终端节点,本文中这两类角色不作功能上的区分)。协调器节点通过串口与电脑连接,接收到的电压数据通过串口助手显示到电脑屏幕上。路由节点主要负责电压数据的采集,并在一定的时间间隔后周期性地将数据单播给协调器[2]。
1.2 系统硬件描述
本系统中的协调器和路由节点采用相同的结构,兼容TI公司的评估板。本实验主要用到以下3个模块:串口模块,主控模块和电源模块。
1)串口模块。串口模块采用CC2530单片机异步UART模式的UART0接口,通过MAX232电压转换芯片和RS232标准接口相连。主要用于协调器通过串口线(也可以是USB转串口线[3])和电脑串口助手之间的数据通信。
2)主控模块。主控模块包含了无线模块,采用CC2530芯片。该芯片使用增强型8051内核,如果开发者对8051单片机很熟悉的话,程序设计会很容易上手。除此之外,芯片内部提供了一个IEEE 802.15.4兼容型无线收发器,该收发器为MCU提供了一个接口,可以用来发出命令、读取状态、确定无线设备事件的顺序等。
3)电源模块。电源模块用于给CC2530芯片供电,典型工作电压为3.3V,该电压值随着电池的使用时间增加略有下降,此电压值为本实验的主要采集数据对象。
2 系统软件设计
本实验系统采用的软件开发平台为IAR Embedded Workbench,版本为MCS-51 7.51A。Z-Stack版本为ZStack-CC2530-2.2.2-1.3.0[4]。注意:采用不同版本的Z-Stack对应的IAR软件版本也不同,如ZStack-CC2530-2.5.0推荐使用IAR 8.10版本,否则会出现编译问题。
2.1 Z-Stack协议栈
Z-Stack是TI公司推出的ZigBee协议栈,是一个使用C语言编写的软件包。除了与无线通信有关的实现代码外,它内部还包含了一个简易多任务操作系统,称为操作系统抽象层OSAL。用户可以使用协议栈提供的API进行应用程序的开发,在开发过程中不必关心ZigBee协议的具体实现细节。Z-Stack采用任务轮询的机制,如果有任务事件发生,OSAL会根据事件类型将其分配给能处理该事件的具体任务,并对事件加以处理,然后进入下一次轮询[5]。
2.2 Z-Stack无线收发程序的设计与实现
首先安装好ZStack-CC2530-2.2.2-1.3.0,然后打开工程目录。本次实验基于SampleApp框架,找到SampleApp.eww文件,用IAR软件打开。打开之后选中工程列表中的App文件夹,所有代码都在SampleApp.c和SampleApp.h中实现。本文默认读者有Z-Stack协议栈开发的基础,对系统框架已经有了一定了解,已经掌握协议栈的串口收发功能。
2.2.1 目的地址的定义与初始化
本实验中,数据是由路由节点采集,发送给协调器,因此可以采用单播的方式发送。首先定义一个目的地址的变量,然后对其进行单播方式的初始化,初始化位于void SampleApp_Init( uint8 task_id )函数。具体实现过程如下:
1)afAddrType_t DataCollect_DestAddr;
2)DataCollect_DestAddr.addrMode = (afAddrMode_t)Addr16Bit;
3)DataCollect_DestAddr.endPoint = SAMPLEAPP_ENDPOINT;
4)DataCollect_DestAddr.addr.shortAddr = 0x0000;
2.2.2 数据簇号的定义与初始化
定义一个新的簇ID号,作为本次采集数据的簇号,并将它加入簇列表初始化数组const cId_t SampleApp_ClusterList[SAMPLEAPP_MAX_CLUSTERS]中。同时更改最大簇号(默认是2,改为3)。
1.#define SAMPLEAPP_MAX_CLUSTERS 3
2.#define DATA_COLLECT_CLUSTERID 3
2.2.3 添加周期性事件
周期性事件用于电压数据的采集,并将该数据周期性发送到协调器的过程。在本次实验中,当路由器节点加入网络后,每隔2秒,路由节点会采集一次电压值发送给协调器。因此,首先需要定义一个事件DATA_COLLECT_EVT完成周期数据采集,然后定义一个采集间隔变量DATA_COLLECT_PERIODIC_INTERVAL。
1)#define DATA_COLLECT_EVT 0x0002
2) #define DATA_COLLECT_PERIODIC_INTER
VAL 2000
定义好上述变量后,完善应用层事件处理函数SampleApp_ProcessEvent( uint8 task_id, uint16 events )。
1)case ZDO_STATE_CHANGE:
2)SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
3)if (SampleApp_NwkState == DEV_ROUTER)
4){
5)osal_start_timerEx(SampleApp_TaskID,
6)DATA_COLLECT_EVT,
7)DATA_COLLECT_PERIODIC_INTERVAL); //每隔2秒,就启动采集事件
8) }
9)break;
2.2.4 数据采集事件的实现
接下来实现数据采集事件,该事件需要在SampleApp_ProcessEvent( uint8 task_id, uint16 events )函数中添加并完善。在该事件中,主要有2个功能:电压数据的采集和事件的周期性执行,即每隔2秒触发一次该自定义事件。
1)if ( events & DATA_COLLECT_EVT ) //数据采集事件的处理
2){
3)Voltage_Data_Collect(); //调用数据采集函数
4)osal_start_timerEx(SampleApp_TaskID,
5)DATA_COLLECT_EVT,
6)DATA_COLLECT_PERIODIC_INTERVAL);
7)return (events ^ DATA_COLLECT_EVT);
8)}
2.2.5 数据采集函数的实现
该函数调用读取电压值函数(实现过程见第6部分),经过数据转换后,调用AF_DataRequest()函数转发数据包到协调器。其实现过程如下。
1)uint8 Collect_Data[10] = {0x20}; //用于保存电压值的数组
2)void Voltage_Data_Collect( void )
3){
4)uint16 VoltageValue;
5)VoltageValue = ReadAdcCheckVdd(); //调用读取电压值函数
6)Collect_Data[0] = VoltageValue / 10000 + 0x30;
7) Collect_Data[1] = VoltageValue / 1000 % 10 + 0x30;
8)Collect_Data[2] = VoltageValue / 100 % 10 + 0x30;
9)Collect_Data[3] = VoltageValue / 10 % 10 + 0x30;
10)AF_DataRequest( &DataCollect_DestAddr, &SampleApp_epDesc,
11)DATA_COLLECT_CLUSTERID,
12)10,
13) Collect_Data, //用户数据,电压值
14)&SampleApp_TransID,
15)AF_DISCV_ROUTE,
16)AF_DEFAULT_RADIUS );
17)}
2.2.6 读取电压值函数的实现
读取电压值的函数uint16 ReadAdcCheckVdd (void)比较容易实现,配置好ADC相关寄存器就可以进行数据采集。该函数的实现过程如下。
1)uint16 value;
2)ADCIF = 0;
3)ADCCON3 = 0x0F;
4)while ( !ADCIF );
5)value = ADCL;
6)value |= ((uint16) ADCH) << 8;
7)return value;
2.2.7 数据的无线接收并串口显示
无线数据的接收会触发系统事件集中的AF_INCOMING_MSG_CMD事件,默认会调用回调函数SampleApp_MessageMSGCB( MSGpkt )来执行相应的操作。因此,只需要完善该函数的内容即可。定义数组变量Recv_Buf[16]来保存接收到的数据。
1)memcpy(Recv_Buf, pkt->cmd.Data, pkt->cmd.DataLength); //保存接收到的用户数据
2)switch(pkt->clusterId)
3)case DATA_COLLECT_CLUSTERID:
4)HalUARTWrite(MT_UART_DEFAULT_PORT, "Voltage is: ", 12);
5)HalUARTWrite(MT_UART_DEFAULT_PORT, Recv_Buf, 1);
6)HalUARTWrite(MT_UART_DEFAULT_PORT, ".", 1);
7)HalUARTWrite(MT_UART_DEFAULT_PORT, &Recv_Buf[1], 1);
8)HalUARTWrite(MT_UART_DEFAULT_PORT, &Recv_Buf[2], 1);
9)HalUARTWrite(MT_UART_DEFAULT_PORT, &Recv_Buf[3], 1);
10)HalUARTWrite(MT_UART_DEFAULT_PORT, "V\n", 2);
11)break;
3 实验结果
在所有的操作完成后,就可以通过串口助手查看实验结果。把协调器和电脑用串口线连接,打开串口助手,设置波特率等参数,可以观察到采集到的数据。
图1 串口显示的电压采集值
4 结语
本文从一个典型的无线数据采集实验为例,剖析了Z-Stack快速开发的过程,并将代码的实现以片段的形式展现出来,重点希望读者能够在看完本文的同时熟悉并实现最简单的数据采集工程。由于在本文的描述中忽略了大量介绍性的陈述,因此需要读者在之前就接触过Z-Stack,熟悉各个接口函数的含义,了解系统的结构,这样才能在正确的位置找到需要添加和更改的代码,从而理解各段代码的意义。
参考文献:
[1] 青岛东合信息技术有限公司. Zigbee开发技术及实践[M]. 西安:西安电子科技大学出版社,2014.
[2] 李延,张发生. 基于Z-Stack的室内温湿度检测系统设计[J]. 软件导刊,2015(2):94-96.
[3] 马昆,姚竹亭. 基于Zigbee的温度采集系统设计[J]. 电子技术,2014:26-27.
[4] Texas Instruments. http:http://www.ti.com.cn.
[5] 李树丹,张从松. 基于ZigBee协议的温湿度检测系统设计与实现[J]. 电子科技,2014-12(27):37-40.