在德州仪器的网站: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)操作系统抽象层
每个应用程序对象运行在不同的端口上,因此端口的作用就是区分不同的应用程序对象,可以把一个应用程序对象看成为一个任务,因此,需要一个机制来实现任务的切换、同步和互斥,这就是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 //端口
#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;//初始化端口
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化学工业出版社