打印

【分享】Zigbee无线技术

[复制链接]
1021|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一抹隐兮|  楼主 | 2017-12-9 11:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
透传的基本概念:
002
透传就是透明传输的简称。那么什么是透明传输呢?顾名思义,透明传输就是指在传输过程中,对外界完全透明,不需要关系传输过程以及传输协议,最终目的是要把传输的内容原封不动的传递给被接收端,发送和接收的内容完全一致。这就相当于把信息直接扔给你想要传输的人,只需要扔(也就是传输)这一个步骤,不需要其他的内容安排。
003
串口无线透传编程流程:
004
程序需要实现的功能:
005
1、 ZigBee 模块接收到从 PC 机发来的消息,然后无线发送出去
006
2、 ZigBee 模块接收到其他 ZigBee 模块发来的消息,然后发送给 PC 机
007
发送和接收数据的流程:
008
发送数据:
009
填充并注册端点描述符 配置发送模式及目的地址AF_DataRe quest()发送数据
010
接收数据:
011
填充并注册端点描述符处理系统事件 SYS_EVENT_MSG 中的AF_INCOMING _MSG_CMD 消息获得消息包中的无线数据
012

013
相关的API函数或结构体的介绍:
014
串口无线透传我们需要掌握以下重点:
015
   端点描述符
016
   简单描述符
017
   如何发送数据
018
   如何接收数据
019
我们重点分析四个函数:
020
   任务的初始化函数
021
   任务的事件处理函数
022
   无线消息接收回调函数
023
   无线消息发送函数
024
端口描述符的定义:
025
端点(Endpoint)是协议栈应用层入口,它通常为节点的一个通信部件或设备(如各种类型的传感器、开关、 LED 灯等)也是用户定义的应用对象驻留的地方。端点类似于在计算机 TCP/IP 网络通信中,为方便计算机中不同的进程进行通信,在传输层设置的端口(Port)概念。端点和 IEEE64 位扩展地址、16 位网络短地址一样,是 ZigBee 无线通信的一个重要地址参数,能够为多个应用对象提供逻辑子通道以进行通信。每个 ZigBee 设备支持多达 240 个端点,也就是说,每个设备最多可以定义 240 个应用对象。端点 0 必须在ZigBee 设备中具有,它分配给 ZigBee 设备对象(ZD0)使用,端点 255 是端点广播地址,端点 241~254 保留,为以后扩展使用。端点描述符用来描述一个端点,Z-Stack 中的 AF.h 中有关于端点描述符的定义如下:
026
typedef struct
027
{
028
  uint8 endPoint;     //端口号
029
  uint8 *task_id;     // 指向任务ID号  Pointer to location of the Application task ID.
030
  // 简单设备描述符  可以通过go to…的方式查看结构体变量的类型
031
  SimpleDescriptionFormat_t *simpleDesc;
032
  afNetworkLatencyReq_t latencyReq;   // 延时,采用默认值初始化即可
033
} endPointDesc_t;
034

035
端点描述符的初始化:
036
端点描述符需要在应用层 SampleApp.c 文件中的 SampleApp_Init()函数中进行端点填充,并向 AF 层注册端点描述符。第一次对话实验中填充端点描述符的过程如下,该部分代码比较固定。
037
void SampleApp_Init( uint8 task_id )
038
{
039
  // Fill out the endpoint description.
040
  // 以下四行是对节点描述符进行初始化
041
  // 我们需要手动指定端口号,程序中 SAMPLEAPP_ENDPOINT 的宏值为20,
042
// 可以使用的端口号范围:1~240,用户可根据需要进行修改。
043
  SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
044
  //指定任务 ID,这里我们指向的是当前任务的 ID。
045
  SampleApp_epDesc.task_id = &SampleApp_TaskID;
046
// 指向简单描述符。我们下边会分析简单描述符的定义。
047
  SampleApp_epDesc.simpleDesc
048
            = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
049
// 采用默认值 noLatencyReqs 即可
050
  SampleApp_epDesc.latencyReq = noLatencyReqs;
051

052
  // Register the endpoint description with the AF
053
  // 用 afRegister()函数向 AF 层注册端点描述符。
054
  afRegister( &SampleApp_epDesc );
055
}
056

057
简单设备描述符的定义:
058
typedef struct
059
{
060
  uint8          EndPoint;                // 端口号
061
  uint16         AppProfId;               // 应用规范ID
062
  uint16         AppDeviceId;             // 应用设备ID
063
  uint8          AppDevVer:4;             // 应用版本设备号
064
  uint8          Reserved:4;              // 保留  AF_V1_SUPPORT uses for AppFlags:4.
065
  uint8          AppNumInClusters;        // 输入簇的个数
066
  cId_t         *pAppInClusterList;       // 输入簇的列表
067
  uint8          AppNumOutClusters;       // 输出簇的个数
068
  cId_t         *pAppOutClusterList;      // 输出簇的列表
069
} SimpleDescriptionFormat_t;
070

