ZIGBEE通讯-13.网络通讯

在ZigBee网络中进行数据通信主要有三种类型:广播(Broadcast)、单播(Unicast)和组播(Multicast)。

广播描述的是一个节点发送的数据包,网络中的所有节点都可以收到。这类似于开会时,领导讲话,每个与会者都可以听到。如图所示:

ZIGBEE通讯-13.网络通讯_第1张图片

 单播描述的是网络中两个节点之间进行数据包的收发过程。这就类似于任意两个与会者之间进行的讨论。如图所示:

ZIGBEE通讯-13.网络通讯_第2张图片

 组播,又称为多播,描述的是一个节点发送的数据包,只有和该节点属于同一组的节点才能收到该数据包。这类似于领导开完会后,各个小组进行自由讨论,只有本小组的成员才能听到相关的讨论内容,不属于该小组的成员不需要接受相关信息。如图所示:

ZIGBEE通讯-13.网络通讯_第3张图片

 那么,ZigBee协议栈是如何实现上述通信方式的呢?简单来说,ZigBee协议栈将数据通信过程高度抽象,使用一个函数完成数据的发送,以不同的参数来选择数据发送方式(广播、组播还是单播)。该函数如下:

afStatus_t AF_DataRequest( afAddrType_t *dstAddr, 
                             endPointDesc_t *srcEP,
                             uint16 cID, 
                             uint16 len, 
                             uint8 *buf, 
                             uint8 *transID,
                             uint8 options, 
                             uint8 radius );

函数的第一个参数是一个指向afAddrType_t类型的结构体的指针,该结构体的定义如下:

typedef struct
{
    union
    {
        uint16      shortAddr;
        ZLongAddr_t extAddr;
    } addr;
    afAddrMode_t addrMode; // 发送方式
    uint8 endPoint;
    uint16 panId;  // used for the INTER_PAN feature
}afAddrType_t;

在afAddrType_t结构体中,有一个表示地址模式的参数类型为afAddrMode_t,它是一个枚举类型,定义为:

typedef enum
{
  afAddrNotPresent = AddrNotPresent,
  afAddr16Bit      = Addr16Bit, // 单播方式发送数据
  afAddr64Bit      = Addr64Bit,
  afAddrGroup      = AddrGroup, // 组播方式发送数据
  afAddrBroadcast  = AddrBroadcast // 广播方式发送数据
} afAddrMode_t;

可见:

  • 当addrMode=AddrBroadcast时,就对应的广播方式发送数据:
  • 当.ddrMode= AddrGroup时,就对应的组播方式发送数据;
  • 当addrMode=Addrl6Bit时,就对应的单播方式发送数据。

1、单播

通过上面所讲原理可知,不同的通信方式只需要改变addrMode就可以了。下面打开SampleApp.c  文件,仿照协议栈已经定义好的广播和组播,定义单播模式,如下:

ZIGBEE通讯-13.网络通讯_第4张图片

接下来,在初始化函数中对SampleApp_Point_DstAddr的一些参数进行配置,参考广播或者组播就可以了,如下:

ZIGBEE通讯-13.网络通讯_第5张图片

 最后一句配置单播发送的对象时0x0000,也就是协调器的地址,节点与协调器单播通信。

接下来需要定义单播通信的发送函数,通过发送函数发送This is a unicast,依然参考广播和组播通信的发送函数,如下:

void SampleApp_SendPointMessage( void )
{
  char buffer[] = "This is a unicast\n";
  if ( AF_DataRequest( &SampleApp_Point_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_POINT_CLUSTERID, // 自己定义的单播ID
                       18,
                       buffer,
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
  else
  {
    // Error occurred in request to send.
  }
}

相对于广播发送来说,我们只需要将发送函数的第一个参数改成新定义的SampleApp_Point_DstAddr就可以了,簇ID为新定义的一个宏,如下:

ZIGBEE通讯-13.网络通讯_第6张图片

函数定义完成之后,还需要在文件上部进行声明,如下:

ZIGBEE通讯-13.网络通讯_第7张图片

 下面我们把周期发送部分的广播发送改为单播发送,发送部分就完成了,如下:

ZIGBEE通讯-13.网络通讯_第8张图片

在接收方面,我们只需要在无线接收中添加对单播簇ID的判断与处理就可以了,如下:

ZIGBEE通讯-13.网络通讯_第9张图片

 由于协调器不允许给自己单播,故周期性单播初始化时协调器不能初始化。如下:

ZIGBEE通讯-13.网络通讯_第10张图片

将终端、路由以及协调器程序下载进开发板中,并通过串口连接在PC上,可以看到只有 协调器 在一个周期内收到信息。也就是说路由器和终端均与地址为 0x0000 (协调器)的设备通信,不与其他设备通信,实现单播传输。

ZIGBEE通讯-13.网络通讯_第11张图片

 2、广播

广播的定义,协议栈已经全部定义好了,我们只需要直接调用就可以了,可以看到,设备通信地址配置的为0xFFFF。广播地址主要有三种类型:

  • 0xFFFF——数据包将被传送到网络上的所有设备,包括睡眠中的设备。对于睡眠中的设备,数据包将被保留在其父亲节点直到查询到它,或者消息超时。
  • 0xFFFD——数据包将被传送到网络上的所有在空闲时打开接收的设备(RXONWHENIDLE),也就是说,除了睡眠中的所有设备。
  • 0xFFFC——数据包发送给所有的路由器,包括协调器。

接着看广播的发送函数,如下:

ZIGBEE通讯-13.网络通讯_第12张图片

发送函数的第一个参数为广播方式,簇ID也为广播簇ID。周期发送时,调用了广播发送函数,将设备类型发送了出去。如下:

ZIGBEE通讯-13.网络通讯_第13张图片

 无线接收部分,判断为广播簇ID时,将设备地址打印出去,如下:

ZIGBEE通讯-13.网络通讯_第14张图片

3、组播

组播的相关定义协议栈也已经写好了,我们在使用的时候根据需要进行修改就可以了,如下:

 组播通信的组信息在哪里呢?协议栈也已经定义好了,如下:

ZIGBEE通讯-13.网络通讯_第15张图片

可以看到,组的类型为结构体aps_Group_t,来看一下aps_Group_t的定义,如下:

ZIGBEE通讯-13.网络通讯_第16张图片

 每个定义的组有一个特定的ID,然后是组名,组名存放在name数组中。name数组的第一个元素是组名的长度,从第二个元素开始存放真正的组名字符串。

在初始化函数SampleApp_Init()中,将组信息进行了添加,默认情况下,所有设备都从组1开始。如下:

为了区分两个路由设备以及协调器,我们定义一个全局变量作为设备号来使用,如果设置为0,就为协调器,如果设置为1,就为路由设备1,如果设置为2,就为路由设备2,如下:

ZIGBEE通讯-13.网络通讯_第17张图片

 接下来,将组播通信的发送函数修改为如果设备号为0就发送this is a GroupMSG0,如果为1就发送this is a GroupMSG1,如果为2就this is a GroupMSG2,终端消息ID为组播的簇ID,如下:

void SampleApp_SendFlashMessage( uint16 flashTime )
{
  (void) flashTime;
  char *buffer = NULL;
  char buffer0[] = "this is a GroupMSG0\n";
  char buffer1[] = "this is a GroupMSG1\n";
  char buffer2[] = "this is a GroupMSG2\n";
  if(device == 0)
  {
    buffer = buffer0;
  }
  else if(device == 1)
  {
    buffer = buffer1;

  }
  else if(device == 2)
  {
    buffer = buffer2;
  }


  if ( AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_FLASH_CLUSTERID,
                       20,
                       buffer,
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
  else
  {
    // Error occurred in request to send.
  }
}

然后我们将周期广播发送改为组播发送,这样就可以实现周期组播发送了,组播发送需要传参,所以传了一个0,如下:

ZIGBEE通讯-13.网络通讯_第18张图片

 在接收部分,我们只需要在无线接收中修改对组播簇ID的判断与处理就可以了,如下:

ZIGBEE通讯-13.网络通讯_第19张图片

将修改 后的程序分别以 1个协调器、2个路由器的方式下载到 3个设备,把协调器和路由器1组号设置成 0x0001 ,路由器设备 2  组号设成 0x0002 。连接串口,可以观察到只有组号为0x0001  的两个设备相互发送信息。如图:

ZIGBEE通讯-13.网络通讯_第20张图片

 

最后,再补充一点知识,终端设备不参与组播,原因是 SampleAPP 例程中终端设备默认采用睡眠中断的工作方式,射频不是一直工作。这个在协议规范里面是有规定的,睡眠中断不接收组播信息,如果一定想要接收的话,只有将终端的接收机一直打开,这样就可以接收到了。

具体做法为:将 f8config.cfg 配 置 文 件 中 的 -RFD_RCVC_ALWAYS_ON=FALSE 改 为-RFD_RCVC_ALWAYS_ON=TRUE 就可以了!如图:

ZIGBEE通讯-13.网络通讯_第21张图片

 

你可能感兴趣的:(ZIGBEE通讯)