之前实现了基于Zigbee的SHT10温湿度数据采集系统,这里来重新复盘一些主要的知识和代码。
写在前面:
1 功能介绍:使用Zigbee终端节点采集环境的温度和湿度数据,然后将数据无线发送的Zigbee协调器,最后在电脑端显示获得到的数据。2 我没有让Zigbee终端节点 使用周期定时发送,而是通过电脑端的串口来控制 ,即:当电脑需要数据时,就返回终端节点的数据;不需要时终端节点就不会上传数据。 我这样的做法比较方便,因为选择什么时间上传 和 多久上传一次都可以由自己来决定!3 我设计的Zigbee协调器和Zigbee终端节点没有采用广播的发送方式,因为我之前要控制12个节点,广播的效果实在不太好,而且对首发时间的要求并不算高,所以我采用“单播轮询”的发送方式。4关于地址的选择,我没有使用64位的IEEE地址,我用的16位的短地址PANID,当然这些在AF_DataRequest()函数都写得很清楚。5其余细节在说代码的时候,具体再说。
下面主要介绍一下,Zigbee协调器的SampleApp.c文件的代码:
首先,我们要配置与电脑通信的串口。
这里别忘了在SampleApp.c头文件引入串口头文件#include “hal_uart.h”,我们的波特率设置为115200.
/* 串口基本定义 */#define MY_DEFINE_UART_PORT 0//自定义串口号(0,1);#define RX_MAX_LENGTH 20 //接收缓冲区最大值: 20个字节;uint8 RX_BUFFER[RX_MAX_LENGTH]; //接收缓冲区;void UartCallBackFunction(uint8 port , uint8 event); //回调函数声明,定义在最后面;/* 配置串口*/halUARTCfg_t uartConfig; //定义串口配置结构体变量;void Uart_Config(void); //函数声明;void Uart_Config(void) //函数定义;//结构体的定义函数{uartConfig.configured = TRUE; //允许配置;uartConfig.baudRate = HAL_UART_BR_115200;//波特率;uartConfig.flowControl = FALSE;uartConfig.flowControlThreshold = 64; //don't care - see uart driver.uartConfig.rx.maxBufSize = 128; //串口接收缓冲区大小uartConfig.tx.maxBufSize = 128; //串口发送缓冲区大小uartConfig.idleTimeout = 6; //don't care - see uart driver.uartConfig.intEnable = TRUE; //使能中断uartConfig.callBackFunc= UartCallBackFunction; //指定回调函数名;}
下面是我的串口回调函数static void UartCallBackFunction(uint8 port , uint8 event)。在里面我用osal_set_event自定义了任务事件,SAMPLEAPP_SEND_PERIODIC_MSG_EVT1,即:当接收到的字符为01或者02或者03时,在任务事件处理函数,SampleApp_ProcessEvent里处理相应的事件。01 控制终端节点1~终端节点4(我试过01,控制6个节点效果也是可以的,很少丢包)02控制终端节点5~终端节点803控制终端节点9~终端节点12
static void UartCallBackFunction(uint8 port , uint8 event){uint8 shuang[2]={0,0};uint16 nlen = 0; //接收到字符串大小;if(event !=HAL_UART_TX_EMPTY){nlen = HalUARTRead(0,shuang,2);if(nlen > 0) //有数据存在;{if((shuang[0] ==0x30)&&(shuang[1]==0x31))//01 //1END~4END{chose=1;x1=1;x2=1;x3=1;x4=1;osal_set_event(SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT1); }else if((shuang[0] ==0x30)&&(shuang[1]==0x32))//02 //4END~8END{chose=2;x5=1;x6=1;x7=1;x8=1;//osal_set_event(SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT1); }else if((shuang[0] ==0x30)&&(shuang[1]==0x33))//03 //9END~12END{chose=3;x9=1;xa=1;xb=1;xc=1;//9~12osal_set_event(SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT1); }}} }
下面介绍一下Zigbee协调器的接收消息事件 处理函数SampleApp_MessageMSGCB。
这里有的人会问。为什么你的接收咋就没有short address和endpoint,直接上来就判断clusterId?因为这个SampleApp_MessageMSGCB( )函数是属于应用层范畴,你的short address和endpoint在NWK层就被解析了我们在APP层就区分一下clusterId就可以了。接收的数据一共分为两类:其中SAMPLEAPP_P3P1_CLUSTERID是接收1~9号终端节点返回的PANIDSAMPLEAPP_P3P2_CLUSTERID是接收10~18号节点返回的PANID.(不是我写错了,因为去年我需要控制18个Zigbee终端节点,当然控制12个这么写也没错)SAMPLEAPP_P2P1_CLUSTERID~SAMPLEAPP_P2PC_CLUSTERID是1到12号Zigbee终端节点返回的SHT10传感器温度和湿度的DATA。
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ){switch ( pkt->clusterId ){case SAMPLEAPP_P3P1_CLUSTERID://接受终端 网络ID的镞//ok//1~9{Addrtable[(pkt->cmd.Data[0]*10)+(pkt->cmd.Data[1])]=(((uint16)pkt->cmd.Data[2])<<8)|(((uint16)pkt->cmd.Data[3])&0x00ff);//初始化D2P1SEL&=0Xfd;//1111 1101P1DIR|=0x02; //P11定义为输出0000 0010P1_1 =0;}break;case SAMPLEAPP_P3P2_CLUSTERID://接受终端 网络ID的镞//ok//10~18{Addrtable[(pkt->cmd.Data[0]*10)+(pkt->cmd.Data[1])]=(((uint16)pkt->cmd.Data[2])<<8)|(((uint16)pkt->cmd.Data[3])&0x00ff);//初始化D2P1SEL&=0Xfd;//1111 1101P1DIR|=0x02; //P11定义为输出0000 0010P1_1 =0;}break;case SAMPLEAPP_P2P1_CLUSTERID:{if(x1==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x1=0;}}break;case SAMPLEAPP_P2P2_CLUSTERID:{if(x2==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x2=0;}}break;case SAMPLEAPP_P2P3_CLUSTERID:{if(x3==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x3=0;}}break;case SAMPLEAPP_P2P4_CLUSTERID:{if(x4==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x4=0;} }break;case SAMPLEAPP_P2P5_CLUSTERID:{if(x5==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x5=0;}}break;case SAMPLEAPP_P2P6_CLUSTERID:{if(x6==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x6=0;}}break;case SAMPLEAPP_P2P7_CLUSTERID:{if(x7==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x7=0;}}break;case SAMPLEAPP_P2P8_CLUSTERID:{if(x8==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x8=0;}}break;case SAMPLEAPP_P2P9_CLUSTERID:{if(x9==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);x9=0;}}break;case SAMPLEAPP_P2Pa_CLUSTERID://10{if(xa==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);xa=0;}}break;case SAMPLEAPP_P2Pb_CLUSTERID://11{if(xb==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);xb=0;}}break;case SAMPLEAPP_P2Pc_CLUSTERID://12{if(xc==1){HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength);xc=0;}}break;}}
下面介绍一下Zigbee协调器的数据请求函数void SAMPLEAPP_TO_jiedian_shang(uint16 addr)。
在AF_DataRequest里我选择数据发送形式为单播,16位shortAddr的短地址为各个终端节点的PANID。SAMPLEAPP_ENDPOINT为20。SAMPLEAPP_P2P_CLUSTERID为4
-这个函数的作用就是依次向终端节点发送数据请求,然后终端节点就会返回温湿度的数据
//数据请求函数void SAMPLEAPP_TO_jiedian_shang(uint16 addr){SampleApp_P2P_DstAddr.addr.shortAddr=Addrtable[addr];char theMessageData[]="DATA";if ( AF_DataRequest( &SampleApp_P2P_DstAddr, &SampleApp_epDesc,SAMPLEAPP_P2P_CLUSTERID,//4(byte)osal_strlen( theMessageData )+1,(byte * )&theMessageData,&SampleApp_TransID,AF_DISCV_ROUTE,AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ){}else{// Error occurred in request to send.}}
除了SHT10之外,我还加了烟雾传感器,OLED显示屏和一个指示灯,当温度、湿度超过阈值时,指示灯闪烁。后期让好朋友用SolidWorks给Zigbee板子做了一个外壳,看起来更好一看些。
下一期,有时间再说一下我程序的Zigbee终端节点相关代码解析。
如果觉得《基于Zigbee的SHT10温湿度数据采集系统(已实现控制12个终端节点)——Zigbee协调器主要代码解析》对你有帮助,请点赞、收藏,并留下你的观点哦!