基于ZigBee多跳组播实验文档格式.docx
《基于ZigBee多跳组播实验文档格式.docx》由会员分享,可在线阅读,更多相关《基于ZigBee多跳组播实验文档格式.docx(15页珍藏版)》请在冰豆网上搜索。
![基于ZigBee多跳组播实验文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/22/db80a91e-6d59-4b5b-bd63-3173738b1279/db80a91e-6d59-4b5b-bd63-3173738b12791.gif)
如果电阻R输出是高电平,三极管导通,集电极的电流能够使得蜂鸣器发声。
当输出为低电平,三极管截止,蜂鸣器没有电流通过,不会发声。
如果输出为方波,通过控制方波的频率,蜂鸣器也能够产生简单的音乐。
2.程序流程
组播通信寻址使用16位多播组ID完成。
多播组是所有已登记在同一个多播组ID下节点的集合。
一个多播信息发送给一个特定的目标组,即多播表中该组ID所列的所有设备。
组播数据帧既可以由目标多播组的成员在网络中传播,也可以由非目标多播组成员在网络中传播。
数据包发送由数据包的一个地址模式标志指明,确定转发到下一跳的方式。
如果原始信息由组的成员创建,就被视为处于“成员模式”,按广播方式转发。
如果原始信息不是组成员设备创建,就被视为处于“非成员模式”,按单播方式转发一个组成员。
如果一个非成员信息到达目标组的任何成员,不管下一个数据包由哪个设备进行转发,就会立即转换为成员模式类型。
实现组播通信,首先,要对组对象进行定义和初始化,将设备加入到特定组中,然后,向特定设备组发送组播消息,最后组内成员接收到消息后,进行相应消息处理。
1)组对象初始化
组播网络中,设备发出的消息经过组寻址才会发到具有相同组号的组员设备中。
组号用来标记设备所属的组,而组寻址需要定义组播地址。
(1).在SampleApp.h中定义两者的组ID,以标记设备所属的组。
#defineSAMPLEAPP_FLASH_GROUP10x0001
#defineSAMPLEAPP_FLASH_GROUP20x0002
(2)在程序SampleApp.c文件的SampleApp_Init函数中定义两个组对象并进行简单初始化,主要包括组的ID和组名字。
aps_Group_tSampleApp_Group1;
//定义组1和组2对象
aps_Group_tSampleApp_Group2;
//组1初始化
SampleApp_Group1.ID=0x0001;
osal_memcpy(SampleApp_Group1.name,"
Group1"
7);
//组2初始化
SampleApp_Group2.ID=0x0002;
//
osal_memcpy(SampleApp_Group2.name,"
Group2"
(3)组播地址定义。
组播通信过程中,网络中节点是通过使用组地址进行网络寻址,并能够向特定分组节点传递消息。
组播数据包应该具有设备寻址的地址模式、所属任务的端点号和组号。
组1地址定义以及初始化为:
//定义组1地址
afAddrType_tSampleApp_Flash_DstAddr_Group1;
//设置地址模式为组播
SampleApp_Flash_DstAddr_Group1.addrMode=(afAddrMode_t)afAddrGroup;
SampleApp_Flash_DstAddr_Group1.endPoint=SAMPLEAPP_ENDPOINT;
//设置组地址为组1ID号
SampleApp_Flash_DstAddr_Group1.addr.shortAddr=SAMPLEAPP_FLASH_GROUP1;
2)设备入组/离开组
(1).在ZigBee网络实现组播通信时,设备加入组是通过设备端点加入到工作组中。
aps_AddGroup(SAMPLEAPP_ENDPOINT,&
SampleApp_Group);
初始情况下,编者将设备都加入到了组1和组2中:
SampleApp_Group1);
SampleApp_Group2);
#ifdefined(LCD_SUPPORTED)
HalLcdWriteString("
GROUP1+2"
HAL_LCD_LINE_6);
#endif
(2).将一个设备从工作组中移除,将该端点依据组ID号将其从组中移除。
aps_RemoveGroup(SAMPLEAPP_ENDPOINT,SAMPLEAPP_FLASH_GROUP);
(3).使用aps_FindGroup函数判断一设备端点SAMPLEAPP_ENDPOINT是否在组ID号为SAMPLEAPP_FLASH_GROUP的组中。
grp=aps_FindGroup(SAMPLEAPP_ENDPOINT,SAMPLEAPP_FLASH_GROUP);
读者可以在按键函数(SampleApp_HandleKeys)中利用这三个函数实现设备入组、退组、以及组间切换。
3)向特定组发送消息
设备在按键函数中调用SampleApp_SendFlashMessage()函数来发送消息。
本例中,为了实现对不同分组函数控制,编者加入了组号“SAMPLEAPP_FLASH_GROUP”参数:
SampleApp_SendFlashMessage(uint16flashTime,uint8SAMPLEAPP_FLASH_GROUP)
该函数中调用AF_DataRequest()函数进行数据收发,下面是向组1设备发送消息的语句:
if(AF_DataRequest(&
SampleApp_Flash_DstAddr_Group1,&
SampleApp_epDesc,
SAMPLEAPP_FLASH_CLUSTERID,
3,
buffer,
&
SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS)==afStatus_SUCCESS)
{}
AF_DataRequest()函数中需要定义ZigBee设备完整地址,包括网络地址以及端点地址、源端点描述符、发送端ClusterID、数据以及数据长度等。
4)组设备接收到消息,并进行相应处理
节点接收到其他节点设备到来的数据后,应用层任务事件处理函数调用SampleApp_MessageMSGCB()回调函数将进行处理。
回调函数根据到来数据包的ClusterID判断数据类型,如果ClusterID为SAMPLEAPP_FLASH_CLUSTERID,设备蜂鸣器和LED会进行相关数据包接收指示操作:
SampleApp_MessageMSGCB(afIncomingMSGPacket_t*pkt){
switch(pkt->
clusterId)
{
caseSAMPLEAPP_FLASH_CLUSTERID:
flashTime=BUILD_UINT16(pkt->
cmd.Data[1],pkt->
cmd.Data[2]);
HalLedBlink(HAL_LED_4,4,50,(flashTime/4));
//蜂鸣器
HalLedBlink(HAL_LED_2,4,50,(flashTime/4));
//LED灯闪
}
这里,编者并没有针对蜂鸣器编写驱动函数,而是直接利用LED4Blink函数进行操作。
与LED灯闪类似,蜂鸣器会响四次,每次周期蜂鸣器响的百分比为50%,每个周期时间为flashTime/4。
这是由于LED灯和蜂鸣器工作都是由于电平使能的。
原来芯片引脚到LED4的电平加到蜂鸣器的引脚上。
由此,读者可以联想下单片机基本的编程操作方式。
3)实验步骤
组播实验使用四个节点设备,分别编号为节点1,2,3,4。
首先将蜂鸣器接到节点模块上,与原来连接灯LED4的芯片引脚P10相连。
节点初始时,节点既加入到组1,又加入到组2中。
经过按键选择分组后,节点1为协调器,既在组1,又在组2中。
节点2在组1中,节点3在组2中,节点4既在组1,又在组2中。
第一步:
按照程序说明将源代码目录下的SampleApp.c和SampleApp.h替换SampleApp目录下的同名文件。
CoordinatorEB下载到节点1,RouterEB下载到节点2,3,4中。
第二步:
1)按下节点1(协调器)的重启键,LCD屏会显示网络号,LED3(黄灯)长亮时说明网络建立成功;
2)分别按下节点2,3,4的重启键。
等到LED3(黄灯)长亮,并且屏幕上出现设备类型和地址时,说明已与协调器节点建立连接。
3)连续按节点2的SW2(右键),直到节点屏幕上出现“GROUP1”字样,代表节点2只加入到组1中。
4)连续按节点3的SW2(右键),节点屏幕上出现“GROUP2”字样,代表节点3只加入到组2中。
5)节点4不用按键,节点4默认在组1和组2中。
第三步:
按节点1(协调器)的SW1(上键),节点1屏幕上出现“MSG2GROUP1”字样,代表向组1中发送按键消息。
这时,节点2和节点4的蜂鸣器会发出“滴滴滴滴”的声音,并且其LED2闪亮四次。
第四步:
按节点1的SW3(下键),节点1的屏幕上出现“MSG2GROUP2”字样,代表向组2中发送按键消息。
这时,节点3和节点4的蜂鸣器会发出“滴滴滴滴”的声音,并且其LED2闪亮四次。
4)程序清单
清单6.1按键处理函数
/******************************************************************************
*函数名SampleApp_HandleKeys
*描述按键处理函数,主要完成组消息发送,组间切换。
*参数uint16flashTime:
灯每次闪烁,蜂鸣器每次响的周期
*uint8SAMPLEAPP_FLASH_GROUP发送消息的组号
*返回值无
*****************************************************************************/
voidSampleApp_HandleKeys(uint8shift,uint8keys)
{
(void)shift;
//Intentionallyunreferencedparameter
if(keys&
HAL_KEY_SW_1)//上键,向组1发送消息
SampleApp_SendFlashMessage(SAMPLEAPP_FLASH_DURATION,SAMPLEAPP_FLASH_GROUP1);
}
if(keys&
HAL_KEY_SW_3)//下键,向组2发送消息
SampleApp_SendFlashMessage(SAMPLEAPP_FLASH_DURATION,SAMPLEAPP_FLASH_GROUP2);
HAL_KEY_SW_2)
//组切换,如果设备当前在1组,则转入到2组。
//如果当前在2组,则转入到1组。
//如果当前既在1组,又在2组,则只在2组。
aps_Group_t*grp1;
grp1=aps_FindGroup(SAMPLEAPP_ENDPOINT,SAMPLEAPP_FLASH_GROUP1);
//节点是否在1组中
if(grp1)//节点在1组,退出1组,加入2组。
aps_RemoveGroup(SAMPLEAPP_ENDPOINT,SAMPLEAPP_FLASH_GROUP1);
aps_AddGroup(SAMPLEAPP_ENDPOINT,&
SampleApp_Group2);
#ifdefined(LCD_SUPPORTED)
GROUP2"
#endif
else//节点不在1组中,退出2组,转入到1组。
aps_RemoveGroup(SAMPLEAPP_ENDPOINT,SAMPLEAPP_FLASH_GROUP2);
GROUP1"
清单6.2节点发送信息函数
*函数名SampleApp_SendFlashMessage
*描述向组中发送消息函数。
通过信息中的ClusterID执行相应操作。
灯闪烁、蜂鸣器响的周期
voidSampleApp_SendFlashMessage(uint16flashTime,uint8SAMPLEAPP_FLASH_GROUP)
uint8buffer[3];
buffer[0]=(uint8)(SampleAppFlashCounter++);
buffer[1]=LO_UINT16(flashTime);
buffer[2]=HI_UINT16(flashTime);
if(SAMPLEAPP_FLASH_GROUP==SAMPLEAPP_FLASH_GROUP1)//ma
{//向组1发消息
{#ifdefined(LCD_SUPPORTED)
MSG2GROUP1"
HAL_LCD_LINE_4);
//在屏幕上显示向组1发送消息
else
{//Erroroccurredinrequesttosend.
{//向组2发消息
SampleApp_Flash_DstAddr_Group2,&
{#ifdefined(LCD_SUPPORTED)
MSG2GROUP2"
清单6.3节点接收消息回调函数
*函数名SampleApp_MessageMSGCB
*描述信息回调函数,处理来自其他设备的数据,通过信息中的Cluster ID执行相应操作。
*参数afIncomingMSGPacket_t*pkt,来自其他设备的消息包
voidSampleApp_MessageMSGCB(afIncomingMSGPacket_t*pkt)
uint16flashTime;
switch(pkt->
caseSAMPLEAPP_PERIODIC_CLUSTERID:
//心跳包ClusterID
break;
caseSAMPLEAPP_FLASH_CLUSTERID:
if(pkt->
groupId==SAMPLEAPP_FLASH_GROUP1)//接收到组1消息
MSGREVG1"
MSGREVG2"
//闪灯ClusterID,设备接收到组内其他设备消息后,蜂鸣器响四下和LED灯闪四//次
//闪灯频率
HalLedBlink(HAL_LED_4,4,50,(flashTime/4));
//蜂鸣器
HalLedBlink(HAL_LED_2,4,50,(flashTime/4));
实验结果
节点初始化后,都加入到组1和组2中。
通过按键选择,三个路由节点中,一个只在组1中,一个只在组2,一个既在组1,又在组2中。
协调器通过按键分别向组1和组2中发送消息,组内设备接收到消息后,其灯闪烁并且蜂鸣器发声。
1.节点模块及程序下载
节点模块安装好蜂鸣器之后,分别编号为节点1,2,3,4。
节点实物图如图所示。
最上面的为节点1,下载的程序为协调器。
其余三个下载路由器程序,按照自左到右的顺序分别为节点2,3,4。
按下节点1的重启键后,节点1会建立一个ZigBee网络,其余节点按下重启键依次加入ZigBee网络。
图节点模块实物图
2.节点初始化,协调器并向组1发送消息
节点初始化后,节点1的屏幕第一行上可以看到“ZigBeeCoord”,代表节点1类型为协调器。
屏幕第二行出现“NWID:
19”代表网络号ID为19。
最后一行为“GROUP1+2”字样,表示节点1既在组1,又在组2中。
节点2,3,4分别出现“Router1”,“Router:
143E”,“Router:
287B”,代表加入网络后,节点类型以及协调器分别的16位网络短地址。
读者还可以看出三者父地址分别为0,即协调器地址,三者都在组1和组2中。
按下协调器的SW1(上键)后,协调器向组1发送消息,这时屏幕上显示“MSG2GROUP1”。
由于节点2,3,4全在组1中,它们屏幕上出现“MSGREVG1”,代表组1的设备接收到了消息。
这时,节点的LED2灯闪烁,蜂鸣器发声。
图节点初始化,协调器并向组1发送消息
3.节点分组后,协调器向组2发送消息
按下节点2和3的SW2(右键),分别使其只在组1和组2中。
然后,按下协调器的SW2(下键),协调器会发送消息到组2中,如图所示,这时组2中的节点3和节点4接收到消息,屏幕显示“MSGREVG2”。
灯LED2闪烁并且蜂鸣器发声。
图中节点2中显示的“MSGREVG1”,还是代表上次协调器按下上键时,接收到的组1数据包。
图节点分组后,协调器向组2发送消息
4.节点分组后,协调器向组1发送消息
按下协调器的SW1(上键),协调器会发送消息到组1中,如图所示,这时组1中的节点2和节点3接收到消息,屏幕显示“MSGREVG1”。
图中节点3中显示的“MSGREVG2”,还是代表上次协调器按下键时,接收到的组2数据包。
图节点分组后,协调器向组1发送消息
思考:
多个端点组播问题
上文中的实验只使用了一个端点,实际中我们可能需要对多个端点进行分组管理。
多个端点的组播问题可以用下面一个例子说明。
例如,一个路灯控制系统节点A网络短地址为0x5F5F,具有一个光照传感器和一个路灯控制开关。
远程节点需要获取光照传感器数值,并对数据进行分析,然后控制路灯开关。
节点的光照传感器和路灯控制开关分别注册在端点10和50上,如果远程节点获取传感器数据,则向节点A发送短地址为0x5F5F,端点号为10的数据包,端点10上建立的数据处理函数进行传感数据获取,而端点50则不会接收到数据包,也不会进行相应操作。
如果远程节点控制路灯,则向节点A发送短地址为0x5F5F,端点号为50的数据包,端点50上建立的数据处理函数会控制路灯开关,而端点10不会接收到控制数据。
如果网络中多个路灯控制节点,需要实现对特定组的路灯进行光照传感数据获取或路灯控制。
这样,程序需要在组播过程中使用两个端点。
要使用两个端点,应该再定义一个端点及端点描述符,并向AF层注册。
#defineSAMPLEAPP_MY_ENDPOINT21
endPointDesc_tSampleApp_My_epDes