(配套源码、软件、开发板等资源,可移步博客同名QQ群/TB店铺:拿破仑940911)
上一节中,我们简要介绍了ZigBee的第四种无线通信方式——绑定的基本概念;本节中,我们将对ZigBee的绑定通信(握手绑定)进行实验验证。
本节中实现的功能为:组建由一个ZigBee协调器和两个以上ZigBee终端设备组成的ZigBee网络。无需对ZigBee协调器做任何操作,仅由其负责创建ZigBee网络和处理绑定请求;其余ZigBee设备在建立绑定关系之前,不能进行无线数据的收发,建立绑定关系之后,可以成功地进行无线数据的收发。
1、绑定请求函数
上一节中我们讲过,握手绑定(Hand Binding)可以通过调用Z-Stack协议栈中的ZDP_EndDeviceBindReq()函数来实现,其函数定义和声明分别在ZDProfile.c和ZDProfile.h两个文件中,此处就不再赘述。
另外,上一节中也提到,“允许绑定的时间”——APS_DEFAULT_MAXBINDING_TIME的默认值为16秒,其定义在ZGlobals.h文件中。可直接在定义处更改其值,也可以在f8wConfig.cfg文件中或在预编译选项中对进行定义,实现覆盖更改。
2、ZDO消息注册函数(绑定消息)
我们可以为设备绑定状态改变的消息(End_Device_Bind_rsp)指定一个接收处理的任务,当设备的绑定状态发生改变时,被指定的任务就会做相应的处理。为了实现这一功能,我们需要调用ZDO_RegisterForZDOMsg()函数对End_Device_Bind_rsp进行注册,该函数的定义在ZDProfile.c文件中:
/********************************************************************* * @fn ZDO_RegisterForZDOMsg * * @brief Call this function to register of an incoming over * the air ZDO message - probably a response message * but requests can also be received. * Messages are delivered to the task with ZDO_CB_MSG * as the message ID. * * @param taskID - Where you would like the message delivered * @param clusterID - What message? * * @return ZSuccess - successful, ZMemError if not */ ZStatus_t ZDO_RegisterForZDOMsg( uint8 taskID, uint16 clusterID )
3、注册“绑定消息”并定义处理函数
为实现注册“绑定消息”,为设备绑定状态改变的消息(End_Device_Bind_rsp)指定一个接收处理的任务(ProjectApp_TaskID),在ProjectApp_Init( )函数最后,加入如下代码:
ZDO_RegisterForZDOMsg( ProjectApp_TaskID, End_Device_Bind_rsp );如果对“绑定消息”指定了接收处理的任务,当设备的绑定状态发生改变时,被指定的任务就会做相应的处理,这里我们需要在ProjectApp.c文件中定义一个处理函数,我们给其取名为ProjectApp_ProcessZDOMsgs(),其函数声明和定义如下:
...... static void ProjectApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg ); ......static void ProjectApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )//每次“绑定”状态发生改变,均会调用此函数 { switch ( inMsg->clusterID ) { case End_Device_Bind_rsp: if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess ) { printf("Bind success!\r\n"); } else { printf("Bind failure!\r\n"); } break; } }当设备的绑定状态发生改变时,被指定的任务(ProjectApp_TaskID)会收到SYS_EVENT_MSG事件下的ZDO_CB_MSG事件,我们刚刚定义的ProjectApp_ProcessZDOMsgs()函数自然就是在这里被调用的了。所以,我们在ProjectApp_ProcessEvent()函数中的switch语句中加入如下case分支:
case ZDO_CB_MSG : ProjectApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt ); break;//每次“绑定”状态发生改变,均会调用此函数
4、绑定发送函数,声明及定义如下:
5、实验验证...... static void ProjectApp_SendBindcast( void ); ......static void ProjectApp_SendBindcast( void ) { char theMessageData[ ] = "Bind data\r\n"; ProjectApp_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent; ProjectApp_DstAddr.endPoint = 0; ProjectApp_DstAddr.addr.shortAddr = 0; AF_DataRequest( &ProjectApp_DstAddr, &ProjectApp_epDesc, PROJECTAPP_CLUSTERID, (byte)osal_strlen( theMessageData ) + 1, (byte *)&theMessageData, &ProjectApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ); }其中需要注意的是,目的地址的地址模式(ProjectApp_DstAddr.addrMode)部分,需要指定为AddrNotPresent;相信这个函数的定义大家也是一眼就能看明白~
(1)发起绑定请求
(2)调用绑定发送函数static void ProjectApp_HandleKeys( uint8 shift, uint8 keys ) { ...... if ( keys & HAL_KEY_SW_2 ) { ...... // Initiate an End Device Bind Request for the mandatory endpoint printf("Bind start!\r\n"); zAddrType_t dstAddr; dstAddr.addrMode = Addr16Bit; dstAddr.addr.shortAddr = 0x0000; // Coordinator ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(), ProjectApp_epDesc.endPoint, PROJECTAPP_PROFID, PROJECTAPP_MAX_CLUSTERS, (cId_t *)ProjectApp_ClusterList, PROJECTAPP_MAX_CLUSTERS, (cId_t *)ProjectApp_ClusterList, FALSE ); } ...... }static void ProjectApp_HandleKeys( uint8 shift, uint8 keys ) { ...... if ( keys & HAL_KEY_SW_1 ) { ...... ProjectApp_SendBindcast(); } }(3)编译下载
(4)实验现象在IAR左侧的Workspace中,一个ZigBee设备选择CoordinatorEB编译下载,其余所有的ZigBee设备任意选择RouterEB或EndDeviceEB编译下载,如下图所示进行选择;
所有的ZigBee设备上电后,不对ZigBee协调器做任何操作,也不对其余ZigBee设备做任何操作,按下除了协调器之外的其余ZigBee设备上的KEY1后,并不能在任何两个ZigBee设备之间进行无线数据的收发。
除协调器之外的其余任意ZigBee设备上,按下KEY2,就可以向ZigBee协调器发送绑定请求;任意ZigBee设备上的KEY1可以触发绑定发送;凡是成功建立绑定关系的ZigBee设备,都能收到发送设备发送的绑定数据包,该设备上的LED1状态会取反,同时串口每次都会打印出“Bind data”:
(配套源码、软件、开发板等资源,可移步博客同名QQ群/TB店铺:拿破仑940911)