实验内容:在协调器一方(串口助手发送窗口)将一字符通过广播的方式发送给路由器,并在它的串口助手接收窗口中显示出来,若为“1”,则点亮D2,若为“0”,则熄灭D2,若为其他字符,则助手中显示“error”。
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ){
...........
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ( (SampleApp_NwkState == DEV_ZB_COORD))
{
// Start sending the periodic message in a regular interval.
HalLedSet (HAL_LED_1, HAL_LED_MODE_ON);
HalLedSet (HAL_LED_2, HAL_LED_MODE_ON);
}
else
{
// Device is no longer in the network
}
break;
...........
}
之所以把原来的:
if ( (SampleApp_NwkState == DEV_ZB_COORD)||(SampleApp_NwkState == DEV_ROUTER)||(SampleApp_NwkState == DEV_END_DEVICE))
改为上述的:
if ( (SampleApp_NwkState == DEV_ZB_COORD))
就是为了更为明确加入网络的是协调器。在if条件语句里面加入点亮两盏灯是为了判断当前设备网络状态是否为协调器。
若想在设备网络状态进入DEV_ZB_COORD状态就现实发送数据并且是每隔一段时间就发送数据,则在if判断语句加入一条语句:
osal_start_timerEx( SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件里面包含语句有
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
{
// Send the periodic message
SampleApp_SendPeriodicMessage();
// Setup to send message again in normal period (+ a little jitter)
osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
// return unprocessed events
return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
}
但题目是要求是在协调器的对应的串口助手先发送一个字符然后路由器接受一个字符,所以不应该在if判断语句体里面加 osal_start_timerEx()函数而且 if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )语句体里面也应该把osal_start_timerEx()函数注销(防止定期发送数据)。
正确方式:在串口事件函数加入。
void SampleApp_SerialCMD(mtOSALSerialData_t *cmdMsg){
............
for(i=1;i<=len;i++)
{
SampleAppPeriodicCounter=*(str+i);
osal_start_timerEx( SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
//或不要osal_start_timerEx(0函数,直接使用SampleApp_SendPeriodicMessage();函数效率更快
break;
}
......................
}
协调器到此结束,若不允许协调器接收数据应该把SampleApp_MessageMSGCB( MSGpkt );函数注销。
case AF_INCOMING_MSG_CMD:
SampleApp_MessageMSGCB( MSGpkt );
case AF_INCOMING_MSG_CMD:
SampleApp_MessageMSGCB( MSGpkt );
break;
在协调器注销的SampleApp_MessageMSGCB( MSGpkt );在路由器这里要开启,让路由器可以接收数据。
下面这段代码的目的与协调器的一样,若两盏灯没有点亮,则说明设备的网络状态加入DEV_ROUTER失败。
解决办法:
1、在工作空间一点要选择RouterEB
2、若执行步骤1仍然不行,继步骤1后,这直接手动改为路由器模式;修改如下:
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
点击Edit–>File and Replace–>Find in Files寻找ZDO_STATE_CHANGE
pMsg->event = ZDO_STATE_CHANGE;
//把pMsg->status = state;修改为pMsg->status = DEV_ROUTER;
pMsg->status = state;
case ZDO_STATE_CHANGE:
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ((SampleApp_NwkState == DEV_ROUTER))
{
HalLedSet (HAL_LED_1, HAL_LED_MODE_ON);
HalLedSet (HAL_LED_2, HAL_LED_MODE_ON);
}
//这就是实现题目要求的函数
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
uint16 flashTime;
switch ( pkt->clusterId )
{
case SAMPLEAPP_PERIODIC_CLUSTERID:
if((pkt->cmd.Data[0])=='0')
{
HalLedSet (HAL_LED_1, HAL_LED_MODE_OFF);
}
else if((pkt->cmd.Data[0])=='1')
{
HalLedSet (HAL_LED_1, HAL_LED_MODE_ON);
}
else
{
HalUARTWrite(0,"error\n",5);
}
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;
}
}
操作步骤
分别把CoordinatorEB和routerEB下载到实验板上,在CoordinatorEB对应的串口助手上发送一个字符。若字符不是’0’或’1’则在routerEB串口助手上显示字符串"error"!
源码下载
github源码下载连接