目录
3。代码讲解
1.基础概念
在Zigbee网络中存在3中逻辑设备:协调器、路由器、终端。
(这个实验当中我们只用到协调器以及终端)。
协调器:协调器负责启动网络,当启动和配置好网络后,协调器就会像一个路由器一样或者就消失了。
终端:网络中的一个设备,一个节点。
广播:当应用程序需要将数据包发送给网络的每一个设备时,使用这种模式。地址模式设置为
AddrBroadcast。目标地址可以设置为下面广播地址的一种:
NWK BROADCAST SHORTADDR DEVALL(0xFFFF)--数据包将被传送到网络上的所有设备,包括睡眠中的设备。
NWK BROADCAST SHORTADDR DEVRXON(0xFFFD)-数据包将被传送到网络上除了睡眠中的所有设备。
NWK BROADCAST SHORTADDR DEVZCZR(0xFFFC)--数据包发送给所有的路由器,包括协调器。
2.Zigbee协议栈工作流程
在main()函数中初始化操作系统osal_init_system(),初始化一些外设(协议栈已经将这些外设封装好了,可以像32一样调用函数使用。),最后进入osal_start_system()中执行操作系统,并且程序会一直处于这个函数当中,不会返回(函数中有死循环),在这个函数当中判断是否有事件发生,然后会根据优先级来处理这些事件(任务)。我们以后主要需要修改在SampleApp_Init()当中.
3.代码讲解
协议栈中很多东西已经帮我们写好,我们以后使用仅仅需要修改增加一些内容。因此代码不需要全部都懂。(初学者不要尝试将所有的代码都看懂,循序渐进。)
在目录中找到SampleApp.c,打开它,并在该C文件的顶部包含#include"MT_UART.h"
#include "MT_APP.h"
#include "MT.h"
#include "string.h"
这四个头文件。接下来找到void SampleApp_Init( uint8 task_id )这个函数
void SampleApp_Init( uint8 task_id )
{
SampleApp_TaskID = task_id;
SampleApp_NwkState = DEV_INIT;
SampleApp_TransID = 0;
//这一部分为新加进来的代码
//------------------------配置串口---------------------------------
MT_UartInit(); //串口初始化
MT_UartRegisterTaskID(task_id); //注册串口任务
HalUARTWrite(0,"UartInit OK\n", sizeof("UartInit OK\n"));
//-----------------------------------------------------------------
#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;//广播地址
/*//组播的代码
// Setup for the flash command's destination address - Group 1
SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;
SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;*/
SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_epDesc.task_id = &SampleApp_TaskID;
SampleApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
SampleApp_epDesc.latencyReq = noLatencyReqs;
afRegister( &SampleApp_epDesc );
RegisterForKeys( SampleApp_TaskID );
/*//组播的代码
// By default, all devices start out in Group 1
SampleApp_Group.ID = 0x0001;
osal_memcpy( SampleApp_Group.name, "Group 1", 7 );
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
*/
#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}
其中 MT_UartInit()在目录中MT文件中的MT_UART.c的文件当中,为串口的初始化。
这个初始化的函数当中,我们需要将波特率设置好,流控制关闭,其他的可以不用管。
然后我们就可以调用HalUARTWrite(0,"UartInit OK\n", sizeof("UartInit OK\n"))来发送初始化完成的提示。然后,如上面的代码块一样,将组播的代码注释掉。
接下来,我们进入到uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )当中。
//在这个函数当中完成对事件的处理
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
(void)task_id;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case KEY_CHANGE:
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
case AF_INCOMING_MSG_CMD://接收到数据包就进行处理
SampleApp_MessageMSGCB( 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) )
{
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;
}
接下来进入SampleApp_SendPeriodicMessage()函数当中。
void SampleApp_SendPeriodicMessage( void )
{//联网后进入这个函数
uint8 *buff=NULL;
if(zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR)//判断Zigbee的逻辑类型,如果是协调器
{
buff="I am coordinator device\r\n";
}
else if(zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE)//如果是终端
{
buff="I am endpoint device\r\n";
}
// AF_DataRequest()这个函数是真正发送数据的函数,我们需要将第三第四个参数该为数组的大小,以及数组的内容,然后就可以发送了。
if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,
SAMPLEAPP_PERIODIC_CLUSTERID,
strlen(buff),//传输数据的字节大小
buff,//传输数据
&SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
}
else
{
}
}
数据发送完了,当接受到数据包后,MSGpkt->hdr.event=AF_INCOMING_MSG_CMD,接下来,我们就要进入SampleApp_MessageMSGCB( MSGpkt )当中。
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )//无线数据包接收到之后
{
uint16 flashTime;
switch ( pkt->clusterId )
{
case SAMPLEAPP_PERIODIC_CLUSTERID://接收到该命令后执行的代码
HalUARTWrite(0,(pkt->cmd).Data,(pkt->cmd).DataLength);//将接受到的数据打印到串口中
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;
}
}
至此,代码就完成了。接下来就可以烧录,看现象了。
4.可能遇到的问题
1.注意协调器与终端的烧录,需要分开烧录。可由上图所示更改。
2.以下问题为版本不兼容
以及一堆 Undefined external "?V1" referred in AF类似的,都是由于版本不兼容的原因。解决方法:
将16改为8
在 ZStack-CC2530-2.5.1a\Projects\zstack\ZMain\TI2530DB下的chipcon_cstartup.s51文件中删除END,并添加以下代码:
;----------------------------------------------------------------;
; Virtual registers ;
; ================= ;
; Below is some segment needed for the IAR ICC C/EC++ compiler ;
; ;
; BREG : A segment for 8 bit registers for use by the compiler. ;
; ?B0 is the first register. ;
; VREG : Segment that holds up to 32 virtual registers for ;
; use by the compiler. ?V0 is the first register. ;
; PSP : Segment containing the PDATA stack pointer (?PSP) ;
; XSP : Segment containing the XDATA stack pointer (?XSP) ;
; ;
;----------------------------------------------------------------;
;----------------------------------------------------------------;
PROGRAM VIRTUAL_REGISTERS
PUBLIC ?B0
PUBLIC ?V0
PUBLIC ?V1
PUBLIC ?V2
PUBLIC ?V3
PUBLIC ?V4
PUBLIC ?V5
PUBLIC ?V6
PUBLIC ?V7
PUBLIC ?V8
PUBLIC ?V9
PUBLIC ?V10
PUBLIC ?V11
PUBLIC ?V12
PUBLIC ?V13
PUBLIC ?V14
PUBLIC ?V15
PUBLIC ?V16
PUBLIC ?V17
PUBLIC ?V18
PUBLIC ?V19
PUBLIC ?V20
PUBLIC ?V21
PUBLIC ?V22
PUBLIC ?V23
PUBLIC ?V24
PUBLIC ?V25
PUBLIC ?V26
PUBLIC ?V27
PUBLIC ?V28
PUBLIC ?V29
PUBLIC ?V30
PUBLIC ?V31
PUBLIC ?PSP
PUBLIC ?XSP
RSEG BREG:BIT:NOROOT
?B0:
DS 8
RSEG VREG:DATA:NOROOT
?V0:
DS 1
?V1:
DS 1
?V2:
DS 1
?V3:
DS 1
?V4:
DS 1
?V5:
DS 1
?V6:
DS 1
?V7:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V7
?V8:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V8
?V9:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V9
?V10:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V10
?V11:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V11
?V12:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V12
?V13:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V13
?V14:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V14
?V15:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V15
?V16:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V16
?V17:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V17
?V18:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V18
?V19:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V19
?V20:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V20
?V21:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V21
?V22:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V22
?V23:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V23
?V24:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V24
?V25:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V25
?V26:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V26
?V27:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V27
?V28:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V28
?V29:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V29
?V30:
DS 1
RSEG VREG:DATA:NOROOT
REQUIRE ?V30
?V31:
DS 1
RSEG PSP:DATA:NOROOT
EXTERN ?RESET_PSP
REQUIRE ?RESET_PSP
?PSP:
DS 1
RSEG XSP:DATA:NOROOT
EXTERN ?RESET_XSP
REQUIRE ?RESET_XSP
?XSP:
DS 2
ENDMOD ; VIRTUAL_REGISTERS
END
3.注意在烧录前需要预编译