单播广播实验
实验基于IAR Assembler for 8051 8.10.1 编程环境和粤嵌CC2530开发版,在协议栈代码上进行修改增删。
实验内容
1、协调器进行广播,发送Coordinator Send!
这一消息。此时led2不亮,led1闪烁。
2、组网过程:首先终端所有灯都不闪烁;等稳定之后,led2闪烁;最后当终端进入到网络中,led1开始闪烁,终端对协调器单播,向协调器发送EndDevice Received!
3、当终端加入到网络后,协调器由led1闪烁转换成led2闪烁,并接收终端发来的数据,经串口发送到PC机,最终显示到串口助手上。
代码分析
下面将从协调器和终端两个方面进行分析
协调器
协调器中有三个核心函数,分别为消息处理函数GenericApp_ProcessEvent()、数据处理函数GenericApp_MessageMSGCB()以及消息发送函数GenericApp_SendTheMessage()
GenericApp_MessageMSGCB()函数
这一函数的过程为:使用osal_msg_receive函数从消息队列上接收一个消息,然后使用switch-case语句判断事件类型,如果是接收了新数据事件AF_INCOMING_MSG_CMD,则调用相应的事件处理函数,如果是接收了网络状态变化事件ZDO_STATE_CHANGE,也会做相应处理。
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
上面这一语句使用osal_msg_receive()函数从消息队列接收消息,消息包含指向接收到的无线数据包的指针,类比ESP8266中的数据包,因为zigbee是类似WiFi的一种无线通信设备。
HalLedSet(HAL_LED_2,HAL_LED_MODE_OFF); //(哪一个灯,灯的模式/状态)
HalLedBlink(HAL_LED_1,0,50,500); //(哪一个灯,闪烁次数,在一个周期内各状态的百分比,周期)
上面是协议栈提供的两个函数,HalLedSet()的功能是设置某个灯的状态,HalLedBlink()的功能是使灯闪烁。
HalLedBlink(HAL_LED_1,0,50,500);的意思为操作LED1,0表示一直闪烁,亮灭各占一半,周期500即500ms
case AF_INCOMING_MSG_CMD:
上面代表一个事件,常用事件有:
- AF_INCOMING_MSG_CMD 表示收到了一个新的无线数据
- AF_DATA_CONFIRM_CMD 调用AF_DataReguest()发送数据时,有时需要确认信息,该事件与此有关
- ZDO_STATE_CHANGE 当网络状态发生变化时,会产生该事件,如终端加入网络时,就可以通过判断该事件来决定何时向协调器发送数据包
- ZDO_CB_MSG 指示每一个注册的ZDO响应消息
osal_start_timerEx(GenericApp_TaskID,SEND_TO_ALL_EVENT,5000);
//以下是本函数的原型函数
/*********************************************************************
* @brief This function is called to start a timer to expire in n mSecs.
* When the timer expires, the calling task will get the specified event.
*
* @param uint8 taskID 定时时间到达后,哪个任务对其做出响应
* @param uint16 event_id 事件id,定时时间到达后,该事件发生
* @param UNINT16 timeout_value 定时时间参数由timeout_value(以毫秒为单位)参数确定。
*
* @return SUCCESS, or NO_TIMER_AVAIL.
*********************************************************************/
uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value )
{
halIntState_t intState;
osalTimerRec_t *newTimer;
HAL_ENTER_CRITICAL_SECTION( intState );
newTimer = osalAddTimer( taskID, event_id, timeout_value );
HAL_EXIT_CRITICAL_SECTION( intState );
return ( (newTimer != NULL) ? SUCCESS : NO_TIMER_AVAIL );
}
osal_start_timerEx()是一个定时函数,可以实现毫秒级的定时,定时时间到达后,发送数据到协调器,发送完数据后,再定一段时间,如此反复,实现周期性发送数据。
#define SEND_TO_ALL_EVENT 0X01 //定义新事件
return (events ^ SYS_EVENT_MSG);
异或运算,可以恰好可以将处理完的事件清除,仅留下未处理的事件。
if ( events & SEND_TO_ALL_EVENT )
{
GenericApp_SendTheMessage();
osal_start_timerEx( GenericApp_TaskID,SEND_TO_ALL_EVENT,5000 );
return( events & SEND_TO_ALL_EVENT );//清除SEND_TO_ALL_EVENT事件
}
上面这一块代码表示如果SEND_TO_ALL_EVENT发生,则events & SEND_TO_ALL_EVENT非零,条件成立则执行,向终端节点发送数据,发送完整数据之后再定时5s ,最后清除这一事件。
完整代码:
//消息处理函数
UINT16