基于TI CC2530的 zigbee 开发(二)简单的无线传输组网实验
基于TI CC2530的 zigbee 开发(二)简单的无线传输组网例程
ZStack版本:ZStack-CC2530-2.5.1a
程序下载和调试软件:TI SmartRF Flash Programmer
下载和调试器:SmartRF04EB
IDE开发软件:IAR Embedded Workbench IDE - 8051 10.20.1
本例程的基本功能是实现两个zigbee节点的点对点通信功能。其中节点1作为协调器建立zigbee网络,节点2作为终端设备,加入网络,然后节点2发送“test”四个字符,如果节点1收到数据后,确认是“test”数据,则点亮开发板上的LED灯。
一、打开工程
进入ZStack-CC2530-2.5.1a\Projects\zstack\Samples\GenericApp\CC2530DB目录,双击GenericApp.eww,即可打开工程。
打开工程后,出现如下界面:
这是因为该工程是基于ZStack-CC2530-2.5.1a版本的,相较于IDE工具IAR来说版本太老,需要进行版本转换,我们只需选择"yes",IAR会自动帮我们进行转换。转换完成后,右击左上角的
选项,选择"Rebuild All” 进行编译,会发现有好多错误。
首先,我们仍然右击左上角的那个工程选项,选择“options”,出现如下界面,
将界面中圈出的数字“16”,更改成8。然后,下载新版的Z-Stack,我下载的是Z-Stack 3.0.2,将Z-Stack 3.0.2\Projects\zstack\ZMain\TI2530DB文件夹下的chipcon_cstartup.s51代替ZStack-CC2530-2.5.1a\Projects\zstack\ZMain\TI2530DB下的相同文件,重新编译,发现没有任何错误。
二、节点1协调器代码的开发
在左侧的项目导航栏选择APP下的GenericApp.c文件,右击,选择"Remove"。
如下图所示:
新建一个文件,保存为Coordinator.c,选择App行,右击选择Add,Add“Coordinator.c”,即可将该文件添加到App下。同理,新建Endevice.c文件,添加到App下。
选中新添加的Endevice.c文件,右击,选中“Options”,出现如下界面:
点击上图红色圈中的框,出现对勾后,然后点击下方"ok"按钮,则Endevice.c文件变成灰色。因为这个文件是终端设备的文件,而现在我们要编译的是协调器的程序,所以将该文件排除编译。
Coordinator.c的代码如下:
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include <string.h>
#include "DebugTrace.h"
#if !defined( WIN32 )
#include "OnBoard.h"
#endif
/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
#include "OSAL_Nv.h"
#include "GenericApp.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, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList, // byte *pAppInClusterList;
0, // byte AppNumInClusters;
(cId_t *)NULL // byte *pAppInClusterList;
};
endPointDesc_t GenericApp_epDesc;
byte GenericApp_TaskID; // Task ID for internal task/event processing
// This variable will be received when
// GenericApp_Init() is called.
byte GenericApp_TransID; // This is the unique message ID (counter)
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void GenericApp_Init( uint8 task_id )
{
GenericApp_TaskID = task_id;
GenericApp_TransID = 0;
// Device hardware initialization can be added here or in main() (Zmain.c).
// If the hardware is application specific - add it here.
// If the hardware is other parts of the device add it in main().
// 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 )
{
case AF_INCOMING_MSG_CMD:
GenericApp_MessageMSGCB( MSGpkt );
break;
default:
break;
}
// Release the memory
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
unsigned char buffer[4];
unsigned char LEDState = 0;
osal_memcpy(buffer,pkt->cmd.Data,4);
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
if((buffer[0] == 't') && (buffer[1] == 'e') && (buffer[2] == 's') && (buffer[3] == 't'))
{
LEDState++;
if(LEDState%2 == 0)
HalLedSet(HAL_LED_1,HAL_LED_MODE_ON);
else
HalLedSet(HAL_LED_1,HAL_LED_MODE_OFF);
}
break;
}
}
上述代码,大部分为从我们移除的GenericApp.c文件复制得到的,只是为了实现两个节点的无线通信,对代码进行了裁剪,以使代码看起来简单明了。
const SimpleDescriptionFormat_t GenericApp_SimpleDesc 数据结构是用来描述一个zigbee的设备节点。
代码中定义了三个全局变量,
1、endPointDesc_t GenericApp_epDesc; 节点描述符变量。
2、byte GenericApp_TaskID; 任务优先级变量。
3、byte GenericApp_TransID; 数据发送序号变量。
void GenericApp_Init( uint8 task_id ) 任务初始化函数;
uint16 GenericApp_ProcessEvent( uint8 task_id, uint16 events ) 事件处理函数;
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) 消息处理函数;
协调器的处理流程如下,首先初始化任务GenericApp_Init,然后循环处理是否有事件发生,如果有事件发生,则调用GenericApp_ProcessEvent事件处理函数,因为有可能发生的事件很多,但是本实现我们只关心是否有新的无线接收数据事件的发生,所以我们只判断AF_INCOMING_MSG_CMD该事件即可,如果是,则调用该事件的消息处理函数GenericApp_MessageMSGCB,本例中,我们是判断接收到的消息是“test”,如果是则将LED灯翻转一次。
二、节点2设备端代码的开发
点击Project菜单,选择Edit Configurations,出现如下界面:
选择EndDeviceEB,点击"OK"按钮。然后选择Coordinator.c文件,点右键,选择options,选择Exclude from build,点击下方"OK"按钮。则Coordinator.c文件变灰。
设备端软件的编译,同样需要将上图的数字16,变成8。
Endevice.c的代码如下:
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "DebugTrace.h"
#if !defined( WIN32 )
#include "OnBoard.h"
#endif
/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
#include "GenericApp.h"
#define SEND_DATA_EVENT 0x01
/*********************************************************************
* 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;
0, // byte AppNumInClusters;
(cId_t *)NULL, // byte *pAppInClusterList;
GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList // byte *pAppInClusterList;
};
endPointDesc_t GenericApp_epDesc;
byte GenericApp_TaskID; // Task ID for internal task/event processing
// This variable will be received when
// GenericApp_Init() is called.
devStates_t GenericApp_NwkState;
byte GenericApp_TransID; // This is the unique message ID (counter)
afAddrType_t GenericApp_DstAddr;
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
static void GenericApp_SendTheMessage( void );
void GenericApp_Init( uint8 task_id )
{
GenericApp_TaskID = task_id;
GenericApp_NwkState = DEV_INIT;
GenericApp_TransID = 0;
// Device hardware initialization can be added here or in main() (Zmain.c).
// If the hardware is application specific - add it here.
// If the hardware is other parts of the device add it in main().
// Fill out the endpoint description.
GenericApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
GenericApp_DstAddr.endPoint = GENERICAPP_ENDPOINT;
GenericApp_DstAddr.addr.shortAddr = 0xFFFF;
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 )
{
case ZDO_STATE_CHANGE:
GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ((GenericApp_NwkState == DEV_END_DEVICE))
{
// Start sending "the" message in a regular interval.
GenericApp_SendTheMessage();
}
break;
default:
break;
}
// Release the memory
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
static void GenericApp_SendTheMessage( void )
{
unsigned char theMessageData[4] = {'t','e','s','t'};
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
4,
theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
设备端的软件和协调器的代码差不多,大部分也是从GenericApp.c文件复制得到的。
不同之处有以下几处:
1、afAddrType_t GenericApp_DstAddr; 目标地址,用来描述目标地址的地址模式、地址、端点等参数。
2、ZDO_STATE_CHANGE 事件处理函数中,变为检测到设备状态为设备,则调用消息发送函数。
3、static void GenericApp_SendTheMessage( void ) 消息发送函数,将要发送的“test”消息发送出去。
三、让编译软件生成可烧写的hex文件
1、打开工程的"Options”选项。
2、点击"Linker"下的“Output”,如下图所示:
勾选红色圈中的选项。
3、点选“Extra Output”项,界面如下:
勾选前两个红色圈的方框,第二个圈为灰色,当勾选第一个框后,第二个框会变正常。然后将第三个红色圈中的字符更换成Enddevice.hex,最后将该界面下方的Output format:有“simple-code”,变成"inter-extended",最后点击"OK"按钮。
如上图,打开“f8w2530.xcl”,将红色209,210两行前面的注释去掉。
设置完成后,重新编译即可生成hex文件。
重点:需要将EndDeviceCB和CoordinatorEB两个工程都要如此设置,不同之处是,生成的hex文件名不同。
四、生成可在线调试的文件:
1、打开工程的"Options”选项。
2、点击"Linker"下的“Output”,如下图所示:
勾选红色框,即可生成用于在线调试的.d51文件。
五、程序烧写
1、点开SmartRF Flash Programmer界面如下:
上面红色圈选择要烧写的hex文件。
下面红色圈为状态提示,烧写完成后,会提示如上图所示。