zigbee协议栈工作流程 From zigbee菜鸟笔记(十 一)

zigbee协议栈工作流程 From zigbee菜鸟笔记(十 一)一.ZigBee协议栈简介什么是ZigBee协议栈呢?它和ZigBee协议有什么关系呢?协议是一系列的通信标准,通信双方需要共同按照这一标准进行正常的数据发射和接收。协议栈是协议的具体实现形式,通俗点来理解就是协议栈是协议和用户之间的一个接口,开发人员通过使用协议栈来使用个协议的,进而实现无线数据收发。ZigBee的协议分为两部分,IEEE802.15.4定义了PHY(物理层)和MAC(介质访问层)技术规范;ZigBee联盟定义了NWK(网络层)、APS(应用程序支持子层)、APL(应用层

大家好,又见面了,我是你们的朋友全栈君。

一.ZigBee 协议栈简介

有问题发送邮件至468078841@qq.com
什么是ZigBee 协议栈呢?它和ZigBee 协议有什么关系呢?协议是一系列的通信标准,通信双方需要共同按照这一标准进行正常的数据发射和接收。协议栈是协议的具体实现形式,通俗点来理解就是协议栈是协议和用户之间的一个接口,开发人员通过使用协议栈来使用个协议的,进而实现无线数据收发。

ZigBee 的协议分为两部分,IEEE 802.15.4 定义了PHY(物理层)和MAC(介质访问层)技术规范;ZigBee 联盟定义了NWK(网络层)、APS(应用程序支持子层)、APL(应用层)技术规范。ZigBee 协议栈就是将各个层定义的协议都集合在一直,以函数的形式实现,并给用户提供API(应用层),用户可以直接调用。

							 					Z-Stack协议栈体系结构								

在这里插入图片描述

二.如何使用ZigBee 协议栈

协议栈是协议的实现,可以理解为代码,函数库,供上层应用调用,协议较底下的层与应用是相互独立的。你需要关心的就是你的应用逻辑,数据从哪里到哪里,怎么存储,处理;还有系统里的设备之间的通信顺序什么的.至于初始化等等工作不需要我们考虑。我们只需要调用相关的API函数就可以了。

三.了解zigbee协议栈的应用文件夹

安装好zigbee协议栈,打开目录Texas Instruments

在这里插入图片描述

(一)Components:顾名思义这个是放我们的库的文件夹,里面放了一些我们用到的ZDO,driver,hal,zcl 等库的代码

(二)Documents:这里放的是TI 的开发文档的,里面很多都是讲述协议栈的API

(三)Projects:这个文件夹放的是TI 协议栈的例子程序。

(四)Tools:这个文件夹是放TI 的例子程序的一些上位机之类的程序,作为工具使用。

接下来介绍的东西均需要打开示例工程在这里我们打开\ZStack-CC25302.5.1a\Projects\zstack\Samples\SampleApp\CC2530DB进入zigbee的协议栈中
在这里插入图片描述

为了确保程序没问题我们在这里重新编译一下协议栈。

这是我们协议栈的汇总目录
在这里插入图片描述
这里是我们zigbee的文件夹,里面写好的代码都分为很多的group
(一)APP:应用层目录,这里用户可以创建不同的工程目录,这里包含项目工程主要内容

(二)HAL:硬件层目录,包含有与硬件相关的配置和驱动及操作函数。

(三)MAC: MAC 层目录,包含了MAC 层的参数配置文件及其MAC 的LIB 库的函数接口文件。

(四)MT:实现通过串口可控各层,于各层进行直接交互。

(五)NWK:网络层目录,含网络层配置参数文件及网络层库的函数接口文件,APS 层库的函数接口

(六)OSAL:协议栈的操作系统。

(七)Profile: AF层目录,包含AF 层处理函数文件。

(八)Security:安全层目录,安全层处理函数,比如加密函数等。

(九)Services:地址处理函数目录,包括着地址模式的定义及地址处理函数。

(十)Tools:工程配置目录,包括空间划分及ZStack 相关配置信息。

(十一)ZDO: ZDO目录。

(十二)ZMac: MAC 层目录,包括MAC 层参数配置及MAC 层LIB 库函数回调处理函数。

(十三)Output:输出文件目录,这个EW8051 IDE 自动生成的。

在这里插入图片描述
点击DemoEB可以进行设备类型工作空间选择,必须要选好,不然不可以使用。

CoordinatorEB:为协调器的工作空间。

ROuterEB:为路由器的工作空间。

EndDeviceEB:为无线终端的设备选择。

四.zigbee协议栈的工作流程

在我们这个版本的来说在我们使用者的路径流程是:main()---> osal_init_system()---> osalInitTasks()---> SampleApp_Init()

(一)打开ZMain.c 找到main 函数
学过C语言的都知道,C语言函数是在一直执行main文件里面的内容,首先我们先查看main.c的内容


int main( void )
{ 
   
  // Turn off interrupts
  osal_int_disable( INTS_ALL ); //关闭协议栈所有中断

  // Initialization for board related stuff such as LEDs
  HAL_BOARD_INIT();             //初始化协议栈系统时钟

  // Make sure supply voltage is high enough to run
  zmain_vdd_check();            //检查芯片电压是否正常

  // Initialize board I/O
  InitBoard( OB_COLD );         //初始化I/O 

  // Initialze HAL drivers
  HalDriverInit();              //初始化芯片硬件

  // Initialize NV System
  osal_nv_init( NULL );         //初始化Flash 存储器

  // Initialize the MAC
  ZMacInit();                   //初始化MAC 层

  // Determine the extended address
  zmain_ext_addr();             //确定IEEE 64位设备地址

  // Initialize basic NV items
  zgInit();                     //初始化非易失变量

#ifndef NONWK
  // Since the AF isn't a task, call it's initialization routine
  afInit();
#endif

  // Initialize the operating system
  osal_init_system();           //初始化协议栈操作系统

  // Allow interrupts
  osal_int_enable( INTS_ALL );  //使能全部中断

  // Final board initialization
  InitBoard( OB_READY );        //最终板载初始化

  // Display information about this device
  zmain_dev_info();             //LCD显示设备信息

  /* Display the device info on the LCD */
#ifdef LCD_SUPPORTED
  zmain_lcd_init();             //初始化LCD
#endif

#ifdef WDT_IN_PM1
  /* If WDT is used, this is a good place to enable it. */
  WatchDogEnable( WDTIMX );
#endif

  osal_start_system(); // No Return from here 执行操作系统,这里进入将不会退出,一直执行osal_start_system

  return 0;  // Shouldn't get here.
} // main()

我们接着看一下osal_start_system在这里我们可以点击选中然后goto到函数里面查看。
在这里插入图片描述

void osal_start_system( void )
{ 
   
#if !defined ( ZBIT ) && !defined ( UBIT )
  for(;;)  // Forever Loop //这是个死循环
#endif
  { 
   
    osal_run_system();  //协议栈一直执行这个函数
  }
}

接着继续goto osal_run_system这个是任务系统轮询的主要函数。他会查找发生的事件然后调用相应的事件执行函数, 如果没有事件登记要发生那就将进入睡眠模式。在协议栈中,所有将要处理的内容定义为事件,这个函数就是查找事件的函数,每个事件都有自己的事件号,根据事件号大小判断优先级,一个一个执行,例如按键按键,就触发按键事件,这个现在知道就可以,在后面我们会介绍。
在这里我们知道了协议栈一直执行事件扫面函数,那我们如何根据需求开发呢,我们要做的就是设置一个自己要监测的事件,然后写交互逻辑。 // 一个任务可以有多个事件

void osal_run_system( void )
{ 
   
  uint8 idx = 0;

  osalTimeUpdate();//更新事件
  Hal_ProcessPoll();

  do { 
   
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    { 
   
      break;
    }
  } while (++idx < tasksCnt);

  if (idx < tasksCnt)
  { 
   
    uint16 events;
    halIntState_t intState;

    HAL_ENTER_CRITICAL_SECTION(intState);
    events = tasksEvents[idx];
    tasksEvents[idx] = 0;  // Clear the Events for this task.
    HAL_EXIT_CRITICAL_SECTION(intState);

    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events );
    activeTaskID = TASK_NO_TASK;

    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
#if defined( POWER_SAVING )
  else  // Complete pass through all task events with no activity?
  { 
   
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif

  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
  { 
   
    osal_task_yield();
  }
#endif
}

我们接下来进行事件的初始设置。在前面main函数中 osalInitTasks(); 为初始化系统任务,我们需要将自己的需求加入其中就可以达到目的。 goto一下进入函数 //osalInitTasks这个是设置任务的函数,然后任务里面也定义了很多事件

void osalInitTasks( void )
{ 
   
  uint8 taskID = 0;

  // 分配内存,返回指向缓冲区的指针
  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  // 设置所分配的内存空间单元值为0
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

  // 任务优先级由高向低依次排列,高优先级对应taskID 的值反而小
  macTaskInit( taskID++ );  // taskID 0
  nwk_init( taskID++ );     // taskID 1
  Hal_Init( taskID++ );     //taskID 2
#if defined( MT_TASK )
  MT_TaskInit( taskID++ );
#endif
  APS_Init( taskID++ );      //taskID 3
#if defined ( ZIGBEE_FRAGMENTATION )
  APSF_Init( taskID++ );
#endif
  ZDApp_Init( taskID++ );    //taskID 4
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
  ZDNwkMgr_Init( taskID++ );  
#endif
 //SampleApp_Init为用户创建任务,我们需要在这里进行任务的添加 现在进入函数我们查看一下
  SampleApp_Init( taskID );  // taskID 5 
}

在这里我们看一下用户应用任务的事件处理函数进入SampleApp_ProcessEvent函数在这里我们可以看到在协议栈初始的时候定义的事件,和处理函数,在后面我们再详细介绍如何使用。

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{ 
   
  afIncomingMSGPacket_t *MSGpkt;
  (void)task_id;  // Intentionally unreferenced parameter

  if ( events & SYS_EVENT_MSG )//如果是SYS_EVENT_MSG 这个事件进入这里
  { 
   
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );//类型转换
    while ( MSGpkt )
    { 
   
      switch ( MSGpkt->hdr.event )
      { 
   
        // Received when a key is pressed
        case KEY_CHANGE:  //如果是按键按下进入下面这个函数
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;

        // Received when a messages is received (OTA) for this endpoint
        case AF_INCOMING_MSG_CMD://如果是接受到RF消息进入这里
          SampleApp_MessageMSGCB( MSGpkt );
          break;

        // Received whenever the device changes state in the network
        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) )
          { 
   
            // Start sending the periodic message in a regular interval.
            osal_start_timerEx( SampleApp_TaskID,
                              SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
                              SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
          }
          else
          { 
   
            // Device is no longer in the network
          }
          break;

        default:
          break;
      }

      // Release the memory释放消息占用的内存
      osal_msg_deallocate( (uint8 *)MSGpkt );

      // Next - if one is available
    // 返回while ( MSGpkt )重新处理事件,直到缓冲区没有等待处理事件为止
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    }

    // return unprocessed events 返回未处理的事件
    return (events ^ SYS_EVENT_MSG);
  }

  // Send a message out - This event is generated by a timer
  // (setup in SampleApp_Init()).
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) //如果是 SAMPLEAPP_SEND_PERIODIC_MSG_EVT 事件进入这里 这里是网络状态改变之后标志位值1的
  { 
   
    // Send the periodic message
    SampleApp_SendPeriodicMessage();

    // Setup to send message again in normal period (+ a little jitter)
    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
        (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

    // return unprocessed events
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }

  // Discard unknown events
  return 0;
}

