智能家居无线传感网通用监控协议的设计与实现
Posted ionfox
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能家居无线传感网通用监控协议的设计与实现相关的知识,希望对你有一定的参考价值。
智能家居的无线终端设备千差万别,未来也不知道有多少新玩意出现。必须有囊括一切的设备描述能力,否则通用性免谈!好在应阁物联网科技的设备接口设计做到了这点。下面设计一个终端设备(硬件已经实现了): 有1个LED指示灯(可控制),一个温度传感器、一个湿度传感器。每5秒采集一次温湿度数据报告给监控平台。但监控平台可以设置采样的周期(1--60秒)。设计流程与协调其类似。
1、设备初始化代码
void Initdevicestable(void) //1、硬件厂家必须描述子设备数量表:在应用程序初始化后调用该函数
deviceinfo = (devicetable_t *)osal_mem_alloc(sizeof(devicetable_t));//动态分配结构体
memset(deviceinfo, 0, sizeof(devicetable_t)); //首先全部清零
//对六类子设备填写数据
setdevicetypeandnumbers(&deviceinfo->subdevices[DO],DO,1); //有1个LED灯开关
setdevicetypeandnumbers(&deviceinfo->subdevices[AI],AI,2); 有1个温度传感器和1个湿度传感器
setdevicetypeandnumbers(&deviceinfo->subdevices[AO],AO,1); //有1个AO设备:采样周期1--60秒
sprintf(deviceinfo->description,"应阁温湿度传感器");
deviceinfo->PanID=_NIB.nwkPanId;
InitDeviceDescription(); //始化子设备的描述
void InitDeviceDescription(void) //2、硬件厂家必须初始化子设备的描述
uint8 i;
uint8 devnumbers=getdevicenumbers(deviceinfo->subdevices[DO]); //DO子设备数量
i=sizeof(devicedescription_t);
DODevices = (devicedescription_t *) osal_mem_alloc( devnumbers * i);//动态分配结构体
for (i=0;i<devnumbers;i++)
memset((void *)(DODevices+i), 0, sizeof(devicedescription_t)); //首先全部清零
DODevices[i].devicenumber=(DO<<5)+i; //类型+序号
DODevices[i].subtype=OPEN;
strcpy(DODevices[i].unit,""); //计量单位:无
sprintf(DODevices[i].description,"第%d个LED灯",i+1);
sprintf(DODevices[i].operation,"点击DO切换开关");
devnumbers=getdevicenumbers(deviceinfo->subdevices[AI]); //AI子设备数量
i=sizeof(devicedescription_t);
AIDevices = (devicedescription_t *) osal_mem_alloc( devnumbers * i);//动态分配结构体
for (i=0;i<devnumbers;i++)
memset((void *)(AIDevices+i), 0, sizeof(devicedescription_t)); //首先全部清零
AIDevices[i].devicenumber=(AI<<5)+i; //类型+序号
AIDevices[i].subtype=Unknow;
if (i==0)
strcpy(AIDevices[i].unit,"℃"); //温度传感器:计量单位
sprintf(AIDevices[i].description,"温度传感器");
sprintf(AIDevices[i].operation,"");
else if (i==1)
strcpy(AIDevices[i].unit,"%"); //湿度传感器:计量单位
sprintf(AIDevices[i].description,"湿度传感器");
sprintf(AIDevices[i].operation,"");
else
strcpy(AIDevices[i].unit,""); //计量单位:无
sprintf(AIDevices[i].description,"未知设备");
sprintf(AIDevices[i].operation,"未知设备");
devnumbers=getdevicenumbers(deviceinfo->subdevices[AO]); //AO子设备数量
i=sizeof(devicedescription_t);
AODevices = (devicedescription_t *) osal_mem_alloc( devnumbers * i);//动态分配结构体
for (i=0;i<devnumbers;i++)
memset((void *)(AODevices+i), 0, sizeof(devicedescription_t)); //首先全部清零
AODevices[i].devicenumber=(AO<<5)+i; //类型+序号
AODevices[i].subtype=Unknow;
if (i==0)
strcpy(AODevices[i].unit,"毫秒"); //采样周期
sprintf(AODevices[i].description,"定时采样周期");
sprintf(AODevices[i].operation,"输入毫秒数");
else
strcpy(AODevices[i].unit,""); //计量单位:无
sprintf(AODevices[i].description,"未知设备");
sprintf(AODevices[i].operation,"未知设备");
//如果有其他类型的子设备,需要一一填写结构体
//.............
2、入网后报告设备信息
static void NotifyCoordinatorDevices(void) //报告设备信息给协调器
uint8 i,size;
uint8 cnt;
uint16 addr;
devicedescription_t* devdes;
//交互命令CMD协议定义,应用数据帧FF FX ADDR SIZE DATA
//数据内容标识头=0xFFF0+CMD; 第3,4个字节为设备ID号
//第5个字节SIZE为后面数据DATA的字节数
//#define SENDDATAHead 0xFFF0// 交互数据内容识头
//#define SENDDEVTABLE 0 // 发送设备信息表,E-->C
//#define SENDDEVDESCP 1 // 发送子设备描述记录,E-->C
//#define SENDDEVSTATE 2 // 发送子设备状态数据,E-->C
//#define SENDDEVCTRLL 3 // 控制子设备工作指令,C-->E
//1、发送设备数据表
uint8 table[80];
addr=NLME_GetShortAddr();
table[0]=SENDDATAHead>>8;
table[1]=(SENDDATAHead & 0x00F0)+SENDDEVTABLE;
table[2]=addr&0xFF;
table[3]=addr>>8;
table[4]=sizeof(devicetable_t);
memcpy((void*)(table+5), (void*)deviceinfo, table[4]);
while(true)
if(AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
5+table[4], //这个参数就是发送的数据的长度
(uint8 *)table,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
else
HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
DelayMS(500); //稍微延时后重发
//2、发送各个子设备的描述
/*****************DO**************************/
DelayMS(1000); //稍微延时
cnt=getdevicenumbers(deviceinfo->subdevices[DO]); //DO子设备数量
size=sizeof(devicedescription_t); //子设备信息描述结构体大小
for (i=0;i<cnt;i++)
//HalLedSet(HAL_LED_2, HAL_LED_MODE_BLINK);
//HalLedBlink(HAL_LED_2,3,50,500);
devdes=DODevices+i;
table[1]=(SENDDATAHead & 0x00F0)+SENDDEVDESCP; //发送子设备信息描述
table[4]=size;
memcpy((void*)(table+5), (void*)devdes, size);
while(true)
if (AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
5+size,//这个参数就是发送的数据的长度
(void *)table,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
else
HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
//DelayMS(500); //稍微验收后重发
HalLedBlink(HAL_LED_2,3,50,500);
DelayMS(1000); //稍微延时
/*****************AI**************************/
cnt=getdevicenumbers(deviceinfo->subdevices[AI]); //AI子设备数量
size=sizeof(devicedescription_t); //子设备信息描述结构体大小
for (i=0;i<cnt;i++)
//HalLedSet(HAL_LED_2, HAL_LED_MODE_BLINK);
//HalLedBlink(HAL_LED_2,3,50,500);
devdes=AIDevices+i;
table[1]=(SENDDATAHead & 0x00F0)+SENDDEVDESCP; //发送子设备信息描述
table[4]=size;
memcpy((void*)(table+5), (void*)devdes, size);
while(true)
if (AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
5+size,//这个参数就是发送的数据的长度
(void *)table,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
else
HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
//DelayMS(500); //稍微验收后重发
HalLedBlink(HAL_LED_2,3,50,500);
DelayMS(500); //稍微延时
/*****************AI**************************/
cnt=getdevicenumbers(deviceinfo->subdevices[AO]); //AO子设备数量
size=sizeof(devicedescription_t); //子设备信息描述结构体大小
for (i=0;i<cnt;i++)
devdes=AODevices+i;
table[1]=(SENDDATAHead & 0x00F0)+SENDDEVDESCP; //发送子设备信息描述
table[4]=size;
memcpy((void*)(table+5), (void*)devdes, size);
while(true)
if (AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
5+size,//这个参数就是发送的数据的长度
(void *)table,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) break;
else
HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); //LED指示一下
//DelayMS(500); //稍微验收后重发
HalLedBlink(HAL_LED_2,3,50,500);
DelayMS(500); //稍微延时
3、收到监控平台数据指令的处理
static void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )//接受处理函数
uint8 buffer[120];
uint16 addr;
uint8 cmd;
uint8 type;
uint8 number;
uint16 addrself;
addrself=NLME_GetShortAddr();
//需要根据具体硬件设计来修改该函数,有待完善....//
switch ( pkt->clusterId )
case GENERICAPP_CLUSTERID:
osal_memcpy(buffer,pkt->cmd.Data,pkt->cmd.DataLength); //获取应用数据
//交互命令CMD协议定义,应用数据帧FF FX ADDR SIZE DATA
//数据内容标识头=0xFFF0+CMD; 第3,4个字节为设备ID号
//第5个字节SIZE为后面数据DATA的字节数
//提取地址,验证地址码?可能是广播
if(pkt->cmd.DataLength<6) return; //协议规定了至少6个字节
if(buffer[0]!=0xFF || (buffer[1]>>4)!=0x0F) return;
addr=buffer[2]+(buffer[3]<<8); //验证地址码?
if (addrself!=addr && addr!=0xFFFF) return; //不是发给自己的,或者广播地址
ProcessTempHumiData(buffer);
break;
void ProcessTempHumiData(uint8* buffer)
uint16 addr;
uint8 cmd;
uint8 type;
uint8 number;
uint8 *data;
//需要根据具体硬件设计来修改该函数,有待完善....//
//交互命令CMD协议定义,应用数据帧FF FX ADDR SIZE DATA
//数据内容标识头=0xFFF0+CMD; 第3,4个字节为设备ID号
//第5个字节SIZE为后面数据DATA的字节数
//提取地址,验证地址码?可能是广播
cmd=buffer[1] & 0x0F;
if (cmd==SENDDEVCTRLL) // 3:控制子设备工作指令,P-->C-->E
//高3位:子设备类型,低五位:子设备编号0--15
type=buffer[5]>>5;
number=buffer[5]&0x1F;
if (type==DO) //DO子设备
if(number==0)
//HalLedSet(HAL_LED_1,HAL_LED_MODE_TOGGLE);
P1_0=buffer[6];
buffer[1]=0xF0+SENDDEVSTATE;// 负责返回实际状态SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
buffer[6]=P1_0; //查看接线图
buffer[4]=2; //两个字节的数据
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
7,
buffer,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
else if (number==1)
//HalLedSet(HAL_LED_2,HAL_LED_MODE_TOGGLE);
P1_1=buffer[6];
buffer[1]=0xF0+SENDDEVSTATE;// 负责返回实际状态SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
buffer[6]=P1_1; //查看接线图
buffer[4]=2; //两个字节的数据
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
7,
buffer,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
if (type==AO) //AO子设备
if(number==0) //调节采样周期
data= (uint8 *)osal_mem_alloc(buffer[4]);//动态分配数据
memset(data,0,buffer[4]);
memcpy(data,&buffer[6],buffer[4]-1);
addr=atoi(data);
if (addr>=1000 && addr<=60000)
My_SEND_MSG_TIMEOUT=addr;
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_SEND_MSG_EVT,
My_SEND_MSG_TIMEOUT);
buffer[1]=0xF0+SENDDEVSTATE;// 负责返回实际状态SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
buffer[4]+5,
buffer,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
osal_mem_free(data);
else if (cmd==SENDDEVSTATE)// SENDDEVSTATE 2:发送子设备状态数据,E<-->C<-->P
//高3位:子设备类型,低五位:子设备编号0--15
type=buffer[5]>>5;
number=buffer[5]&0x1F;
if (type==DO) //获取DO子设备状态
if(number==0)
buffer[6]=P1_0; //查看接线图
buffer[4]=2; //两个字节的数据
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
7,
buffer,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
else if (number==1)
buffer[6]=P1_1; //查看接线图
buffer[4]=2; //两个字节的数据
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
7,
buffer,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
else if (number==0x1F) //所有DO子设备状态
buffer[6]=P1_0; //查看接线图
buffer[7]=P1_1; //查看接线图
buffer[4]=3; //3个字节的数据
AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
8,
buffer,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
else if (type==AI) //获取AI子设备状态
if(number==0)
//GenericApp_Send_TempSensor_Message();
else if (number==1)
//GenericApp_Send_LightSensor_Message();
else if (number==0x1F) //所有AI子设备状态
GenericApp_Send_TempHumitureSensor_Message();
else if (type==AO) //获取AO 子设备状态:采样周期
if(number==0)
GenericApp_Send_Sample_Time();
else if (number==1)
//GenericApp_Send_LightSensor_Message();
else if (number==0x1F) //所有A0子设备状态
GenericApp_Send_Sample_Time();
只要程序设计者,合理规划设备的功能,任何复杂的设备都可以统一监控。是不是很爽?就像上面例子的AO子设备,其实是一项功能,并没有实际的硬件电路支持(定时器除外)。需要详细工程项目案例的代码,请到http://www.ionfox.com.cn/ZigBeeDevice.zip下载查看运行。开发环境:IAR8.10.1
祝你的设备哪里都可以用。
以上是关于智能家居无线传感网通用监控协议的设计与实现的主要内容,如果未能解决你的问题,请参考以下文章
基于单片机GSM大棚环境智能监控系统基于单片机的警示灯爆闪灯设计基于单片机太阳能手机智能充电器设计基于单片机智能无线病床呼叫系统设计-设计资料转发分享