lesson10 Zigbee组播通信原理

文章详细介绍了Zigbee组播通信的原理,包括组播的特点和与广播通信的相似性。实验部分描述了如何通过模块的组号、端点号和簇进行数据包的发送与接收,以及如何通过按键操作改变模块的组关联,实现数据的定向传输。实验结果显示,组播通信能成功实现单个发送设备向多个接收设备同时发送数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

Zigbee组播通信原理

实验原理

实验过程

实验设计

发送模块

接收模块

实验现象

组播通信总结


Zigbee组播通信原理

实验原理

1、组播通信:在Zigbee无线网络里,模块可以进行分组来标记。发送的模块如果发送的组号和网络里标记模块的组号相对应,那么这些模块就可以拿到发送模块发送的这些无线数据包。

2、组播特点:

  • 分组中组的编号是两个字节,和我们的簇是一样的。
  • 组都是和模块里已经定义了的端点相关联,如果我们说一个模块标记为组1,那么这个模块里至少有1个定义了的可用的端点和组0x0001相关联。
  • 一个组可以与多个端点关联,同样一个端点也可以同时关联多个组。
  • 发送的模块按照组的方式发送了一个无线数据包,需要指定的内容:目标模块的组编号、端点号、簇,原则上只有当接收模块的这三个参数都匹配上了,才能拿到和处理这样一个无线数据包。

举例如下所示:发送模块A发送了一个无线数据包,无线数据包中指定了接收者要满足:组号为0x0001、端点号为10、簇为0x0001,因此通过判断只有模块B的10号端点最终成功接收到了数据包。

3、组播通信与广播通信相似,单个发送设备可以同时向多个接收设备发送数据。

实验过程

实验设计

本节实验代码基于上一节广播实验进行修改。

关于实验我设计的内容如下图所示:

两个模块上电成功组网后,接收模块默认不关联任何组,按钮1按下,端点将只与组0x0001关联,按钮2按下,端点将只与组0x0002关联。发送模块按下按钮1或者按钮2发送数据包,接收模块簇0x0001如果接收到数据则将有效数据发送给串口上位机,否则什么也不做。

注:按钮按下后,模块对应的LED灯闪烁3S。

发送模块

发送数据的程序我们只需将发送模式改为组播,目标地址改为组编号即可,其它不变(端点号默认为10,簇默认为0x0001)

注意StarryApp_DstAddr结构体无论是在单播、广播还是组播中都是用来指定描述接收模块的一些信息

 

 任务事件处理函数中按键事件代码为:

 if( events & StarryApp_MY_KEY_EVT)
  {
      keyChange_t *msgPtr;
      msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );//定义一个按钮状态改变的消息
      if( msgPtr )
      {
        msgPtr->hdr.event = KEY_CHANGE;//给这个消息填写类型
        if(P0_0==0)//KEY1
        {
          msgPtr->keys=1;//赋值 
           
          char theMessageData[] = "你好";
           
          StarryApp_DstAddr.addrMode = (afAddrMode_t)AddrGroup;//发送模式是组播的方式
          StarryApp_DstAddr.addr.shortAddr = 0x0001;//表示目标接收模块的组编号
          // Take the first endpoint, Can be changed to search through endpoints
          StarryApp_DstAddr.endPoint = StarryApp_ENDPOINT;//10
          
          AF_DataRequest( &StarryApp_DstAddr, &StarryApp_epDesc,
                     StarryApp_CLUSTERID,//0x0001
                     (byte)osal_strlen( theMessageData ) + 1,
                     (byte *)&theMessageData,
                     &StarryApp_TransID,
                     AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
        }
        if(P0_1==0)//KEY2
        {
          msgPtr->keys=2;//赋值
          
          char theMessageData[] = "hello";
           
          StarryApp_DstAddr.addrMode = (afAddrMode_t)AddrGroup;//发送模式是组播的方式
          StarryApp_DstAddr.addr.shortAddr = 0x0002;//表示目标接收模块的组编号
          // Take the first endpoint, Can be changed to search through endpoints
          StarryApp_DstAddr.endPoint = StarryApp_ENDPOINT;//10
          
          AF_DataRequest( &StarryApp_DstAddr, &StarryApp_epDesc,
                     StarryApp_CLUSTERID,//0x0001
                     (byte)osal_strlen( theMessageData ) + 1,
                     (byte *)&theMessageData,
                     &StarryApp_TransID,
                     AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
        }        
        osal_msg_send( StarryApp_TaskID, (uint8 *)msgPtr );//把发送给应用层StarryApp_TaskID的消息发送到消息队列
      }
  }

LED灯对应定时器如下

接收模块

在应用层初始化函数中默认挂钩了端点号10,所以我们不需要改,具体可以跳转到宏定义去查看

同样簇的编号也被默认定义了0x0001,我们也不需要动

因此我们只需要关联组即可。

我们标记组的话,首先要定义一个组的结构体变量aps_Group_t StarryApp_Group;

组的结构体和相关函数可以在aps_groups.h中找到

定义完组结构体,给组结构体的第一个成员变量ID赋值为组编号0x0001,第二个参数name可以不用,name的作用就相当于一个注释,给组起个别名,最多不能超过16个字节

然后我们调用函数ZStatus_t aps_AddGroup( uint8 endpoint, aps_Group_t *group );(也在组头文件中有声明),它的作用是将我们的端点与组关联起来。(第一个参数为关联的端点号,第二个参数是组结构体的地址)

在关联之前我们还需要调用函数extern uint8 aps_RemoveGroup( uint8 endpoint, uint16 groupID );,它的作用时去除当前端点所关联的组编号。来确保只有一个组与我们的10号端点关联。(第一个参数是我们要取消关联的端点,第二个参数是取消关联的组号)

 按键操作程序如下:

  if( events & StarryApp_MY_KEY_EVT)
  {
      keyChange_t *msgPtr;
      
      aps_Group_t StarryApp_Group;
      
      msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );//定义一个按钮状态改变的消息
      if( msgPtr )
      {
        msgPtr->hdr.event = KEY_CHANGE;//给这个消息填写类型
        if(P0_0==0)//KEY1
        {
           msgPtr->keys=1;//赋值
           aps_RemoveGroup(10,0x0002);
           //如果10号端点关联了0x0002,那么就取消组2的关联;如果没有关联,就不做处理。
           StarryApp_Group.ID=0x0001;
           aps_AddGroup(10,&StarryApp_Group);
        }
        if(P0_1==0)//KEY2
        {
           msgPtr->keys=2;//赋值
           aps_RemoveGroup(10,0x0001);
           //如果10号端点关联了0x0001,那么就取消组2的关联;如果没有关联,就不做处理。
           StarryApp_Group.ID=0x0002;
           aps_AddGroup(10,&StarryApp_Group);
        }        
        osal_msg_send( StarryApp_TaskID, (uint8 *)msgPtr );//把发送给应用层StarryApp_TaskID的消息发送到消息队列
      }
  }