071
简单设备描述符的初始化:
072
宏定义在SampleApp.h文件中
073
#define SAMPLEAPP_ENDPOINT           20   // 端口号20
074

075
#define SAMPLEAPP_PROFID             0x0F08
076
#define SAMPLEAPP_DEVICEID           0x0001
077
#define SAMPLEAPP_DEVICE_VERSION     0
078
#define SAMPLEAPP_FLAGS              0
079

080
#define SAMPLEAPP_MAX_CLUSTERS       2
081
#define SAMPLEAPP_PERIODIC_CLUSTERID 1
082
#define SAMPLEAPP_FLASH_CLUSTERID     2
083
初始化在SampleApp.c文件中
084
const cId_t SampleApp_ClusterList[SAMPLEAPP_MAX_CLUSTERS] =
085
{
086
  SAMPLEAPP_PERIODIC_CLUSTERID,
087
  SAMPLEAPP_FLASH_CLUSTERID
088
};
089

090
const SimpleDescriptionFormat_t SampleApp_SimpleDesc =
091
{
092
  SAMPLEAPP_ENDPOINT,              //  int Endpoint;  端口号
093
  SAMPLEAPP_PROFID,                //  uint16 AppProfId[2];  应用规范ID
094
  SAMPLEAPP_DEVICEID,              //  uint16 AppDeviceId[2];  应用设备ID
095
  SAMPLEAPP_DEVICE_VERSION,        //  int   AppDevVer:4;    应用设备版本号
096
  SAMPLEAPP_FLAGS,                 //  int   AppFlags:4;     保留
097
  SAMPLEAPP_MAX_CLUSTERS,          //  uint8  AppNumInClusters;  输入簇命令个数
098
  (cId_t *)SampleApp_ClusterList,  //  uint8 *pAppInClusterList; 输入簇列表
099
  SAMPLEAPP_MAX_CLUSTERS,          //  uint8  AppNumInClusters;  输出簇命令个数
100
  (cId_t *)SampleApp_ClusterList   //  uint8 *pAppOutClusterList;输出簇列表
101
};
102

103
发送数据函数详解:
104
【1】 afStatus_t AF_DataRequest(
105
afAddrType_t *dstAddr, //包含目的节点的网络地址以及发送数据的格式,如广播、组播或单播。
106
endPointDesc_t *srcEP,//某一个节点上不同的端口 (endpoint) ,我们可以理解为 TCP/IP 中的端口。
107
uint16cID,//该参数主要是为了区分不同的命令,对应简单描述符中的输出群集
108
uint16 len,//该参数标识了发送数据的长度。
109
uint8 *buf,//该参数是指向发送缓冲区的指针。
110
uint8 *transID,//该参数是指向发送序号的指针。可以用来检测丢包率,由OSAL维护。
111
uint8 options,//取默认值 AF_DISCV_ROUTE 即可。
112
uint8 radius//取默认值 AF_DEFAULT_RADIUS 即可。
113
    )
114
                           
115
【2】对于发送数据函数AF_DataRequest函数的具体实现,
116
        只需要理解zigbee协议栈是通过发送函数实现广播、组播、单播的即可。
117
         
118
【3】这里重点关注AF_DataRequest函数的第一个参数,可以通过go to……的方式跳转到第一个参数的变量类型:
119
    第一个参数是一个结构体:如下
120
    typedef struct
121
    {
122
        union
123
        {
124
            uint16      shortAddr;   //代表节点的网络地址
125
            ZLongAddr_t extAddr;
126
        } addr;
127
        afAddrMode_t addrMode;   //重点关注这个变量,他代表我的发送形式
128
        uint8 endPoint;
129
        uint16 panId;  // used for the INTER_PAN feature
130
    } afAddrType_t;
131
     
132
    afAddrMode_t变量是一个枚举类型:
133
    typedef enum
134
    {
135
        afAddrNotPresent = AddrNotPresent,
136
        afAddr16Bit      = Addr16Bit,     //代表单播
137
        afAddr64Bit      = Addr64Bit,   
138
        afAddrGroup      = AddrGroup,     //代表组播
139
        afAddrBroadcast  = AddrBroadcast  //代表广播
140
    } afAddrMode_t;
141

142
    上述使用到的Addr16Bit,AddrGroup,,AddrBroadcast是一个常数,在zigbee协议栈中具有定义:如下
143
    enum
144
    {
145
        AddrNotPresent = 0,
146
        AddrGroup = 1,
147
        Addr16Bit = 2,
148
        Addr64Bit = 3,
149
        AddrBroadcast = 15
150
    };
