Zigbee协议栈————广播组网

目录

1.基础概念

2.Zigbee协议栈工作流程

3。代码讲解


1.基础概念

在Zigbee网络中存在3中逻辑设备:协调器、路由器、终端。

(这个实验当中我们只用到协调器以及终端)。

协调器:协调器负责启动网络,当启动和配置好网络后,协调器就会像一个路由器一样或者就消失了。

终端:网络中的一个设备,一个节点。

 广播:当应用程序需要将数据包发送给网络的每一个设备时,使用这种模式。地址模式设置为
AddrBroadcast。目标地址可以设置为下面广播地址的一种:
NWK BROADCAST SHORTADDR DEVALL(0xFFFF)--数据包将被传送到网络上的所有设备,包括睡眠中的设备。
NWK BROADCAST SHORTADDR DEVRXON(0xFFFD)-数据包将被传送到网络上除了睡眠中的所有设备。
NWK BROADCAST SHORTADDR DEVZCZR(0xFFFC)--数据包发送给所有的路由器,包括协调器。

2.Zigbee协议栈工作流程

main()函数中初始化操作系统osal_init_system(),初始化一些外设(协议栈已经将这些外设封装好了,可以像32一样调用函数使用。),最后进入osal_start_system()中执行操作系统,并且程序会一直处于这个函数当中,不会返回(函数中有死循环),在这个函数当中判断是否有事件发生,然后会根据优先级来处理这些事件(任务)。我们以后主要需要修改在SampleApp_Init()当中.

 3.代码讲解

协议栈中很多东西已经帮我们写好,我们以后使用仅仅需要修改增加一些内容。因此代码不需要全部都懂。(初学者不要尝试将所有的代码都看懂,循序渐进。)

在目录中找到SampleApp.c,打开它,并在该C文件的顶部包含#include"MT_UART.h"
#include "MT_APP.h"
#include "MT.h"
#include "string.h"

这四个头文件。接下来找到void SampleApp_Init( uint8 task_id )这个函数

void SampleApp_Init( uint8 task_id )
{ 
  SampleApp_TaskID = task_id;
  SampleApp_NwkState = DEV_INIT;
  SampleApp_TransID = 0;
  //这一部分为新加进来的代码
  //------------------------配置串口---------------------------------
  MT_UartInit();                    //串口初始化
  MT_UartRegisterTaskID(task_id);   //注册串口任务
  HalUARTWrite(0,"UartInit OK\n", sizeof("UartInit OK\n"));
  
  //-----------------------------------------------------------------
  


 #if defined ( BUILD_ALL_DEVICES )
  
  if ( readCoordinatorJumper() )
    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
  else
    zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES

#if defined ( HOLD_AUTO_START )

  ZDOInitDevice(0);
#endif

 
  SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//广播模式
  SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;//广播地址
/*//组播的代码
  // Setup for the flash command's destination address - Group 1
  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;
  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;*/

  
  SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_epDesc.task_id = &SampleApp_TaskID;
  SampleApp_epDesc.simpleDesc
            = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
  SampleApp_epDesc.latencyReq = noLatencyReqs;

 
  afRegister( &SampleApp_epDesc );

  
  RegisterForKeys( SampleApp_TaskID );
/*//组播的代码
  // By default, all devices start out in Group 1
  SampleApp_Group.ID = 0x0001;
  osal_memcpy( SampleApp_Group.name, "Group 1", 7  );
  aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
*/

#if defined ( LCD_SUPPORTED )
  HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}

 其中 MT_UartInit()在目录中MT文件中的MT_UART.c的文件当中,为串口的初始化。



 

 这个初始化的函数当中,我们需要将波特率设置好,流控制关闭,其他的可以不用管。

        然后我们就可以调用HalUARTWrite(0,"UartInit OK\n", sizeof("UartInit OK\n"))来发送初始化完成的提示。然后,如上面的代码块一样,将组播的代码注释掉。

        接下来,我们进入到uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )当中。

//在这个函数当中完成对事件的处理
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
  (void)task_id;  

  if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        case KEY_CHANGE:
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;

        
        case AF_INCOMING_MSG_CMD://接收到数据包就进行处理
          SampleApp_MessageMSGCB( MSGpkt );
          break;

      
        case ZDO_STATE_CHANGE://协调器状态改变就进入下面的函数,协调器刚建立网络就会进去
          SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          if ( (SampleApp_NwkState == DEV_ZB_COORD)
              || (SampleApp_NwkState == DEV_ROUTER)
              || (SampleApp_NwkState == DEV_END_DEVICE) )
          {
            
            osal_start_timerEx( SampleApp_TaskID,
                              SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
                              SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
          }
          else
          {
           
          }
          break;

        default:
          break;
      }

     
      osal_msg_deallocate( (uint8 *)MSGpkt );

    
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    }

    return (events ^ SYS_EVENT_MSG);
  }

  
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )//上面有出现哦,协调器状态改变
  {
    
    SampleApp_SendPeriodicMessage();//协调器发送数据 

    
    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
        (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

   
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }


  return 0;
}

接下来进入SampleApp_SendPeriodicMessage()函数当中。