了解以上的流程我们就可以了解到协议栈的整体运行机制了。并且大概的概念。

下面我们介绍本节涉及zigbee协议栈的函数;

函数名osal_start_timerEx

函数声明uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )

这是一个定时器的函数,将在timeout_value毫秒之后将任务号为taskID的任务,事件号为event_id的事件标志位置为1.这个时候就可以通过evens&进行判断

有问题请发邮件至468078841@qq.com
zigbee协议栈串口收发 From zigbee菜鸟笔记(十 二)点击进入

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/140160.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 木马编程-手把手带你进入木马的世界之木马编程

    木马编程-手把手带你进入木马的世界之木马编程一、基础知识1.1、木马病毒木马(Trojan)这个名字来源于古希腊传说(荷马史诗中木马计的故事,Trojan一词的本意是特洛伊的,即代指特洛伊木马,也就是木马计的故事)。木马会想尽一切办法隐藏自己,主要途径有:在任务栏中隐藏自己,这是最基本的办法。只要把Form的Visible属性设为False,ShowInTaskBar设为False,程序运行时

  • 多重继承

    多重继承

  • 一个示例让你明白适配器模式

    一个示例让你明白适配器模式本文讨论适配器模式。适配器模式是23中设计模式之一,它的主要作用是在新接口和老接口之间进行适配。它非常像我们出国旅行时带的电源转换器。为了举这个例子,我还特意去京东上搜了一下电源转换器,确实看到了很多地方的标准不一样。我们国家的电器使用普通的扁平两项或三项插头,而去外国的话,使用的标准就不一样了,比如德国,使用的是德国标准,是两项圆头的插头。

  • c++入门教程–-8循环控制语句

    c++入门教程–-8循环控制语句

  • 可视化希尔排序算法是什么_希尔排序一趟排序的结果

    可视化希尔排序算法是什么_希尔排序一趟排序的结果如需转载请标明出处:https://blog.csdn.net/zhuzi9QQ技术交流群:594200841前言概念介绍希尔排序是基于插入排序算法的一种更高效的改进版本。它是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越少,当增量减少至1时,整个文件恰被分成一组。此时算法便终止。原理讲解以[41243421917]这个序列为例说明希尔排序算法的实现原理未开始遍历时,此时效果如下图由上面数组可知

  • Axure的动态面板制作tab切换效果

    Axure的动态面板制作tab切换效果最近进行机房合作画原型图的时候用到了Axure画图软件,画出来的图感觉棒棒哒!在画结账窗体的时候确实遇到了一些问题,因为有动态效果图,点击不同的Tab时要有不同的界面显示,所以学习了一下!

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号