lesson10 Zigbee组播通信原理

news2024/9/29 13:16:25

目录

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,表示收到的数据包不是通过组播发送的,而是通过单播或者广播等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/711625.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

被偷走的文件

也是一道流量解析题目 既然是文件被盗走,可能跟文件传输协议ftp有关,过滤一下ftp 跟踪流后发现有一个flag.rar文件,是内嵌的吗? 那说明应该也可以利用binwal分出来吧 分离出来的rar文件需要密码,拿去爆破一下&#xff…

03_ES6

ES6(在js中进行操作) 使用var声明变量的弊端 var 声明的变量有预解析,造成逻辑混乱,可以先使⽤,后声明,undefined var 可以重复定义同⼀个变量,第二个会修改变量的值 var ⽤在 for 循环条件中,造成 for 循环的污染的…

【八股】【C++】(三)STL

这里写目录标题 STL定义一、容器概念(1)vector如何避免扩容导致效率低为什么是1.5或2扩容怎么找某vector或者list的倒数第二个元素vector如何释放空间[] 下标检查 (2)deque(3)stack(4&#xff0…

如何通过Python下载GSMap数据集(解决.dat无法打开的问题)?

目录 01 前言 02 GSMap-MVK的存储方式和数据集介绍 03 代码实现 01 前言 这么晚了我还是希望将这篇博客写一下,记录生活。 我所下载的数据集为GSMap-MVK数据集,延迟大概2.5月左右我记得.边下载我就想着先处理着吧。 例如,其中一个文件如…

HOT38-翻转二叉树

leetcode原题链接:翻转二叉树 题目描述 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2: 输入:…

华为OD机试真题B卷 Python 实现【小朋友排队】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Python算法源码六、效果展示1、输入2、输出 一、题目描述 小明今年升学到了小学1年级,来到新班级后,发现其他小朋友身高参差不齐,然后就想基于每个小朋友和自己的身高差&#xff…

postgresql内核分析 spinlock与lwlock原理与实现机制

​专栏内容: postgresql内核源码分析 手写数据库toadb 并发编程 个人主页:我的主页 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 概述 在postgresql 中,有大量的并发同步&#xff0…

浅谈容器技术之Podman

1.Podman容器简介 Podman(Pod Manager)是一个由RedHat公司推出的容器管理工具,它的定位就是 Docker 的替代品,在使用上与Docker 的体验类似。Podman源于CRI-O项目,可以直接访问 OCI 的实现(如 runC&#x…

【Unity实战】复刻实现经典2d平台跳跃游戏《蔚蓝 Celeste》(附工程源码)

文章目录 前言蔚蓝欣赏实现1. 移动2. 跳跃3. 滑动4. 爬墙5. 蹬墙跳6. 移动优化7. 粒子效果8. 角色环境素材9. 编写角色动画控制10. Tilemap绘制地图环境11. 环境粒子特效12. 冲锋残影效果13. 屏幕震动效果14. 涟漪效果 最终效果工程源码参考完结 前言 《蔚蓝》是一款备受好评的…

信号与系统复习笔记——通讯系统

信号与系统复习笔记——通讯系统 复指数与正弦幅度调制 y ( t ) x ( t ) c ( t ) y(t) x(t)c(t) y(t)x(t)c(t) 上式称为调制,其中 x ( t ) x(t) x(t) 称为 调制信号 ,而 c ( t ) c(t) c(t) 称为 载波信号 , y ( t ) y(t) y(t) 称为 已…

Redis高可用(主从复制、哨兵模式和Cluster集群)

文章目录 一、Redis高可用1.持久化2.主从复制3.哨兵4.Cluster集群 二、主从复制1.概念2.作用3.主从复制流程4.配置主从复制 三、哨兵模式1.功能2.作用3.组成4.故障转移机制7.故障模拟8.恢复故障节点 四、Cluster群集1.简介2.作用(1)数据分区(…

Redis常用数据类型

Redis 哈希(Hash)🍉 Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。 Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿) 它…

如何动手用js自己写一个分页?

实现效果 实现代码 function generateTableHead() {const tableHead document.getElementById(table-head);tableHead.innerHTML ;// 添加复选框列的表头const checkboxHead document.createElement(th);const checkbox document.createElement(input);checkbox.type che…

项目部署

#修改表的编码 alter table t_course convert to character set utf8 show create table t_course启动docker&#xff1a; service docker startdocker创建redis设置密码&#xff1a; docker pull redis docker run --name my-redis -p 6379:6379 -e REDIS_PASSWORD<pass…

【大数据趋势】7月2日 汇率,美澳,恒指期货的大数据趋势概率分析。

数据源头之一 : 汇率变化 从程序模拟趋势来看&#xff0c;如果没有干预&#xff0c;极大概率要试探顶部7.375的位置。【位置1】从长期趋势来看&#xff0c;在一个上升通道中长期震荡上行&#xff0c;所以正常应该走2.2的路径【趋势2.2】 因为这轮上涨的动能很大&#xff0c;所…

join on 后面的and 与where 的区别及用法

--- 先把数据导入数据库 CREATE TABLE test_join_where_a ( aid int(0) NOT NULL, aname varchar(255) , atimedate datetime(0) , ascore varchar(255) ); INSERT INTO test_join_where_a(aid, aname, atimedate, ascore) VALUES (1, 张三, 2023-05-03 01:13:30, 8…

环境变量的配置

在我上一篇文章中有写到&#xff0c;在编译和运行Hello World这个文档的时候要使用java.c和java这俩个工具&#xff0c;但是我们却没有转换到这俩个工具所在的磁盘位置&#xff0c;而是直接调用了&#xff0c;那么是怎么实现这一功能的嘞&#xff0c;就有下面的理解 首先wine打…

Linux--给指令起别名:alias

示例&#xff1a;给ls-al起了个别名叫kk​ 注意&#xff1a;起别名只在本次登录有效。

Python爬虫-某政务网站文档爬取,并将正文内容保存在word

前言 本文是该专栏的第1篇,后面会持续分享python爬虫案例干货,记得关注。 地址:aHR0cDovL3d3dy5oZWJlaS5nb3YuY24vc2VhcmNoL3BjUmVuZGVyP3BhZ2VJZD1iOTdhMzg4MzNmNzM0M2NlYmMzMWRlYzQ0NTQ0ZjY4NA== 需求:以某政务网网站为例,采集其正文内容,并将其正文内容以docx格式保…

借助APlayer、MetingJS实现 网页音乐播放器

借助APlayer、MetingJS实现 1、src/publi/index.html引入 <script src"https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script> <script src"https://cdn.jsdelivr.net/npm/meting2.0.1/dist/Meting.min.js"></scri…