void SampleApp_SendPeriodicMessage( void )
{//联网后进入这个函数
  uint8 *buff=NULL;
  if(zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR)//判断Zigbee的逻辑类型,如果是协调器
  {
    buff="I am coordinator device\r\n";
  }
  else if(zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE)//如果是终端
  {
    buff="I am endpoint device\r\n";
  }
  
  
  
  
  // AF_DataRequest()这个函数是真正发送数据的函数,我们需要将第三第四个参数该为数组的大小,以及数组的内容,然后就可以发送了。
  
  if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,
                       SAMPLEAPP_PERIODIC_CLUSTERID,
                       strlen(buff),//传输数据的字节大小
                       buff,//传输数据
                       &SampleApp_TransID,
                       AF_DISCV_ROUTE,
                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
  {
  }
  else
  {
   
  }
}

 数据发送完了,当接受到数据包后,MSGpkt->hdr.event=AF_INCOMING_MSG_CMD,接下来,我们就要进入SampleApp_MessageMSGCB( MSGpkt )当中。

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )//无线数据包接收到之后
{
  uint16 flashTime;

  switch ( pkt->clusterId )
  {
    case SAMPLEAPP_PERIODIC_CLUSTERID://接收到该命令后执行的代码
      HalUARTWrite(0,(pkt->cmd).Data,(pkt->cmd).DataLength);//将接受到的数据打印到串口中
      break;

    case SAMPLEAPP_FLASH_CLUSTERID:
      flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );
      HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
      break;
  }
}

至此,代码就完成了。接下来就可以烧录,看现象了。

4.可能遇到的问题

 1.注意协调器与终端的烧录,需要分开烧录。可由上图所示更改。

2.以下问题为版本不兼容

以及一堆 Undefined external "?V1" referred in AF类似的,都是由于版本不兼容的原因。解决方法:

 

 将16改为8

  ZStack-CC2530-2.5.1a\Projects\zstack\ZMain\TI2530DB下的chipcon_cstartup.s51文件中删除END,并添加以下代码:

;----------------------------------------------------------------;
; Virtual registers						 ;
; =================						 ;
; Below is some segment needed for the IAR ICC C/EC++ compiler   ;
;								 ;
; BREG  : A segment for 8 bit registers for use by the compiler. ;
;         ?B0 is the first register.                             ;
; VREG  : Segment that holds up to 32 virtual registers for      ;
;         use by the compiler. ?V0 is the first register.        ;
; PSP   : Segment containing the PDATA stack pointer (?PSP)      ;
; XSP   : Segment containing the XDATA stack pointer (?XSP)      ;
; 								 ;
;----------------------------------------------------------------;
;----------------------------------------------------------------;

	PROGRAM VIRTUAL_REGISTERS
	PUBLIC  ?B0
	PUBLIC  ?V0
	PUBLIC  ?V1
	PUBLIC  ?V2
	PUBLIC  ?V3
	PUBLIC  ?V4
	PUBLIC  ?V5
	PUBLIC  ?V6
	PUBLIC  ?V7
	PUBLIC  ?V8
	PUBLIC  ?V9
	PUBLIC  ?V10
	PUBLIC  ?V11
	PUBLIC  ?V12
	PUBLIC  ?V13
	PUBLIC  ?V14
	PUBLIC  ?V15
	PUBLIC  ?V16
	PUBLIC  ?V17
	PUBLIC  ?V18
	PUBLIC  ?V19
	PUBLIC  ?V20
	PUBLIC  ?V21
	PUBLIC  ?V22
	PUBLIC  ?V23
	PUBLIC  ?V24
	PUBLIC  ?V25
	PUBLIC  ?V26
	PUBLIC  ?V27
	PUBLIC  ?V28
	PUBLIC  ?V29
	PUBLIC  ?V30
	PUBLIC  ?V31
	PUBLIC  ?PSP
	PUBLIC  ?XSP
	RSEG    BREG:BIT:NOROOT
?B0:
	DS      8

  	RSEG    VREG:DATA:NOROOT
?V0:
	DS      1
?V1:
	DS      1
?V2:
	DS      1
?V3:
	DS      1
?V4:
	DS      1
?V5:
	DS      1
?V6:
	DS      1
?V7:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V7
?V8:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V8
?V9:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V9
?V10:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V10
?V11:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V11
?V12:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V12
?V13:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V13
?V14:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V14
?V15:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V15
?V16:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V16
?V17:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V17
?V18:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V18
?V19:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V19
?V20:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V20
?V21:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V21
?V22:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V22
?V23:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V23
?V24:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V24
?V25:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V25
?V26:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V26
?V27:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V27
?V28:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V28
?V29:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V29
?V30:
	DS      1

  	RSEG    VREG:DATA:NOROOT
  	REQUIRE ?V30
?V31:
	DS      1

	RSEG    PSP:DATA:NOROOT
	EXTERN  ?RESET_PSP
	REQUIRE	?RESET_PSP
?PSP:
	DS      1

	RSEG    XSP:DATA:NOROOT
	EXTERN  ?RESET_XSP
	REQUIRE	?RESET_XSP
?XSP:
	DS      2

	ENDMOD ; VIRTUAL_REGISTERS

	END

3.注意在烧录前需要预编译

 

只有ZTOOL_P1前没有x,其它的都需要在前面加一个x。

4.注意协议栈里的串口0,使用的是P0_2(RX),P0_3(TX)。

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值