目录
一、zigbee是什么?
ZigBee是一种基于IEEE 802.15.4标准的高层通信协议,主要用于近距离无线个人区域网(WPAN)。它由ZigBee联盟开发,旨在实现低功耗、低数据率、低成本的无线通信解决方案,广泛应用于家庭自动化、工业控制、医疗保健、智能电网等领域。ZigBee网络具有自组织、自愈能力,支持星状、树状和网状拓扑结构,允许多个设备之间的互联互通。
二、zigbee的特点
ZigBee 是一种无线连接,可工作在 2.4GHz(全球流行)、868MHz(欧洲流行)和 915MHz(美国流行)三个频段上,分别具有最高 250kb/s、20kb/s 和 40kb/s 的传输速率,它的传输距离在 10~75m 的范围内,但可以继续增加。作为一种无线通信技术,ZigBee 自身的技术优势主要表现在以下几个方面。
1.功耗低三
ZigBee 网络节点设备工作周期较短、收发数据信息功耗低,且使用了休眠模式(当不需接收数据时处于休眠状态,当需要接收数据时由“协调器”唤醒它们),因此,ZigBee技术特别省电,据估算,ZigBee 设备仅靠两节 5 号电池就可以维持长达 6 个月到两年左右的使用时间,这是其他无线设备望尘莫及的,避免了频繁更换电池或充电,从而减轻了网络维护的负担。
2.成本低
由于 ZigBee 协议栈设计非常简单,所以其研发和生产成本较低。普通网络节点硬件只需 8 位微处理器,4~32KB 的 ROM,且软件实现也很简单。随着产品产业化,ZigBee 通信模块价格预计能降到 10 元人民币,并且 ZigBee 协议是免专利费的。低成本对于 ZigBee也是一个关键的因素。
3.可靠性高
由于采用了碰撞避免机制并且为需要固定带宽的通信业务预留了专用时隙,避免了收
发数据时的竞争和冲突,且 MAC 层采用完全确认的数据传输机制,每个发送的数据包都必须等待接收方的确认信息,所以从根本上保证了数据传输的可靠性。如果传输过程中出现问题可以进行重发。
4.容量大
一个 ZigBee 网络最多可以容纳 254 个从设备和 1 个主设备,一个区域内最多可以同时存在 100 个 ZigBee 网络,而且网络组成灵活。
5.时延小
ZigBee 技术与蓝牙技术的时延相比,其各项指标值都非常小。通信时延和从休眠状态激活的时延都非常短,典型的搜索设备时延 30ms,而蓝牙为 3~10s。休眠激活的时延是15ms,活动设备信道接入的时延为 15ms。因此 ZigBee 技术适用于对时延要求苛刻的无线控制(如工业控制场合等)应用。
6.安全性好
ZigBee 技术提高了数据完整性检查和鉴权功能,加密算法使用 AES-128,且各应用可以灵活地确定安全属性,从而使网络安全能够得到有效的保障。
7.有效范围小
有效覆盖范围在 10~75m 之间,具体依据实际发射功率的大小和各种不同的应用模式而定,基本上能够覆盖普通的家庭或办公室环境。
8.兼容性
ZigBee 技术与现有的控制网络标准无缝集成。通过网络协调器自动建立网络,采
用载波侦听/冲突检测(CSMACA)方式进行信道接入。为了可靠传递,还提供全握手协议。
ZigBee 具有广阔的应用前景。ZigBee 联盟预言在未来的 4 到 5 年,每个家庭将拥有 50个 ZigBee 器件,最后将达到每个家庭 150 个。据估计,ZigBee 市场价值将超过数亿美元/年。
三、项目要求
1.硬件准备:
两块支持ZigBee的开发板(如CC2530, CC2650等)。每个开发板需要连接一个串口模块(如USB转串口模块),以便通过串口助手进行通信。如图
2.软件准备:
安装ZigBee协议栈(如TI的Z-Stack)。
安装串口助手软件(如PuTTY, SecureCRT, 或任何你喜欢的串口通信软件)。如下
准备或获取一个支持串口透传的ZigBee示例项目(如sampleAPP)。
配置sampleAPP
A小组(协调器)
修改sampleAPP.c:
设置为协调器模式。
配置网络参数(如PAN ID, 信道等)。
编写代码以从串口接收数据,并通过ZigBee网络发送。
部分sampleAPP.h如下:
#ifndef SAMPLEAPP_H
#define SAMPLEAPP_H
#ifdef __cplusplus
extern "C"
{
#endif
#define SAMPLEAPP_ENDPOINT 20
#define SAMPLEAPP_PROFID 0x0F08
#define SAMPLEAPP_DEVICEID 0x0001
#define SAMPLEAPP_DEVICE_VERSION 0
#define SAMPLEAPP_FLAGS 0
#define SAMPLEAPP_MAX_CLUSTERS 2
#define SAMPLEAPP_PERIODIC_CLUSTERID 1
#define SAMPLEAPP_FLASH_CLUSTERID 2
#define SAMPLEAPP_SERIAL_CLUSTERID 4
#define SAMPLEAPP_P2P_CLUSTERID 5
// Send Message Timeout
#define SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT 5000
#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT 0x0001
#define SAMPLEAPP_FLASH_GROUP 0x0003
#define SAMPLEAPP_FLASH_DURATION 1000
#ifdef __cplusplus
}
#endif
确保端点号(EP)在两个小组中是相同的,以便于识别。
下载代码到开发板:
编译并下载代码到A小组的开发板。
B小组(终端)
sampleAPP.c部分代码:
void SampleApp_Init( uint8 task_id )
{
SampleApp_TaskID = task_id;
SampleApp_NwkState = DEV_INIT;
SampleApp_TransID = 0;
#if defined ( BUILD_ALL_DEVICES )
if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES
#if defined ( HOLD_AUTO_START )
ZDOInitDevice(0);
#endif
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;
SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;
SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;
SampleApp_P2P_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SampleApp_P2P_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_P2P_DstAddr.addr.shortAddr = 0x0000;
SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id = &SampleApp_TaskID;
SampleApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; //sampleapp
SampleApp_epDesc.latencyReq = noLatencyReqs;
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
// Received when a key is pressed
case KEY_CHANGE:
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
// Received when a messages is received (OTA) for this endpoint
case AF_INCOMING_MSG_CMD:
SampleApp_MessageMSGCB( MSGpkt );
break;
case CMD_SERIAL_MSG:
SampleApp_SerialMSG((mtOSALSerialData_t *)MSGpkt); // 㲥
break;
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ( (SampleApp_NwkState == DEV_ZB_COORD)
|| (SampleApp_NwkState == DEV_ROUTER)
|| (SampleApp_NwkState == DEV_END_DEVICE) )
{
// Start sending the periodic message in a regular interval.
osal_start_timerEx( SampleApp_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
}
else
{
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt );
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
}
return (events ^ SYS_EVENT_MSG);
}
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
{
SampleApp_SendPeriodicMessage();
osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
}
return 0;
}
#if defined(ZDO_COORDINATOR)
#else
SampleApp_SendFlashMessage(0);
#endif
SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION );
}
if ( keys & HAL_KEY_SW_2 )
{
aps_Group_t *grp;
grp = aps_FindGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );
if ( grp )
{
// Remove from the group
aps_RemoveGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );
}
else
{
// Add to the flash group
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
}
}
}
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
uint16 flashTime;
uint8 asc_16[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
uint16 temp;
switch ( pkt->clusterId )
{
case SAMPLEAPP_PERIODIC_CLUSTERID:
break;
case SAMPLEAPP_FLASH_CLUSTERID:
flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );
HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
break;
case SAMPLEAPP_SERIAL_CLUSTERID:
HalUARTWrite(0, &pkt->cmd.Data[0],
pkt->cmd.DataLength);
HalUARTWrite(0,"\n",1);
break;
case SAMPLEAPP_P2P_CLUSTERID:
HalUARTWrite(0,"Rx:",3);
HalUARTWrite(0,pkt->cmd.Data,pkt->cmd.DataLength);
HalUARTWrite(0,"\n",1);
temp=pkt->srcAddr.addr.shortAddr;
if(pkt->cmd.Data[0]==1)
HalUARTWrite(0,"ROUTER ShortAddr:0x",20);
if(pkt->cmd.Data[0]==2)
HalUARTWrite(0,"ENDDEVICE ShortAddr:0x",25);
HalUARTWrite(0,&asc_16[temp/4096],1);
HalUARTWrite(0,&asc_16[temp%4096/256],1);
HalUARTWrite(0,&asc_16[temp%256/16],1);
HalUARTWrite(0,&asc_16[temp%16],1);
HalUARTWrite(0,"\n",1);
break;
default:
break;
}
}
设置为终端模式。
编写代码以加入A小组创建的ZigBee网络。
编写代码以从ZigBee网络接收数据,并通过串口发送。
修改sampleAPP.h:
确保端点号与A小组一致。
下载代码到开发板:
编译并下载代码到B小组的开发板。
测试
启动A小组的开发板:
通过串口助手发送测试字符串。
启动B小组的开发板:
观察串口助手是否能接收到从A小组发送的字符串。
注意事项
确保ZigBee网络参数(如PAN ID, 信道)在两个设备中是一致的。
检查串口配置(波特率、数据位、停止位等)在两个串口助手中是否一致。
如果网络加入失败,检查ZigBee网络的安全性设置(如是否启用了加密)。
调试时,可以使用ZigBee协议栈提供的调试工具来查看网络状态和消息传递情况。
四、实验结果
其中A小组使用ZigBee协调器(Coordinator)而B小组使用ZigBee终端(End Device),我们需要通过ZigBee网络来传递信息。A小组通过串口助手发送字符串信息给A开发板,B小组串口助手能够看到B开发板无线接收到A开发板的信息。