ZigBee无线组网远程数据采集系统
1、实验内容:协调器建立Zigbee网络,路由器和终端节点加入网络,然后周期性地采集温度和电压发送给协调器,协调器通过串口发送给PC的串口调试助手
2、补充:(为了便于数据的传输和管理,传输的数据用一个结构体表示)如下
[cpp] view plain copy
//NewCoordinator.h
[cpp] view plain copy
typedef union h
{
unsigned char databuf[18];
struct RFRXBUF
{
unsigned char head[2]; // "&&"
unsigned char type[3]; // "ROU"或 "END"
unsigned char myNWK[4]; // 自身的网络地址
unsigned char pNWK[4]; // 父节点的网络地址
unsigned char value[4]; // value[0]表采集数据的类型 如:W表温度 V表电压 后面几位表数值
unsigned char tail; //"&"
}BUF;
}RFTX;
[cpp] view plain copy
上面是个联合结构体,便于数据的强制类型转换。
3、程序设计
协调器程序设计(负责接收来自路由或终端节点发送来的数据,并通过串口发送到PC的串口助手进行显示)
[cpp] view plain copy
/***************************
* INCLUDES
*/
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "NewCoordinator.h"
//#include "GenericApp.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 "aps_groups.h"
#define SEND_TO_ALL_EVENT 0x01
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* 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;
// GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
// (cId_t *)GenericApp_ClusterList // byte *pAppInClusterList;
0,
(cId_t *)NULL
};
// This is the Endpoint/Interface description. It is defined here, but
// filled-in in GenericApp_Init(). Another way to go would be to fill
// in the structure here and make it a "const" (in code space). The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t GenericApp_epDesc;
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
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;
/*********************************************************************
* LOCAL FUNCTIONS
*/
//void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
//void GenericApp_HandleKeys( byte shift, byte keys );
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );//处理事件
void GenericApp_SendTheMessage( void );//发送数据
static void rxCB(uint8 port,uint8 envent);
/*********************************************************************
* NETWORK LAYER CALLBACKS
*/
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn GenericApp_Init
*
* @brief Initialization function for the Generic App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should be
* used to send messages and set timers.
*
* @Return none
*/
void GenericApp_Init( byte task_id )
{
GenericApp_TaskID = task_id;
// GenericApp_NwkState = DEV_INIT; //这句不注释掉 会怎样???
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
afRegister( &GenericApp_epDesc );
//串口的设置,并打开串口
halUARTCfg_t uartConfig;
uartConfig.configured =TRUE;
uartConfig.baudRate =HAL_UART_BR_115200;
uartConfig.flowControl=FALSE;
uartConfig.callBackFunc=NULL;//???????????????????????????????????
//uartConfig.callBackFunc=rxCB;
HalUARTOpen(0,&uartConfig); //打开串口
}
/*********************************************************************
* @fn GenericApp_ProcessEvent
*
* @brief Generic Application Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The OSAL assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return none
*/
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
// HalLedBlink(HAL_LED_1,0,50,500);
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case AF_INCOMING_MSG_CMD: //天线接收到数据
// HalLedBlink(HAL_LED_2,0,50,500);
GenericApp_MessageMSGCB( MSGpkt ); //接收数据并把数据发送到UART
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;
}
/*********************************************************************
* LOCAL FUNCTIONS
*/
/*********************************************************************
* @fn GenericApp_MessageMSGCB
*
* @brief Data message processor callback. This function processes
* any incoming data - probably from other devices. So, based
* on cluster ID, perform the intended action.
*
* @param none
*
* @return none
*/
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
RFTX rftx;
unsigned char changeline[2]={0x0A,0x0D};
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memcpy(&rftx,pkt->cmd.Data,sizeof(rftx));
HalUARTWrite(0,rftx.databuf,sizeof(rftx)); //从这一行你就能看到联合体的作用、好处
HalUARTWrite(0,changeline,2);
break;
}
}
路由器节点或终端节点(共用的Sonsor.h、Sonsor.c、NewEnddevice.c文件)
[cpp] view plain copy
//Sensor.h
#ifndef SENSOR_H
#define SENSOR_H
#include
extern int8 readTemp(void);
extern unsigned int getVddvalue(void);
#endif
Sensor.c主要用于传感器采集的实现
[cpp] view plain copy
#include "Sensor.h"
#include
//你知道下面宏的具体含义是什么吗???
#define ADC_REF_115V 0x00
#define ADC_DEC_256 0x20
#define ADC_CHN_TEMP 0x0e
#define ADC_DEC_064 0x00
#define ADC_CHN_VDD3 0x0f
int8 readTemp(void)
{
static uint16 reference_voltage;
static uint8 bCalibrate=TRUE;
unsigned char tmpADCCON3=ADCCON3;//????????
uint16 value;
int8 temp;
ATEST=0x01; //使能温度传感器
TR0|=0x01; //连接温度传感器
ADCIF=0; //?????
ADCCON3=(ADC_REF_115V|ADC_DEC_256|ADC_CHN_TEMP);//???????
while(!ADCIF)//???????
;
ADCIF=0;
value=ADCL; //这里应该是取低位
value |=((uint16)ADCH)<<8; //这里应该是取高位
value>>=4;//除以16???
if(bCalibrate)//记录第一次读取的温度值,用于校正温度数据
{
reference_voltage=value;
bCalibrate=FALSE;
}
temp=22+((value-reference_voltage)/4);//温度校正函数
return temp;
}
unsigned int getVddvalue(void)
{
unsigned int value;
unsigned char tmpADCCON3=ADCCON3;
ADCIF=0;
ADCCON3=(ADC_REF_115V|ADC_DEC_064|ADC_CHN_VDD3);
while(!ADCIF)
;
value=ADCH;
ADCCON3=tmpADCCON3;
return (value);
}
NewEndDevice.c
[cpp] view plain copy
/*********************************************************************
* INCLUDES
*/
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "NewCoordinator.h"
//#include "GenericApp.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"
#define SEND_DATA_EVENT 0x01
#include "Sensor.h"
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* 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,
(cId_t*)0,
//GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
// (cId_t *)GenericApp_ClusterList, // byte *pAppInClusterList;
GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList // byte *pAppInClusterList;
};
// This is the Endpoint/Interface description. It is defined here, but
// filled-in in GenericApp_Init(). Another way to go would be to fill
// in the structure here and make it a "const" (in code space). The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t GenericApp_epDesc;
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
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; //???????????????
/*********************************************************************
* LOCAL FUNCTIONS
*/
//void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
//void GenericApp_HandleKeys( byte shift, byte keys );
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void GenericApp_SendTheMessage( void );
void SendInfo(void);
void sendVdd(void);
void sendTemp(void);
void To_string(uint8 *dest,char* src,uint8 length);//二进制书转化为十六进制数
//static void rxCB(uint8 port,uint8 envent);
/*********************************************************************
* NETWORK LAYER CALLBACKS
*/
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn GenericApp_Init
*
* @brief Initialization function for the Generic App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should be
* used to send messages and set timers.
*
* @return none
*/
void GenericApp_Init( byte task_id )
{
GenericApp_TaskID = task_id;
GenericApp_NwkState = DEV_INIT;
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
afRegister( &GenericApp_epDesc );
}
/*********************************************************************
* @fn GenericApp_ProcessEvent
*
* @brief Generic Application Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The OSAL assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return none
*/
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_ROUTER)
|| (GenericApp_NwkState == DEV_END_DEVICE) )
{
osal_set_event(GenericApp_TaskID,SEND_DATA_EVENT);
}
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);
}
if ( events & SEND_DATA_EVENT )
{
sendTemp();
sendVdd();
osal_start_timerEx( GenericApp_TaskID,
SEND_DATA_EVENT, //事件
GENERICAPP_SEND_MSG_TIMEOUT );//定时时间
return (events ^ SEND_DATA_EVENT);
}
// Discard unknown events
return 0;
}
void sendTemp(void)
{
RFTX rftx;
uint16 nwk;
osal_memcpy(rftx.BUF.head,"&&",2);
if(GenericApp_NwkState==DEV_ROUTER)
osal_memcpy(rftx.BUF.type,"ROU",3);
if(GenericApp_NwkState==DEV_END_DEVICE)
osal_memcpy(rftx.BUF.type,"END",3);
nwk=NLME_GetShortAddr();
To_string(rftx.BUF.myNWK,(uint8*)&nwk,2);
nwk=NLME_GetCoordShortAddr();
To_string(rftx.BUF.pNWK,(uint8*)&nwk,2);
uint16 tempvalue;
tempvalue=readTemp();
rftx.BUF.value[0]='W';
rftx.BUF.value[1]=tempvalue/10+'0';
rftx.BUF.value[2]=tempvalue%10+'0';
rftx.BUF.value[3]='*';
rftx.BUF.tail='&';
afAddrType_t my_DstAddr;
my_DstAddr.addrMode=(afAddrMode_t)Addr16Bit;
my_DstAddr.endPoint=GENERICAPP_ENDPOINT;
my_DstAddr.addr.shortAddr=0x0000;
AF_DataRequest(&my_DstAddr,&GenericApp_epDesc,GENERICAPP_CLUSTERID,
18,
(uint8*)&rftx,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS);
}
void sendVdd(void)
{
RFTX rftx;
uint16 nwk;
osal_memcpy(rftx.BUF.head,"&&",2);
if(GenericApp_NwkState==DEV_ROUTER)
osal_memcpy(rftx.BUF.type,"ROU",3);
if(GenericApp_NwkState==DEV_END_DEVICE)
osal_memcpy(rftx.BUF.type,"END",3);
nwk=NLME_GetShortAddr();
To_string(rftx.BUF.myNWK,(uint8*)&nwk,2);
nwk=NLME_GetCoordShortAddr();
To_string(rftx.BUF.pNWK,(uint8*)&nwk,2);
uint16 vddvalue;
vddvalue=69*getVddvalue()/256;
rftx.BUF.value[0]='V';
rftx.BUF.value[1]=vddvalue/10+'0';
rftx.BUF.value[2]='.';
rftx.BUF.value[3]=vddvalue%10+'0';
rftx.BUF.tail='&';
afAddrType_t my_DstAddr;
my_DstAddr.addrMode=(afAddrMode_t)Addr16Bit;
my_DstAddr.endPoint=GENERICAPP_ENDPOINT;
my_DstAddr.addr.shortAddr=0x0000;
if(AF_DataRequest(&my_DstAddr,&GenericApp_epDesc,GENERICAPP_CLUSTERID,
18,
(uint8*)&rftx,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS)== afStatus_SUCCESS )
{
HalLedBlink(HAL_LED_1,0,50,500);
}
}
void To_string(uint8 *dest,char* src,uint8 length)//二进制书转化为十六进制数
{
uint8* xad;
uint8 i=0;
uint8 ch;
xad=src+length-1;
for(i=0;i
{
ch=(*xad>>4)&0x0F; //除以十六
dest[i<<1]=ch+((ch<10)?'0':'7');
ch=*xad&0x0F;
dest[(i<<1)+1]=ch+((ch<10)?'0':'7');
}
}
4、实验结果
|