目录
在ZigBee网络中进行数据通信主要有三种类型:广播(Broadcast),单播(Unicast)和组播(Multicast)。
广播描述的是一个节点发送的数据包,网络中的所有节点都可以收到,类似于开会时,领导讲话,每个开会者都可以听到
单播描述的是网络中两个节点之间进行数据包的收发过程,类似于任意两个与会者之间进行的讨论
组播又称为多播,描述的是一个节点发送的数据包,只有和该节点属于同一组的节点才能收到该数据包。类似于领导讲完话后,各小组进行讨论,只有本小组的成员才能听到该相关的讨论内容,不属于该小组的成员不需要听取相关的内容
- 广播和单播通信:
协调器周期性以广播的形式向终端节点发送数据(每隔5s广播一次),终端节点收到数据后,使开发板上的LED状态翻转,同时向协调器发送字符串“Enddevice received!”,协调器收到终端节点发回的数据后,通过串口输出到PC机
协调器编程:
//Coordinator.c
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case AF_INCOMING_MSG_CMD: //收到新数据事件
GenericApp_MessageMSGCB( MSGpkt );
break;
case ZDO_STATE_CHANGE: //建立网络后,设置事件
GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);
if(GenericApp_NwkState == DEV_ZB_COORD)
{
osal_start_timerEx(GenericApp_TaskID,SEND_TO_ALL_EVENT,5000);
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt );
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
}
return (events ^ SYS_EVENT_MSG);
}
if(events & SEND_TO_ALL_EVENT) //数据发送事件处理
{
GenericApp_SendTheMessage();
osal_start_timerEx(GenericApp_TaskID,SEND_TO_ALL_EVENT,5000);
return (events ^ SEND_TO_ALL_EVENT);
}
return 0;
}
当网络状态发生变化时,启动定时器定时5s,定时时间到达后,设置SEND_TO_ALL事件,在SEND_TO_ALL事件处理函数中,调用发送数据函数GenericApp_SendTheMessage(),发送完数据后,再次启动定时器,定时5s.......
Coordinator.c
#define SEND_TO_ALL_EVENT 0x01 //定义发送事
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
char buf[20];
unsigned char buffer[2]={0x0A,0x0D}; //回车换行的ASCII码
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memcpy(buf,pkt->cmd.Data,20);
HalUARTWrite(0,buf,20);
HalUARTWrite(0,buffer,2); //输出回车换行符
break;
}
}
void GenericApp_SendTheMessage( void )
{
unsigned char *theMessageData = "Coordinator send!";
afAddrType_t my_DstAddr;
my_DstAddr.addrMode= (afAddrMode_t)AddrBroadcast;
my_DstAddr.endPoint= GENERICAPP_ENDPOINT;
my_DstAddr.addr.shortAddr= 0xFFFF;
AF_DataRequest( &my_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
osal_strlen(theMessageData)+1,
theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) ;
}
当收到终端节点发回的数据后,读取该数据,然后发送到串口,使用广播方式发送数据
终端节点编程:
//Enddevice.c
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
char *recvbuf;
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memcpy(recvbuf,pkt->cmd.Data,osal_strlen("Coordinator send!")+1);
if(osal_memcmp(recvbuf,"Coordinator send!",osal_strlen("Coordinator send!")+1))
{
GenericApp_SendTheMessage();
}
else
{
}
break;
}
}
void GenericApp_SendTheMessage( void )
{
unsigned char *theMessageData = "EndDevice received!";
afAddrType_t my_DstAddr;
my_DstAddr.addrMode= (afAddrMode_t)Addr16Bit;
my_DstAddr.endPoint= GENERICAPP_ENDPOINT;
my_DstAddr.addr.shortAddr= 0x0000;
AF_DataRequest( &my_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
osal_strlen(theMessageData)+1,
theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) ;
HalLedSet(HAL_LED_2,HAL_LED_MODE_TOGGLE);
}
当接收到协调器发送的字符串“Coordinator send!”时,调用函数GenericApp_SendTheMessage()发送返回消息,向协调器发送单播数据
最终出现如下现象:
- 组播:
协调器周期性以组播的形式向路由器发送数据(每隔5s发送组播数据一次),路由器收到数据后,使开发板上的LED状态翻转,同时向协调器发送字符串“Router received!”,协调器收到路由器发回的数据后,通过串口输出到PC机
协调器编程:
//Coordinator.c
aps_Group_t GenericApp_Group; //定义了一个aps_Group_t类型的变量GenericApp_Group
void GenericApp_Init( byte task_id )
{
halUARTCfg_t uartConfig;
GenericApp_TaskID = task_id;
GenericApp_TransID = 0;
GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;
GenericApp_epDesc.task_id = &GenericApp_TaskID;
GenericApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
GenericApp_epDesc.latencyReq = noLatencyReqs;
afRegister( &GenericApp_epDesc );
uartConfig.configured = TRUE;
uartConfig.baudRate = HAL_UART_BR_115200;
uartConfig.flowControl = FALSE;
uartConfig.callBackFunc = NULL;
HalUARTOpen (0, &uartConfig);
GenericApp_Group.ID = 0x0001;
GenericApp_Group.name[0] = 6;
osal_memcpy(&(GenericApp_Group.name[1]),"Group1",6);
}
将组ID初始化为0x0001,将组名的长度写入name数组的第1个元素位置处,使用osal_memcpy()函数将组名“Group1”拷贝到name数组中,从第2个元素位置处开始存放数组名,这样就可以使用aps_AddGroup()函数使该端口加到组中
//Coordinator.c
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
char buf[17];
unsigned char buffer[2]={0x0A,0x0D}; //回车换行的ASCII码
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memcpy(buf,pkt->cmd.Data,17);
HalUARTWrite(0,buf,17);
HalUARTWrite(0,buffer,2); //输出回车换行符
break;
}
}
void GenericApp_SendTheMessage( void )
{
unsigned char *theMessageData = "Coordinator send!";
afAddrType_t my_DstAddr;
my_DstAddr.addrMode= (afAddrMode_t)AddrGroup;
my_DstAddr.endPoint= GENERICAPP_ENDPOINT;
my_DstAddr.addr.shortAddr= GenericApp_Group.ID;
AF_DataRequest( &my_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
osal_strlen(theMessageData)+1,
theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) ;
}
当接收到路由器发送的回复消息后,读取并输出到串口;实现了组播发送,此时地址模式设置为AddrGroup,网络地址设置为组ID,即GenericApp_Group.ID。
路由器编程:
//Enddevice.c
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case AF_INCOMING_MSG_CMD:
GenericApp_MessageMSGCB(MSGpkt);
break;
case ZDO_STATE_CHANGE: //建立网络后,加入组中
GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);
if(GenericApp_NwkState == DEV_ROUTER)
{
//接收“该”消息。
aps_AddGroup(GENERICAPP_ENDPOINT,&GenericApp_Group);
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt ); //释放内存
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
}
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
char buf[18];
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memcpy(buf,pkt->cmd.Data,osal_strlen("Coordinator send!")+1);
if(osal_memcmp(buf,"Coordinator send!",osal_strlen("Coordinator send!")+1))
{
GenericApp_SendTheMessage();
}
break;
}
}
void GenericApp_SendTheMessage( void )
{
unsigned char *theMessageData = "Router received!";
afAddrType_t my_DstAddr;
my_DstAddr.addrMode= (afAddrMode_t)Addr16Bit;
my_DstAddr.endPoint= GENERICAPP_ENDPOINT;
my_DstAddr.addr.shortAddr= 0x0000;
AF_DataRequest( &my_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
osal_strlen(theMessageData)+1,
theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) ;
HalLedSet(HAL_LED_2,HAL_LED_MODE_TOGGLE);
}
接收到协调器发送的数据后,判断是否是“Coordinator send!”,如果接收正确,则调用GenericApp_SendTheMessage()函数,以单播的方式向协调器发送数据"Router received!",发送完数据后,调用HalLedSet()函数使LED得状态翻转
最终出现如下现象: