基于Z—Stack的ZigBee协议的实现
2017-11-03殷松瑜
殷松瑜
摘 要:文中基于ZigBee2007协议栈设计开发了一个应用层ZigBee协议,实现了协调器和终端模块之间双向传输预设格式的数据。ZigBee协议通过对无线模块内的各种硬件资源标准化编码,实现了使用统一的方法来访问控制模块内部的相关资源。串口控制协议提供了对模块有效的控制访问途径,用户设备可通过统一的串口协议对无线通信进行控制,访问相关设备,传递各种测量控制数据等。
关键词:紫蜂;协议栈;串口通信;传感器
中图分类号:TP39;TN925 文献标识码:A 文章编号:2095-1302(2017)10-00-05
0 引 言
ZigBee技术是一种近距离,拥有低复杂度、低功耗、低速率、低成本的双向无线通信技术,主要适合短距离无线通信、组网、自动控制和远程控制等领域,同时还可嵌入各种设备中。ZigBee协议是专用于ZigBee网络的通信协议,通过好的算法能最大限度节省网络中的能量,可接入大量节点,具有高容错性,强鲁棒性。由传感器和ZigBee系统组成的ZigBee无线传感器网络可自动采集、分析和处理各个节点的数据,同时,ZigBee技术具有很强的网络扩展能力,适合于各种自动组网领域,具有广阔的应用领域和较高的研究价值[1]。ZigBee管理系统通信模型如图1所示。
文中ZigBee应用层协议的预期目标是能够在协调器和终端模块之间进行双向传递数据,实验过程参考了北京赛佰特科技有限公司的相关设备资料。实验环境的硬件采用ZigBee(CC2530)模块(4个),ZigBee下载调试板,USB仿真器,PC机。软件采用IAR Embedded Workbench for MCS-51,ZigBee2007协议栈ZStack-2.3.0-1.4.0。
1 Z-Stack协议栈
本文以Z-Stack协议栈自带的SampleApp样例作为模板,SampleApp实现了协调器自动组建星形网,节点设备申请加入网络后两者建立无线通信过程。协调器终端节点之间数据传送方式主要为周期性定时自动发送消息和通过按键事件触发传送数据。本文协议实现采用第一种数据传送方式,即周期定时自动发送信息。
2 相关通信协议
传感器串口通信协议见表1所列[2]。
其中,SOF固定为0xEE 0xCC,标志一帧的开始,SensorType见传感器说明,SensorId固定为0x01,CmdId固定为0x01,Data为6 B传感器数据域,见传感器说明,ExtenData为2 B 扩展数据域,END固定为0xFF,标志一帧的结束。一帧数据为定长16 B。传感器说明(测量型)见表2所列,传感器说明(控制型)见表3所列。
ZigBee通信协议如下所示:
uint8DataHeadH; //包头0xEE
uint8DataDeadL; //包头0xCC
uint8NetID; //所属网络标识00(zigbee) 01(蓝牙)02(WiFi)
03(IPv6)
uint8NodeAddress[4]; //节点网络地址
uint8FamilyAddress[4]; //根节点网络地址
uint8NodeState; //节点状态
uint8NodeChannel; //ZigBee物理信道(预留,固定为0x0B)
uint8ConnectPort; //ZigBee ENDPOINT ID
uint8SensorType; //传感器类型编号
uint8SensorID; //相同类型传感器设备号
uint8SensorCMD; //节点命令序号
uint8 Sensordata1; //节点数据1
uint8 Sensordata2; //节点数据2
uint8 Sensordata3; //节点数据3
uint8 Sensordata4; //节点数据4
uint8 Sensordata5; //节点数据5
uint8 Sensordata6; //节点数据6
uint8 Resv1; //保留字节1
uint8 Resv2; //保留字节2
uint8DataEnd; //节点包尾0xFF
其中,一帧数据为定长26 B。
3 ZigBee通信协议功能实现代码
ZigBee协议实现代码按照数据传输方向和发送接受节点不同,可分为6个不同的数据传送过程,如图2所示。其中,过程1表示传感器通过串口把测量数据传送给终端节点;过程2表示终端节点通过串口把接收的控制数据传送给传感器;过程3表示协调器通过无线射频把接收的控制数据传送给终端节点;过程4表示终端节点通过无线射频把传感器测量数据传送给协调器;过程5表示上位机通过串口把控制數据传送给协调器;过程6表示协调器通过串口把接收的测量数据传送给上位机。
为了实现ZigBee通信协议传输数据,在协议实现代码中添加终端与协调器通信相关的消息处理函数,在SampleApp.c文件中进行修改。
(1)定义所属网络标识
#define ZigBee 0;// 所属网络标识
(2)添加自定义的应用程序命令号:
constcId_tSampleApp_ClusterList[SAMPLEAPP_MAX_CLUSTERS] =
{ SAMPLEAPP_PERIODIC_CLUSTERID,//发给协调器endprint
SAMPLEAPP_CTRL_CLUSTERID //发给终端节点
};
(3)由于协议栈串口通信过程现在正在MT层实现处理,所以使用ZigBee串口通信要在编译选项里加入MT层支持ZAPP_P1:
#if defined (ZAPP_P1)
MT_UartRegisterTaskID(SampleApp_TaskID);//注册任务优先级
MT_UartZAppBufferLengthRegister(100);//注册缓存区长度
#end if
(4)当设备加入到网络后,其设备状态就会发生变化,对所有任务触发ZDO_STATE_CHANGE事件,开启一个定时器。定时时间到,触发广播Periodic消息事件,相应任务为SampleApp_TaskID,事件处理函数处理SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,调用函数SampleApp_SendPeriodicMessage()来周期性自动发送信息。
(5)ZigBee协议功能实现代码中添加与协调器终端相互通信相关的消息处理函数。
SampleApp_ProcessEvent()事件处理函数代码如下:
/* 根据不同的事件调用相应的事件处理函数 */
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{ afIncomingMSGPacket_t *MSGpkt;//指向接收消息結构体的指针
(void)task_id; // 任务优先级由OSAL分配
if ( events & SYS_EVENT_MSG )
{//从消息队列接收消息,其中包含接收到的无线数据包的指针
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
while ( MSGpkt )
{switch ( MSGpkt->hdr.event )//对接收的事件进行判断
{case AF_INCOMING_MSG_CMD://接收无线数据
SampleApp_MessageMSGCB(MSGpkt);//接收消息处理函数
break;
#if defined (ZAPP_P1)
case SPI_INCOMING_ZAPP_DATA://接收到串口数据
SampleApp_ProcessMTMessage(MSGpkt);//监控调试层串口消息处理函数
MT_UartAppFlowControl (MT_UART_ZAPP_RX_READY);//串口流控制
break;
#end if
case ZDO_STATE_CHANGE://节点设备类型发生变化
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //读取节点设备类型
if ( (SampleApp_NwkState == DEV_ZB_COORD)//协调器
|| (SampleApp_NwkState == DEV_ROUTER)//型路由器
|| (SampleApp_NwkState == DEV_END_DEVICE) )//终端节点
{HalLedSet(HAL_LED_1, HAL_LED_MODE_ON);//LED_1点亮
if(SampleApp_NwkState == DEV_ZB_COORD) //设备类型协调器
{//周期定时发送消息
osal_start_timerEx( SampleApp_TaskID,
SAMPLEAPP_COORD_AUTO_SEND_MSG_EVT,
COORD_AUTO_MSG_TIMEOUT);
} }
else
……
}
//处理完接收的消息,需释放消息占用的堆内存,防止内存泄漏
osal_msg_deallocate( (uint8 *)MSGpkt );
……
}
//定时器当预设时间到达之后设置周期性消息发送事件
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
{SampleApp_SendPeriodicMessage();// 定时发送周期性消息
// 设置发送消息时间为固定周期再附加随机时间延迟,防止访问碰撞冲突
osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
……
}/*协调器自动发送消息事件*/
if ( events & SAMPLEAPP_COORD_AUTO_SEND_MSG_EVT )
{ osal_start_timerEx(SampleApp_TaskID,SAMPLEAPP_COORD_AUTO_SEND_MSG_EVT,COORD_AUTO_MSG_TIMEOUT);endprint
SampleApp_atuo_send_msg();//自动发送信息
……
}
……
}
SampleApp_MessageMSGCB()接收消息处理函数代码如下:
/* 对接收到的消息调用相应的消息处理函数 */
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{ switch ( pkt->clusterId )//判断发给不同应用领域特定对象的命令
{ case SAMPLEAPP_PERIODIC_CLUSTERID://发给协调器
……
SampleApp_ProcessAFMessage(pkt);//调用应用层消息处理函数
break;
case SAMPLEAPP_CTRL_CLUSTERID://发给终端节点
……
SampleApp_ProcessCtrMessage(pkt);//调用传感器控制消息处理函数
break; }
}
SampleApp_ProcessMTMessage()监控调试层串口通信處理函数代码如下:
/*实现协调器通过无线信道接收终端节点16 B传感器数据包后,提取出传感器测量数据,构造ZigBee通信协议数据包,再通过串口向上位机发送测量数据;协调器从串口接收上位机发送的ZigBee协议格式数据包,数据包内容是传感器控制数据,通过无线信道发送给相应的终端节点*/
void SampleApp_ProcessMTMessage( afIncomingMSGPacket_t *pckt )
{ uint8 len;//数据包长度
uint16 FamilyAddr;//根节点16位短地址
unsigned char * buf = ((unsigned char *)pckt+2);//接受 应用层发送的消息
unsigned char data[16];//存放终端节点发送给协调器消息的发送缓冲区
len = pckt->hdr.status; //接收的消息长度
unsigned char data_buf[26]; //发送给协调器消息的发送缓冲区
osal_memcpy(data_buf,buf,26); //复制应用层消息到协调器消息的缓冲区
if(SampleApp_NwkState != DEV_ZB_COORD){// 终端节点接收串口传来的传感器数据
//检验传感器数据包的长度,包头,包尾是否正确
if((len == 14)&&(buf[0]==0xEE)&&(buf[1]==0xCC)&&(buf[13]==0xFF)){
osal_memcpy(data,buf,14); //获取传感器的数据
FamilyAddr=NLME_GetCoordShortAddr();//获取协调器的16位地址
data[14]=FamilyAddr>>8; //协调器16位短地址的低8位
data[15]=FamilyAddr; //协调器16位短地址的高8位
len = 16; //发送数据包的长度
//设置单播模式和设备16位短地址
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
//通信节点端口号
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
//发送目的地是协调器地址0x0000
SampleApp_Periodic_DstAddr.addr.shortAddr = 0x0000;
//Z-Stack协议栈提供的数据发送函数AF_DataRequest()
if ( AF_DataRequest( &SampleApp_Periodic_DstAddr,
//目的地地址
&SampleApp_epDesc,//设备节点描述符
SAMPLEAPP_PERIODIC_CLUSTERID,//周期自动发送消息命令
len,//数据包长度
data,//数据缓冲区指针
&SampleApp_TransID,//数据发送序列号
AF_DISCV_ROUTE,//数据发送路由
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{//向协调器周期性发送消息成功}
else
{//发生错误发送消息不成功}
HalLedBlink( HAL_LED_2, 2, 50, (1000 / 4) );
} }
//协调器接受到从串口传送过来的上位机控制数据
if(SampleApp_NwkState == DEV_ZB_COORD)
{//检验控制数据包的长度,包头,所属网络标识,包尾是否正确
if((len== 26)&&(buf[0]==0xEE)&&(buf[1]==0xCC)&&(buf[2]==0x0)&&(buf[25]==0xFF))endprint
{ SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
//根据传送传感器数据的终端节点地址反向确定控制消息发送的目的地地址
SampleApp_Periodic_DstAddr.addr.shortAddr = BUILD_UINT16(buf[6], buf[5]);
if (AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,//传送传感器控制数据簇命令
SAMPLEAPP_CTRL_CLUSTERID,len,buf,&SampleApp_TransID,AF_DISCV_ROUTE,AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{//向终端节点周期性发送消息成功}
else
{ //发生错误发送消息不成功}
HalLedBlink( HAL_LED_2, 2, 50, (1000 / 4) );} }}
SampleApp_ProcessAFMessage()应用层消息处理函数代码如下:
/*协调器通过无线信道接受终端节点16 B传感器数据包后,从中提取出传感器测量数据,构造ZigBee通信协议数据包,再通过串口向上位机传送测量数据*/
void SampleApp_ProcessAFMessage( afIncomingMSGPacket_t *pckt )
{unsigned char buffer[16]={0x00};//接受缓冲区
int i=0;unsigned char uartbuf[26]={0x00};//串口发送缓冲区
osal_memcpy(buffer, pckt->cmd.Data, 16);//接受到消息数据复制到接受缓冲区
uartbuf[0]=0xEE;//包头0xEE
uartbuf[1]=0xCC;//包头0xCC
uartbuf[2]=ZigBee; //所属网络标识00(ZigBee)
//发送消息的终端节点的源地址(16位短地址)高8位
uartbuf[5]=HI_UINT16(pckt->srcAddr.addr.shortAddr);
//发送消息的终端节点的源地址(16位地址)低8位
uartbuf[6]=LO_UINT16(pckt->srcAddr.addr.shortAddr);
uartbuf[9]=buffer[14];//根节点16位短地址的高8位
uartbuf[10]=buffer[15];//根节点16位短地址的低8位
uartbuf[11]=0X01; //节点状态在线(01)
uartbuf[12]=0X0B;//ZigBee物理信道(预留,固定为0x0B)
uartbuf[13]=pckt->endPoint; //ZigBee通信节点的对应端点号
//传感器测量数据复制到ZigBee通信协议数据发送缓冲区相对应的位置
for(i=14;i<26;i++)
{uartbuf[i]=buffer[i-12];}
//协调器通过串口向上位机传送ZigBee通信协议数据包
HalUARTWrite(0,uartbuf,26);
}
SampleApp_ProcessCtrMessage()传感器控制消息处理函数代码如下:
/*终端节点通过无线信道接受协调器26 B数据包后,提取出控制型传感器相关数据14 B,构造串口通信协议数据包,在通过串口向传感器传送控制数据,完成控制任务。*/
void SampleApp_ProcessCtrMessage(afIncomingMSGPacket_t *pckt )
{unsigned char uartbuf[14];// //构造ZigBee通信协议数据包长度26 B
uartbuf[0]=0xEE;//包头0xEE
uartbuf[1]=0xCC; //包头0xCC
uartbuf[2]=pckt->cmd.Data[14];//传感器类型编号
uartbuf[3]=pckt->cmd.Data[15];//相同类型传感器设备号
uartbuf[4]=pckt->cmd.Data[16];//节点命令序号
uartbuf[5]=pckt->cmd.Data[17];//节点数据1
uartbuf[6]=pckt->cmd.Data[18];//节点数据2
uartbuf[7]=pckt->cmd.Data[19];//节点数据3
uartbuf[8]=pckt->cmd.Data[20]; //节点数据4
uartbuf[9]=pckt->cmd.Data[21];//节点数据5
uartbuf[10]=pckt->cmd.Data[22]; //节点数據6
uartbuf[11]=0x00;//保留字节1endprint
uartbuf[12]=0x00;//保留字节2
uartbuf[13]=0xFF; //节点包尾0xFF
HalLedBlink( HAL_LED_2, 2, 50, (1000 / 4) ); // LED灯闪烁指示接受完成状态
HalUARTWrite(0,uartbuf,14);// 终端节点通过串口向传感器传输控制数据包
}
SampleApp_atuo_send_msg()协调器自动发送消息函数代码如下:
/*上位机构造26 B通信协议数据包,通过串口发给协调器,周期性自动向外发布消息*/
void SampleApp_atuo_send_msg()
{unsigned char uartbuf[26];//构造ZigBee通信协议数据包,长度26 B
osal_memset(uartbuf,0,sizeof(unsigned char)*26);//自动清除原来的旧数据
uartbuf[0]=0xEE;//包頭0xEE
uartbuf[1]=0xCC;//包头0xCC
uartbuf[2]=ZigBee; //所属网络标识00(ZigBee)
uartbuf[11]=0x01; //节点状态在线(01)
uartbuf[12]=0x0B; //ZigBee物理信道(预留,固定为0x0B)
uartbuf[25]=0xFF; //节点包尾0xFF
HalUARTWrite(0,uartbuf,26);// 上位机通过串口向协调器传输通信协议数据包
}
ZigBee协议运行结果如图3所示。
4 结 语
实验证明,该ZigBee应用层协议运行稳定可靠,能够在协调器和终端模块之间快速高效地双向传输预定格式的数据内容,充分发挥了ZigBee强大的网络扩展能力,可以运用到各种自动组网领域,具有很好的应用推广前景。
参考文献
[1]原羿,苏鸿根.基于ZigBee技术的无线网络应用研究[J].计算机应用与软件,2004,21(6): 89-91.
[2]北京赛佰特科技有限公司.CBT 模块通讯协议V1.2[Z].2014.
[3]吴清秀.基于ZigBee协议栈的网络管理研究[J].物联网技术,2016,6(7):66-67.
[4]杨诺,胡必玲,黄志炜.基于物联网核心技术的智能考勤系统[J].物联网技术,2016,6(10):85-89.
[5]查爽.基于ZigBee技术的无线传感器网络网关研究与实现[D].大连:大连理工大学,2007.
[6]王彤.基于Z-Stack协议栈的ZigBee网络组网研究与实现[D].保定:河北大学,2012.
[7]贺东梅.基于ZigBee协议的无线通信网关的设计[J].物联网技术,2017,7(1):45-47.
[8]吴清秀.基于ZigBee协议栈的PHY服务研究[J].物联网技术,2015,5(6):44-45.endprint