• zigbee 学习笔记


    在德州仪器的站点:http://www.ti.com.cn/tool/cn/z-stack上下载安装zigbee2007协议栈版,我的是ZStack-CC2530-2.3.0-1.4.0。

    以下演示一个简单的用zigbee通信的样例:

    完毕这个样例须要两个zigbee的模块,一个用作协调器(Coordinator)(起建立zigbee网络和与上位机通信的作用)一个用作终端设备(Enddevice)(起採集数据。增加建立的zigbee网络),这里须要实现的功能是先由协调器建立网络,终端设备增加网络。然后终端设备发送“QSS”给协调器,协调器进行推断,假设接收到QSS,那么闪烁LED2,否则点亮LED2。

    删除在App目录中的几个文件,仅仅剩下OSAL_SampleApp.c。加入三个文件Coordinator.c,Coordinator.h,Enddevice.c。

    须要在OSAL_SampleApp.c中加入#include "Coordinator.h"。

    编译Coordinator时须要在workspace以下的下拉表中选择CoordinatorEB,然后右键单击Enddevice.c,在弹出的对话框中选择Exclude from build,将终端设备的程序排除在编译范围内,相同在编译Enddevice的程序时也须要将Coordinator.c排除在编译范围内。

    ZigBee网络传输数据流程:

    1、终端节点发送信标请求;

    2、协调器已经建立ZigBee无线网络。在ZigBee无线网络中。协调器的地址必然是0x0000,。

    3、终端节点发送增加网络请求;

    4、协调器对终端节点的增加网络请求作出应答

    5、终端节点接收到协调器的应答后,发送数据请求(Data Request)。请求协调器分配网络地址。

    6、协调器对终端节点的数据请求作出应答

    7、协调器将分配的网络地址发送给终端节点

    之后终端节点就使用分配的网络地址和协调器通信了。

    OSAL(Operating System Abstraction Layer)操作系统抽象层

    每一个应用程序对象执行在不同的port上。因此port的作用就是区分不同的应用程序对象。能够把一个应用程序对象看成为一个任务,因此,须要一个机制来实现任务的切换、同步和相互排斥。这就是OSAL产生的根源。

    它的主要功能有:

    任务注冊、初始化和启动;

    任务间的同步、相互排斥;

    中断处理。

    储存器分配和管理。

    在Coordinator.c中GenericApp_Init是任务的初始化函数。GenericApp_ProcessEvent负责处理传递给此任务的事件,推断事件类型,然后运行对应的事件处理函数。

    OSAL负责调度整个任务的执行,假设有事件发生了,则会调用对应的事件处理函数进行处理。

    那么事件和任务的事件处理函数是怎样联系起来的呢?

    ZigBee的做法是:建立一个事件表,保存各个任务相应的事件,建立还有一个函数表,保存各个任务事件处理函数的地址,然后将这两张表建立某种相应的关系,当某事发生时则查找函数表找到相应的事件处理函数就可以。

    Zigbee协议中三个变量最重要:

    Uint8 tasksCnt-保存任务的总数;

    Uint16 *tackEvents指向事件表的首地址。

    pTaskEventHandlerFn taskArr[]-数组中的每一项都是一个函数指针,指向事件处理函数;

    Typedef unsigned short (*pTaskEventHandlerFn )(unsigned char task_id,unsigned short event);

    总结一下OSAL的工作原理:

    通过tasksEvents指针訪问事件表的每一项,假设有事件发生。则查找函数表找到事件处理函数进行处理,处理完后。继续訪问事件表,查看是否有事件发生。无限循环。

    能够说OSAL是基于事件驱动的轮询式操作系统。

    OSAL的消息队列:

    将事件和数据封装成一个消息,将消息发送到消息队列,然后在事件处理函数中就能够使用osal_msg_receive,从消息队列中得到该消息。OSAL维护了一个消息队列。每一个消息都会被放到这个消息队列中去。当任务接收到事件后,能够从消息队列中获取属于自己的消息,然后调用消息处理函数进行对应的处理就可以。

    OSAL加入新任务:

    OSAL_SampleApp.c中,能够找到数组tasksArr[]和函数osalInitasks。tasksArr[]数组中存放了全部任务的事件处理函数的地址。osalInitasks是OSAL的任务初始化函数。全部任务的初始化工作都在这里完毕,而且自己主动给每一个任务分配一个ID。

    因此要加入一个新任务,仅仅须要编写两个函数:

    新任务的初始化函数。

    新任务的事件处理函数。

       

    Coordinator.h

    /*******************************

    这里定义一些关于zigbee的设备描叙符的宏

    **************************************/

    #ifndef COORDINATOR_H

    #define COORDINATOR_H

    #include "ZComDef.h"//zigbee common definition

    #define GENERICAPP_ENDPOINT         10  //port

    #define GENERICAPP_PROFID           0x0F04

    #define GENERICAPP_DEVICEID         0x0001

    #define GENERICAPP_DEVICE_VERSION   0

    #define GENERICAPP_FLAGS            0

    #define GENERICAPP_MAX_CLUSTERS     1

    #define GENERICAPP_CLUSTERID        1

    extern void GenericApp_Init(byte task_id);

    extern UINT16 GenericApp_ProcessEvent(byte task_id,UINT16 events);

    #endif

    /*********************************************************************/

    Coordinator.c

    /*********************************************************************

     * INCLUDES

     */

    #include "OSAL.h"

    #include "ZGlobals.h"

    #include "AF.h"

    #include "aps_groups.h"

    #include "ZDApp.h"

    #include "Coordinator.h"//这是新加的

    #include "OnBoard.h"

    /* HAL *///硬件抽象层

    #include "hal_lcd.h"

    #include "hal_led.h"

    #include "hal_key.h"

    #include "MT_UART.h"

    #include "MT_APP.h"

    #include "MT.h"

    /*********************************************************************

     * GLOBAL VARIABLES

     */

    // This list should be filled with Application specific Cluster IDs.

    const cId_t GENERICAPP_ClusterList[GENERICAPP_MAX_CLUSTERS] =

    {

      GENERICAPP_CLUSTERID

    };

    const SimpleDescriptionFormat_t GenericApp_SimpleDesc =

    {

      GENERICAPP_ENDPOINT,              //  int Endpoint;

      GENERICAPP_PROFID,                //  uint16 AppProfId[2];

      GENERICAPP_DEVICEID,              //  uint16 AppDeviceId[2];

      GENERICAPP_DEVICE_VERSION,        //  int   AppDevVer:4;

      GENERICAPP_FLAGS,                 //  int   AppFlags:4;

      GENERICAPP_MAX_CLUSTERS,          //  uint8  AppNumInClusters;

      (cId_t *)GENERICAPP_ClusterList,  //  uint8 *pAppInClusterList;

      0,                                //  uint8  AppNumInClusters;

      (cId_t *)NULL                    //  uint8 *pAppInClusterList;

    };//简单的设备节点描叙符

    endPointDesc_t GenericApp_epDesc;//定义一个节点描叙符

    byte GenericApp_TaskID; //任务优先级

    byte GenericApp_TransID; //数据发送序列号

    typedef struct

    {

      byte endPoint;

      byte *task_id;

      SimpleDescriptionFormat_t *simpleDesc;

      afNetworkLatencyReq_t latenncyReq;

    }ndPointDesc_t;

    void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );//消息处理函数

    void GenericApp_SendTheMessage( void );//数据发送函数

    static void rxCB(uint8 port,uint8 event);

    //任务初始化函数

    void GenericApp_Init(byte task_id )

    {

      halUARTCfg_t uartConfig;

      

      GenericApp_TaskID = task_id;//初始化优先级

      GenericApp_TransID = 0;//初始化序列号

      

      // Fill out the endpoint description.//初始化设备节点描叙符

      GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;

      GenericApp_epDesc.task_id = &GenericApp_TaskID;

      GenericApp_epDesc.simpleDesc  = 

                        (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;        

      GenericApp_epDesc.latencyReq = noLatencyReqs;

      // Register the endpoint description with the AF

      //注冊设备节点描叙符,仅仅有注冊之后才干够使用OSAL的服务

      afRegister( &GenericApp_epDesc );

      

    }

    //消息处理函数,完毕对接收数据的处理,固定格式

    UINT16 GenericApp_ProcessEvent( uint8 task_id, uint16 events )

    {

      afIncomingMSGPacket_t *MSGpkt;//定义一个接收消息结构体的指针MSGpkt

      

      if ( events & SYS_EVENT_MSG )

      {

        MSGpkt=(afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );

        while ( MSGpkt )

        {

          switch ( MSGpkt->hdr.event )//对消息进行推断

          {

            // Received when a messages is received (OTA) for this endpoint

            case AF_INCOMING_MSG_CMD://无线数据

              GenericApp_MessageMSGCB( MSGpkt );//对数据进行处理

              break;

              

            default:

              break;

          }

          // Release the memory释放内存

          osal_msg_deallocate( (uint8 *)MSGpkt );

          // Next - if one is available再次从消息队列中接收消息

        MSGpkt=(afIncomingMSGPacket_t*)osal_msg_receive( GenericApp_TaskID );

        }

        // return unprocessed events

        return (events ^ SYS_EVENT_MSG);

      }

      

      return 0;

    }

    //数据处理函数

    void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )

    {

      unsigned char buffer[4] = " ";

      switch ( pkt->clusterId )   

      {

        case GENERICAPP_CLUSTERID:

            osal_memcpy(buffer,pkt->cmd.Data,3);//将接收到的数据复制到buffer区

            if((buffer[0] == 'Q') || (buffer[1] == 'S') || (buffer[2] == 'S'))

            {

              

        HalLedBlink(HAL_LED_2,0,50,500);//闪灯

            }

            else

            {

               HalLedSet(HAL_LED_2,HAL_LED_MODE_ON);//点灯

            }

          break;

         

      }

    }

    Enddevice.c

    /*********************************************************************

     * INCLUDES

     */

    #include "OSAL.h"

    #include "ZGlobals.h"

    #include "AF.h"

    #include "aps_groups.h"

    #include "ZDApp.h"

    #include "Coordinator.h"//新增协调器头文件

    #include "OnBoard.h"

    /* HAL *///硬件抽象层

    #include "hal_lcd.h"

    #include "hal_led.h"

    #include "hal_key.h"

    #include "MT_UART.h"

    #include "MT_APP.h"

    #include "MT.h"

    // This list should be filled with Application specific Cluster IDs.

    const cId_t GENERICAPP_ClusterList[GENERICAPP_MAX_CLUSTERS] =

    {

      GENERICAPP_CLUSTERID

    };

    const SimpleDescriptionFormat_t GenericApp_SimpleDesc =

    {

      GENERICAPP_ENDPOINT,              //  int Endpoint;

      GENERICAPP_PROFID,                //  uint16 AppProfId[2];

      GENERICAPP_DEVICEID,              //  uint16 AppDeviceId[2];

      GENERICAPP_DEVICE_VERSION,        //  int   AppDevVer:4;

      GENERICAPP_FLAGS,                 //  int   AppFlags:4;

      0,

      (cId_t *)NULL,                   //  uint8 *pAppInClusterList;

      GENERICAPP_MAX_CLUSTERS,          //  uint8  AppNumInClusters;

      (cId_t *)GENERICAPP_ClusterList  //  uint8 *pAppInClusterList;

      

    };//简单的设备节点描叙符

    endPointDesc_t GenericApp_epDesc;//节点描叙符

    byte GenericApp_TaskID; //任务优先级

    byte GenericApp_TransID; //数据发送序列号。在协议栈中每发送一个数据包。

    //该发送序列号加1,能够用来在数据接收端查看数据包的序列号来计算丢包率

    devStates_t GenericApp_NwkState;//记录该设备的状态

    void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );//消息处理函数

    void GenericApp_SendTheMessage( void );//数据发送函数

    void GenericApp_Init(byte task_id )//任务初始化函数

    {

      GenericApp_TaskID    = task_id;//初始化了任务优先级(任务优先级由协议栈的操作系统OSAL分配)

      GenericApp_NwkState  = DEV_INIT;//将设备状态初始化为DEV_INT,表示该节点没有连接到ZigBee网络

      GenericApp_TransID   = 0;//将发送数据包的序列号初始化为0,

      

      // Fill out the endpoint description.对节点描叙符进行的初始化

      GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;

      GenericApp_epDesc.task_id = &GenericApp_TaskID;

      GenericApp_epDesc.simpleDesc  = 

                        (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;        

      GenericApp_epDesc.latencyReq = noLatencyReqs;

      // Register the endpoint description with the AF,注冊节点描叙符

      afRegister( &GenericApp_epDesc );

    }

    //消息处理函数,完毕接收数据的处理

    uint16 GenericApp_ProcessEvent( uint8 task_id, uint16 events )

    {

      afIncomingMSGPacket_t *MSGpkt;//定义一个指向消息结构的指针

      

      if ( events & SYS_EVENT_MSG )

      {

        MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );

        while ( MSGpkt )

        {

          switch ( MSGpkt->hdr.event )//推断消息类型

          {

            // Received when a messages is received (OTA) for this endpoint

            case ZDO_STATE_CHANGE:

              GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);//读取设备节点类型

              if(GenericApp_NwkState == DEV_END_DEVICE)

              {

                GenericApp_SendTheMessage();//发送无线数据

              }

              break;

              

            default:

              break;

          }

          // Release the memory

          osal_msg_deallocate( (uint8 *)MSGpkt );

          // Next - if one is available

          MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );

        }

        // return unprocessed events

        return (events ^ SYS_EVENT_MSG);

      }

      

      return 0;

    }

    //发送消息函数

    void GenericApp_SendTheMessage(void )

    {

      unsigned char theMessageData[4] = "QSS";

      afAddrType_t my_DstAddr;//目标地址

      my_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;//将发送数据模式设置为单播

      my_DstAddr.endPoint = GENERICAPP_ENDPOINT;//初始化port

      my_DstAddr.addr.shortAddr = 0x00;//协调器的网络地址是固定的,为0x00

      AF_DataRequest(&my_DstAddr,&GenericApp_epDesc,//调用AF_DataRequest函数发送数据

                        GENERICAPP_CLUSTERID,

                        3,

                        theMessageData,

                        &GenericApp_TransID,

                        AF_DISCV_ROUTE,

                        AF_DEFAULT_RADIUS);

      HalLedBlink(HAL_LED_2,0,50,500);//闪灯

      

    }

    參考书目:

    王小强 欧阳骏 黄宁淋编著《Zigbee无线传感器网络设计与实现》2012化学工业出版社

  • 相关阅读:
    TRUNCATE TABLE 删除表中的所有行,而不记录单个行删除操作
    血腥!实况转播SQL注入全过程,让你知道危害有多大。
    DB2隔离级别设置
    使用解释工具分析SQL语句
    DB2的七种武器
    db2精华文档和论坛链接
    “饮水机”:形象比喻 深入浅出理解RAID
    DB2 数据库恢复测试
    IBM DB2 日常维护汇总
    镜像分割与高可用性灾难恢复
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6755592.html
Copyright © 2020-2023  润新知