1、实验内容:两个ZigBee节点进行点对点通信,ZigBee节点2(终端节点EndDevice,稍后,下载EndDeviceEB里的代码)发送“LED”三个字符,ZigBee节点1(协调器节点Coordinator,稍后,下载CoordinatorEB里的代码)接受数据后,判断接受到的数据是否为“LED”,是,则使板子上的LED灯闪烁。 2、简介
无线传感器主要有三种类型:协调器、路由器、终端节点。
协调器:负责网络的组件、维护、控制终端节点的加入
路由器:负责数据包的路由的选择
终端节点:负责数据的采集
(本实验不用路由器)
3、编程(主要使用的是C:\Texas Instruments\ZStack-CC2530-2.3.1-1.4.0\Projects\zstack\Samples\GenericApp\CC2530DB中的GenericApp.eww工程,并在此基础上,添加修改代码,在App文件夹移除掉GenericApp.c、添加Coordinator.h、Coordinator.c、Enddevice.c)
4、协调器编程(协调器工作流程:开始-》初始化-》建立网络(不用进行相关的编程)-》接收数据(没接收到数据时,一直等待接受数据)-》使得LED闪烁),此处的代码在GenericApp.c的基础上修改添加代码以实现数据的接受和LED闪烁。
//Coordinator.h
#ifndef COORDINATOR_H
#define COORDINATOR_H
#include "ZComDef.h" //??????????????
#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 evens);
#endif
//Coordinator.c
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include <string.h>
#include "Coordinator.h"
#include "DebugTrace.h"
#if !defined(WIN32) //????
#include "OnBoard.h"
#endif
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS]=
{
GENERICAPP_CLUSTERID
};
//简单设备描述符(描述一个ZigBee设备节点)
const SimpleDescriptionFormat_t GenericApp_SimpleDesc=
{
GENERICAPP_ENDPOINT,
GENERICAPP_PROFID,
GENERICAPP_DEVICEID,
GENERICAPP_DEVICE_VERSION,
GENERICAPP_FLAGS,
GENERICAPP_MAX_CLUSTERS,
(cId_t*)GenericApp_ClusterList, //?????
0,
(cId_t *)NULL
};
endPointDesc_t GenericApp_epDesc;//节点描述符
byte GenericApp_TaskID;//任务优先级
byte GenericApp_TransID;//数据发送序列号。
void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pckt);//消息处理函数
void GenericApp_SendTheMessage(void);//数据发送函数
void GenericApp_Init(byte task_id)//任务初始化函数
{
GenericApp_TaskID =task_id; //初始化任务优先级(任务优先级有协议栈的操作系统OSAL分配)
GenericApp_TransID =0; //发送数据包的序号初始化为0
//对节点描述符进行初始化
GenericApp_epDesc.endPoint =GENERICAPP_ENDPOINT;
GenericApp_epDesc.task_id =&GenericApp_TaskID;
GenericApp_epDesc.simpleDesc =(SimpleDescriptionFormat_t*)&GenericApp_SimpleDesc;
GenericApp_epDesc.latencyReq =noLatencyReqs;
afRegister(&GenericApp_epDesc);//afRegister()对节点的描述符进行注册。注册后,才能使用OSAL提供的系统服务。
}
//消息处理函数
UINT16 GenericApp_ProcessEvent(byte task_id,UINT16 events)
{
afIncomingMSGPacket_t* MSGpkt;//MSGpkt用于指向接收消息结构体的指针
if(events&SYS_EVENT_MSG)
{
// MSGpkt=(afIncomingMSGPacket_t*)osal_msg_reveive(GenericApp_TaskID);//osal_msg_receive()从消息队列上接收消息
MSGpkt=(afIncomingMSGPacket_t*)osal_msg_receive(GenericApp_TaskID);
while(MSGpkt)
{
switch(MSGpkt->hdr.event)
{
case AF_INCOMING_MSG_CMD: //接受到新数据的消息的ID是AF_INCOMING_MSG_CMD,这个宏是在协议栈中定义好的值为0x1A
//接受到的是无线数据包
GenericApp_MessageMSGCB(MSGpkt);//功能是完成对接受数据的处理
break;
default:
break;
}
osal_msg_deallocate((uint8 *)MSGpkt);//接收到的消息处理完后,释放消息所占的存储空间
// MSGpkt = (afIncomingMSGPacket_t *)osal_msg_reveive(GenericApp_TaskID);
MSGpkt=(afIncomingMSGPacket_t*)osal_msg_receive(GenericApp_TaskID);
//处理完一个消息后,再从消息队列里接受消息,然后对其进行相应处理,直到所有消息处理完
}
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);
if((buffer[0]=='L')&&(buffer[1]=='E')&&(buffer[2]=='D'))
{
HalLedBlink(HAL_LED_1,0,50,500); //LED2 闪烁
HalLedBlink(HAL_LED_2,0,50,500); //LED2 闪烁
HalLedBlink(HAL_LED_3,0,50,500); //LED2 闪烁
HalLedBlink(HAL_LED_4,0,50,500); //LED2 闪烁
}
else
{
HalLedSet(HAL_LED_2,HAL_LED_MODE_ON);//其他内容 LED2 亮 这几个函数在哪里定义了呢????
}
break;
}
}
5、终端节点编程(终端节点流程:开始-》初始化-》加入网络-》发送数据-》发送完数据后使LED闪烁)此处的代码在添加代码以实现数据的发送和LED闪烁。
//Enddevice.c
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include <string.h>
#include "Coordinator.h"
#include "DebugTrace.h"
#if !defined(WIN32)
#include "OnBoard.h"
#endif
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS]=
{
GENERICAPP_CLUSTERID
};
const SimpleDescriptionFormat_t GenericApp_SimpleDesc=
{
GENERICAPP_ENDPOINT,
GENERICAPP_PROFID,
GENERICAPP_DEVICEID,
GENERICAPP_DEVICE_VERSION,
GENERICAPP_FLAGS,
0,
(cId_t*)NULL,
GENERICAPP_MAX_CLUSTERS,
(cId_t*)GenericApp_ClusterList
};
endPointDesc_t GenericApp_epDesc;//节点描述符
byte GenericApp_TaskID; //任务优先级
byte GenericApp_TransID; //数据发送序列号
devStates_t GenericApp_NwkState;//保存节点状态
void GenericApp_MessageMSGCB(afIncomingMSGPacket_t* pckt);//消息处理函数的声明
void GenericApp_SendTheMessage(void); //数据发送函数的声明
//任务初始化函数
void GenericApp_Init(byte task_id)
{
GenericApp_TaskID = task_id;//初始化任务优先级
GenericApp_NwkState =DEV_INIT; //初始化为DEV_INIT,表节点没有连接到ZigBee网络
GenericApp_TransID =0; //发送数据包的序列号初始化为0
//对节点描述符进行初始化
GenericApp_epDesc.endPoint=GENERICAPP_ENDPOINT;
GenericApp_epDesc.task_id =&GenericApp_TaskID;
GenericApp_epDesc.simpleDesc=(SimpleDescriptionFormat_t*)&GenericApp_SimpleDesc;
GenericApp_epDesc.latencyReq=noLatencyReqs;
//afRegister()函数将节点描述符进行注册,注册后才可以使用OSAL提供的系统服务
afRegister(&GenericApp_epDesc);
}
//消息处理函数
UINT16 GenericApp_ProcessEvent(byte 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)
{
case ZDO_STATE_CHANGE:
GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);//读取节点的设备类型
if(GenericApp_NwkState==DEV_END_DEVICE)
{
GenericApp_SendTheMessage(); //终端节点类型,执行无线数据发送
}
break;
default:
break;
}
osal_msg_deallocate((uint8*)MSGpkt);
MSGpkt=(afIncomingMSGPacket_t*)osal_msg_receive(GenericApp_TaskID);
}
return (events^SYS_EVENT_MSG);
}
return 0;
}
void GenericApp_SendTheMessage(void)
{
unsigned char theMessageData[4]="LED";//存放发送数据
afAddrType_t my_DstAddr;
my_DstAddr.addrMode=(afAddrMode_t)Addr16Bit;//数据发送模式:可选 单播、广播、多播方式 这里选Addr16Bit表单播
my_DstAddr.endPoint=GENERICAPP_ENDPOINT; //初始化端口函
my_DstAddr.addr.shortAddr=0x0000; //标志目的地址节点的网络地址 这里是协调器的地址
//下面是数据发送 长度 数据发送缓冲区
AF_DataRequest(&my_DstAddr,&GenericApp_epDesc,GENERICAPP_CLUSTERID,3,theMessageData,
&GenericApp_TransID,AF_DISCV_ROUTE,AF_DEFAULT_RADIUS);
HalLedBlink(HAL_LED_1,0,50,500); //LED2 闪烁
HalLedBlink(HAL_LED_2,0,50,500); //LED2 闪烁
HalLedBlink(HAL_LED_3,0,50,500); //LED2 闪烁
HalLedBlink(HAL_LED_4,0,50,500); //LED2 闪烁
}
6、代码分析:(协调节点和终端节点交叉分析)
协调器工作流程:开始-》初始化-》建立网络(不用进行相关的编程)-》接收数据(没接收到数据时,一直等待接受数据)-》使得LED闪烁
终端节点流程:开始-》初始化-》加入网络-》发送数据-》发送完数据后使LED闪烁
可知,协调器工作流程:开始-》初始化-》建立网络
然后是终端节点流程:开始-》初始化-》加入网络
(1)初始化:完成各种硬件的初始设置,这里主要讲任务初始化:void GenericApp_Init(byte task_id),调用该函数的是由main()一直往下调用的,过程如下:
int main( void )
osal_init_system( void )
void osalInitTasks( void )
GenericApp_Init( taskID );
任务初始化:void GenericApp_Init(byte task_id)的主要功能:
- //任务初始化函数
- void GenericApp_Init(byte task_id)
- {
- GenericApp_TaskID = task_id;//初始化任务优先级
- GenericApp_NwkState =DEV_INIT; //初始化为DEV_INIT,表节点没有连接到ZigBee网络
- GenericApp_TransID =0; //发送数据包的序列号初始化为0
- //对节点描述符进行初始化
- GenericApp_epDesc.endPoint=GENERICAPP_ENDPOINT;
- GenericApp_epDesc.task_id =&GenericApp_TaskID;
- GenericApp_epDesc.simpleDesc=(SimpleDescriptionFormat_t*)&GenericApp_SimpleDesc;
- GenericApp_epDesc.latencyReq=noLatencyReqs;
- //afRegister()函数将节点描述符进行注册,注册后才可以使用OSAL提供的系统服务
- afRegister(&GenericApp_epDesc);
- }
其中上面的那个些变量都是本文件中的局部变量(定义如下,除了GenericApp_epDesc被afRegister(&GenericApp_epDesc); 直接应用后,其他的变量都在哪引用了呢?)
- endPointDesc_t GenericApp_epDesc;//节点描述符
- byte GenericApp_TaskID; //任务优先级
- byte GenericApp_TransID; //数据发送序列号
- devStates_t GenericApp_NwkState;//保存节点状态
(2)消息处理函数UINT16 GenericApp_ProcessEvent(byte task_id,UINT16 events) ,这个函数在协调器和终端节点都是有的。
先以终端节点的说:
int main( void )
{
// Initialize the operating system
osal_init_system();
...
osal_start_system(); // No Return from here
return 0; // Shouldn't get here.
} // main()
//OSAL_Tasks.h
typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );
//OSAL_GenericApp.c
// The order in this table must be identical to the task initialization calls below in osalInitTask.
const pTaskEventHandlerFn tasksArr[] = {
...
GenericApp_ProcessEvent
};
void osal_start_system( void )
{
for(;;) // Forever Loop
{
...
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);
events = (tasksArr[idx])( idx, events ); //调用了tasksEvents[idx]指向的函数
HAL_ENTER_CRITICAL_SECTION(intState);
tasksEvents[idx] |= events; // Add back unprocessed events to the current task.
HAL_EXIT_CRITICAL_SECTION(intState);
}
...
}
}
//Cooperation.h/Cooperation.c/Endevice.c
UINT16 GenericApp_ProcessEvent(byte task_id,UINT16 events)
在 UINT16 GenericApp_ProcessEvent(byte task_id,UINT16 events)中,
终端的代码是
- switch(MSGpkt->hdr.event)
- {
- case ZDO_STATE_CHANGE:
- GenericApp_NwkState=(devStates_t)(MSGpkt->hdr.status);//读取节点的设备类型
- if(GenericApp_NwkState==DEV_END_DEVICE)
- {
- GenericApp_SendTheMessage(); //终端节点类型,执行无线数据发送
- }
之后是发送数据(要注意发送数据之前要做的一系列事情,比如端口函、对方的的网址、广播、单播还是多播)
- void GenericApp_SendTheMessage(void)
- {
- unsigned char theMessageData[4]="LED";//存放发送数据
- afAddrType_t my_DstAddr;
- my_DstAddr.addrMode=(afAddrMode_t)Addr16Bit;//数据发送模式:可选 单播、广播、多播方式 这里选Addr16Bit表单播
- my_DstAddr.endPoint=GENERICAPP_ENDPOINT; //初始化端口函
- my_DstAddr.addr.shortAddr=0x0000; //标志目的地址节点的网络地址 这里是协调器的地址
- //下面是数据发送 长度 数据发送缓冲区
- AF_DataRequest(&my_DstAddr,&GenericApp_epDesc,GENERICAPP_CLUSTERID,3,theMessageData,&GenericApp_TransID,AF_DISCV_ROUTE,AF_DEFAULT_RADIUS);
- }
协调器的是
- switch(MSGpkt->hdr.event)
- {
- case AF_INCOMING_MSG_CMD: //接受到新数据的消息的ID是AF_INCOMING_MSG_CMD,这个宏是在协议栈中定义好的值为0x1A
- //接受到的是无线数据包
- GenericApp_MessageMSGCB(MSGpkt);//功能是完成对接受数据的处理
- break;
之后就是接受信息
- void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pkt)
- {
- unsigned char buffer[4]= " ";
- switch(pkt->clusterId)
- {
- case GENERICAPP_CLUSTERID:
- osal_memcpy(buffer,pkt->cmd.Data,3);