151
接收数据函数详解:
152
当设备接收到无线数据后,操作系统会将该数据封装成一个消息然后放入消息队列中,同时设置系统事件SYS_EVENT_MSG ,应用层的事件处理函数 SampleApp_ProcessEvent 会处理这个事件,他首先会将消息从消息队列中取出,根据消息的 ID 判断该消息是否就是接收到的数据,标识接收到新数据的消息 ID 是 AF_INCOMING_MSG_CMD,其中 AF_ INCOMING_MSG_CMD 的值是 0x1a,这是在 ZigBee 协议栈中定义好的,用户不可更改。
153
获取更多学习资料+源码+笔记请加QQ3522655328
154
具体的事件处理函数代码如下所示,这部分代码比较固定,我们只需要熟悉这种事件处理结构即可。
155
// 事件处理函数
156
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
157
{
158
  afIncomingMSGPacket_t *MSGpkt;
159
  (void)task_id;  // Intentionally unreferenced parameter
160

161
  if ( events & SYS_EVENT_MSG )
162
  {
163
    // 获取消息
164
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
165
    while ( MSGpkt )
166
    {
167
      switch ( MSGpkt->hdr.event )
168
      {
169
        // Received when a messages is received (OTA) for this endpoint
170
        case AF_INCOMING_MSG_CMD://接收数据事件,调用函数AF_DataRequest()接收数据
171
          SampleApp_MessageMSGCB( MSGpkt );//调用回调函数对收到的数据进行处理
172
          break;
173
        default:
174
          break;
175
      }
176
      // Release the memory   事件处理完了,释放消息占用的内存
177
      osal_msg_deallocate( (uint8 *)MSGpkt );
178
      // Next - if one is available 指针指向下一个放在缓冲区的待处理的事件,
179
      //返回while ( MSGpkt )重新处理事件,直到缓冲区没有等待处理事件为止
180
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
181
    }
182
    // return unprocessed events   返回未处理的事件
183
    return (events ^ SYS_EVENT_MSG);
184
  }
185
  // Discard unknown events
186
  return 0;
187
}
188

189
SampleApp_MessageMSGCB( MSGpkt );函数使用说明:
190
// 接收到消息,消息处理回调函数
191
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
192
{
193
  uint16 flashTime;
194

195
  switch ( pkt->clusterId )
196
  {
197
case SAMPLEAPP_PERIODIC_CLUSTERID:
198
    HalUARTWrite (0, (pkt->cmd).Data, ((pkt->cmd).DataLength));
199
      break;
200

201
    case SAMPLEAPP_FLASH_CLUSTERID:
202
      flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );
203
      HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
204
      break;
205
  }
206
}
207
思考两个问题:
208
为什么要根据SAMPLEAPP_ PERIODIC_CLUSTERID 才能得到正确的数据呢?
209
在 ZigBee 网络中进行通信时需要注意的,两者如果想进行通信,需要具有相同的 Cluster ID,而且一个选择“输入” ,另一个选择“输出”(在简单描述符中填充) 。
210
收到的数据在哪里?
211
在 pkt 指向的那个结构体里,我们去看下 afIncomingMSGPacket_t 的真面目了。
212
接收数据的存放位置:
213
typedef struct
214
{
215
  osal_event_hdr_t hdr;     /* OSAL Message header */
216
  uint16 groupId;           /* Message's group ID - 0 if not set */
217
  uint16 clusterId;         /* Message's cluster ID */
218
  afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
219
                               it's an InterPAN message */
220
  uint16 macDestAddr;       /* MAC header destination short address */
221
  uint8 endPoint;           /* destination endpoint */
222
  uint8 wasBroadcast;       /* TRUE if network destination was a broadcast address */
223
  uint8 LinkQuality;        /* The link quality of the received data frame */
224
  uint8 correlation;        /* The raw correlation value of the received data frame */
225
  int8  rssi;               /* The received RF power in units dBm */
226
  uint8 SecurityUse;        /* deprecated */
227
  uint32 timestamp;         /* receipt timestamp from MAC */
228
  uint8 nwkSeqNum;          /* network header frame sequence number */
229
  afMSGCommandFormat_t cmd; /* Application Data */
230
} afIncomingMSGPacket_t;
231

232
afMSGCommandFormat_t结构体的声明:
233
typedef struct
234
{
235
  uint8   TransSeqNumber;   //用于存储发送序列号;
236
  uint16  DataLength;              //用于存储接收到的数据长度;
237
  uint8  *Data;            //数据接收后放在一个缓冲区,该参数就是指向缓冲区的指针;
238
} afMSGCommandFormat_t;

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

17

帖子

0

粉丝