消息处理函数要修改成适合组播的接收处理程序,其中pkt结构体变量的groupId成员,如果为0,表示收到的数据包不是通过组播发送的,而是通过单播或者广播等

 

static void StarryApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
  unsigned char rcvbuff[40]={0};
  unsigned char str[20];

  if(pkt->groupId==0x0001)
  {
    if(pkt->endPoint==10)
    {
      switch(pkt->clusterId)
      {
      case 0x0001:
        strncpy(str,pkt->cmd.Data,pkt->cmd.DataLength);
        sprintf((unsigned char*)rcvbuff,"receive: %s\n",str);
        String_Print("组0x0001 ");
        String_Print(rcvbuff);
       break;
      }
    }
  }
  if(pkt->groupId==0x0002)
  {
    if(pkt->endPoint==10)
    {
      switch(pkt->clusterId)
      {
      case 0x0001:
        strncpy(str,pkt->cmd.Data,pkt->cmd.DataLength);
        sprintf((unsigned char*)rcvbuff,"receive: %s\n",str);
        String_Print("组0x0002 ");
        String_Print(rcvbuff);
       break;
      }
    }
  }
}

实验现象

我们将发送程序下载到终端,接收程序分别下载到协调器和路由器。由于LED灯的闪烁效果不方便拍照,我在这里只截取了通信过程中的上位机串口显示,也仅说明串口显示的过程。

首先三个模块分别上电:协调器->路由器->终端(谁先上电无所谓,最好协调器先上电创建好网络,其它模块再上电)

然后终端按下S1和S2,此时发现只有终端的LED灯发生闪烁;协调器和终端没有收到任何数据,说明当前两个接收模块都还未关联组。

接下来按下协调器的S1(关联组0x0001),然后按下终端的S1,协调器成功收到路由器数据

再来按下协调器的S2(关联组0x0002),然后按下终端的S2,协调器成功收到路由器数据

最后我们再按下路由器的S2(关联组0x0002),然后再按下终端的S2,发现协调器模块和终端模块同时收到数据。(到此成功验证了我们组播模块通信实验正确无误)

组播通信总结

  • 对于发送模块来说组播和广播没有什么太大区别,仅仅是发送的地址模式和地址内容这两个参数要修改为组播。
  • 对于接收模块来说,组播用到了组的相关结构体,因此要在应用层文件中添加组头文件aps_groups.h,并且在数据处理函数中要添加组号的相关判断。
  • 此外通过实验可以发现,组播通信与广播通信相似,单个发送设备可以同时向多个接收设备发送数据。
  • 还有消息处理函数要修改成适合组播的接收处理程序,其中pkt结构体变量的groupId成员,如果为0,表示收到的数据包不是通过组播发送的,而是通过单播或者广播等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竹烟淮雨(408考研ing)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值