文章目录
总体方向:
单片机的部分就不需要学习了,主要学习zigbee和主控部分前端部分会基本的改就行。
一、了解zigbee在物联网通信协议中的位置
云端协议:
网关协议:
现在长距离一般都使用wifi而这些一般都是有插电的比如冰箱洗衣机等,而短距离就用蓝牙因为省电。我们项目使用zigbee目的是为了便于学习。
二、zigbee是如何建立网络的(只需了解,不需要我们实现)
协调器如何加入网络:
节点如何加入网络:
三、如何使用zigbee(首先要安装zigbee协议用IAR软件打开并编写)
分析zigbee系统:
总:
main
->osal_init_system();//初始化操作系统
->osal_start_system(); // No Return from here// 执行操作系统,进去后不会返回
初始化:
osal_init_system
->osalInitTasks();//初始化系统任务
->ZDApp_Init( taskID++ );//ZDApp_Init(4) ,用户需考虑(不太重要)
->GenericApp_Init( taskID ); //用户自定义初始化(节点,协调器,路由器各有定义)重要
协调器初始化:
GenericApp_Init
...
GenericApp_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//协调器对应AddrBroadcast
GenericApp_DstAddr.endPoint = GENERICAPP_ENDPOINT;//都一样
GenericApp_DstAddr.addr.shortAddr = 0xFFFF;//地址自己定,不与其他一样就行
...
//协调器需要串口与Linux通信,初始化串口
halUARTCfg_t uartConfig;
uartConfig.configured = TRUE;
uartConfig.baudRate = HAL_UART_BR_115200;
uartConfig.flowControl = FALSE;
uartConfig.flowControlThreshold = 1;
uartConfig.rx.maxBufSize = 255;
uartConfig.tx.maxBufSize = 255;
uartConfig.idleTimeout = 1;
uartConfig.intEnable = TRUE;
uartConfig.callBackFunc = rxCB;
HalUARTOpen (HAL_UART_PORT_0, &uartConfig);
//初始化lcd
HalLcdInit();
clear_lcd();
节点初始化:
GenericApp_Init:
...
GenericApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;//节点对应Addr16Bit
GenericApp_DstAddr.endPoint = GENERICAPP_ENDPOINT;
GenericApp_DstAddr.addr.shortAddr = 0x0000;
...
//硬件初始化
InitBeep();
InitLed();
InitRelay();
Init_infrare();
HalLcdInit();
clear_lcd()
开始任务:
osal_start_system
->osal_run_system
->events = (tasksArr[idx])( idx, events );//通过指针调用任务处理函数,关键,执行taskarr中的函数
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_ProcessEvent,
#endif
ZDApp_event_loop,
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_event_[]loop,
#endif
GenericApp_ProcessEvent//只有它不是三者共用的,用于事件发生时的处理函数
};
协调器:
串口接收到中断,发送命令给节点:
static void rxCB(uint8 port,uint8 event)
....
if(AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,//字节的节点id
1,//发送字节数
&cmd,//发送消息
&GenericApp_TransID, //0
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS )==afStatus_SUCCESS)
{
}
....
接收节点消息,串口发送给Linux
GenericApp_ProcessEvent//协调器只需要接收节点消息并提供串口发送给linux就行
......
if ( events & SYS_EVENT_MSG ){//有SYS_EVENT_MSG事件发生
....
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );//接收发送过来的消息
switch ( MSGpkt->hdr.event ){//判断具体是什么事件
....
case AF_INCOMING_MSG_CMD://接收数据事件,调用函数 AF_DataRequest()接收数据
GenericApp_MessageMSGCB( MSGpkt );//根据节点发过来的命令将数据发给linux
break;
....
}
}
GenericApp_MessageMSGCB
....
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID1:
case GENERICAPP_CLUSTERID2:
case GENERICAPP_CLUSTERID3:
case GENERICAPP_CLUSTERID4:
HalUARTWrite(0, pkt->cmd.Data,24);//串口发送数据pkt->cmd.Data
break;
}
....
节点:
GenericApp_ProcessEvent //以节点为例,节点需要定时发送数据给协调器,也需要接收来自协调器的信息
......
if ( events & SYS_EVENT_MSG ){//有SYS_EVENT_MSG事件发生
....
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );//接收发送过来的消息
switch ( MSGpkt->hdr.event ){//判断具体是什么事件
....
case AF_INCOMING_MSG_CMD://接收数据事件,调用函数 AF_DataRequest()接收数据
GenericApp_MessageMSGCB( MSGpkt );//根据协调器发过来的命令进行相应的处理
break;
....
case ZDO_STATE_CHANGE://如果是任何状态改变事件,比如开启时
....
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_SEND_MSG_EVT,//定时器到期标志
GENERICAPP_SEND_MSG_TIMEOUT );//设置定时器时间
show_title();
....
}
}
if ( events & GENERICAPP_SEND_MSG_EVT )//定时器到期
{ //定时器,每隔5秒发送一次传感器数据信息
SyncData(ENDDEVICE_ID);//获取硬件信息,并存入EnvMsg结构体中,并且先在自己的lcd上显示出信息
memcpy(sendbuf, &EnvMsg, 24);
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID1,//协调器1
24, //数据字节数
(uchar *)&EnvMsg,//消息
&GenericApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );//zigbee发送函数
// Setup to send message again
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_SEND_MSG_EVT,
ENDDEVICE_SEND_MSG_TIMEOUT );//重新设置定时器
....
}
......
接收协调器消息,解析命令做出改变:
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
uint8_t cmd = 0;
char buf[10];
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID: //协调器发来数据
cmd = *(pkt->cmd.Data);//获取消息
//显示到lcd屏幕
if((cmd & STO_MASK) == (ENDDEVICE_ID << 6)) // 仓库号正确
{
sprintf(buf,"cmd:%x",cmd);
HalUARTWrite(0, buf,strlen(buf));
HalLcdWriteString(buf,HAL_LCD_LINE_4);
switch(cmd & DEV_MASK) // 判断设备号
{
case RELY: // 排风扇命令字
// 风扇命令处理函数
RelyCtrl(cmd & CMD_MASK);
//HalLcdWriteString("rely",HAL_LCD_LINE_5);
break;
case BEEP: // 蜂鸣器命令字
// 蜂鸣器命令处理函数
BeepCtrl(cmd & CMD_MASK);
break;
case LED: // 照明灯命令字
// 照明灯命令处理函数
LedCtrl(cmd & CMD_MASK);
break;
default :
break;
}
}
break;
}
}