上一篇文章介绍了上位机服务器环境的搭建,这一篇重点在于下位机的使用。本次硬件使用的是TI公司的CC2530,软件用IAR开发编程并且涉及到了TI开发的ZigBee协议栈Z-Stack的使用。
具体操作之前,简单了解一下协议栈的架构。在Z-Stack使用过程中程序的编写一般都在应用层App目录下的SampleApp.c中。
此外,在ZigBee网络中,每个ZigBee节点按功能的强弱划分为:全功能设备FFD和精简功能设备RFD,RFD节点为网络中存在数最多的端设备,而FFD节点可以担任路由器或是协调器的角色。
本次设计会用到一个协调器和两个终端,做到多点数据的采集。
因为考虑到上位机和协调器之间的串口通信,需要先配置串口信息。在硬件层(HAL)的Target\CC2530EB\Drivers目录下的hal_uart.c文件中,包含了串口驱动程序的各种接口函数,只需要调用相应的函数就可以实现串口通信的功能,而对于串口的初始化函数需要在串口、监控测试层(MT)中查看,此目录下的MT_UART.c文件中,找到MT_UartInit()串口初始化函数,其中又关于波特率BaudRate的描述:
uartConfig.baudRate = MT_UART_DEFAULT_BAUDRATE;
右键找到定义,将默认波特率大小改为9600bps:
#define MT_UART_DEFAULT_BAUDRATE HAL_UART_BR_9600
接着需要将默认开启的串口流控关闭:
#define MT_UART_DEFAULT_OVERFLOW FALSE
最后,根据相关函数在预编译设置里开启所需的串口,其中P1对应串口0。
然后需要在APP目录下的SampleApp.c文件中的SampleApp_Init()函数里加入:
MT_UartInit(); //串口初始化 MT_UartRegisterTaskID(task_id); //注册串口任务
之后使用HalUARTWrite()函数完成串口信息的写入。
将事先编写好的DHT11的头文件和c文件加入App目录下,之后在SampleApp.c文件中的SampleApp_Init()函数里加入:
P0SEL &= 0x7f; //P0_7配置成通用io P0DIR |= 0x02; //让P0.1为为输出
以及在SampleApp_SendPeriodicMessage()函数里编写所需的内容,这里加入了当湿度大于60%时开启风扇的功能。
byte temp[5],humi[6]; char dispT[20],dispH[20]; Delay_ms(500); DHT11(); //获取温湿度 Delay_ms(500); //将温湿度的转换成字符串 temp[0] = wendu_shi+0x30; temp[1] = wendu_ge+0x30; temp[2] = ' '; temp[3] = 'C'; temp[4] = '\0'; humi[0] = shidu_shi+0x30; humi[1] = shidu_ge+0x30; humi[2] = ' '; humi[3] = 'R'; humi[4] = 'H'; humi[5] = '\0'; if((shidu_ge>0)&(shidu_shi>5)) { P0_1=1; //开启电机 } else{ P0_1=0; } osal_memcpy(dispT, "Temperature:", 12); osal_memcpy(&dispT[12], temp, 5); HalLcdWriteString(dispT, HAL_LCD_LINE_3); // LCD第三行显示 osal_memcpy(dispH, "Humidity:", 9); osal_memcpy(&dispH[9], humi, 6); HalLcdWriteString(dispH, HAL_LCD_LINE_4); // LCD第四行显示 //仅发送湿度的两位数据 if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc, SAMPLEAPP_PERIODIC_CLUSTERID, 2, humi, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { // Error occurred in request to send. }
这样就完成了终端的温湿度数据的LCD显示并且能够发送湿度数据,接下来配置协调器。同样在SampleApp.c文件中,找到SampleApp_MessageMSGCB()函数,修改为:
uint16 flashTime; switch ( pkt->clusterId ) { case SAMPLEAPP_P2P_CLUSTERID: break; case SAMPLEAPP_PERIODIC_CLUSTERID: HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); //输出接收到的数据 break; case SAMPLEAPP_FLASH_CLUSTERID: break; }
因为考虑到后续多个节点的加入,所以使用了组播通信,这样协调器便完成了将接收到的数据写入串口的功能。
这里将第二个终端设计为温度采集的功能,也可以换为其他传感模块,采集不同的环境数据,例如烟雾传感和光敏电阻传感。
具体操作:将DS18B20相关文件加入App目录中,此时需要配置另一个终端。在IAR界面中依次点击Project–Edit Configurations…–New,加入EndDeviceEB-2,Based on已有的终端配置,之后在App目录里添加已经编写好的第二个终端函数(可以按照SampleApp.c文件修改,重命名以区分)。最后在Workspace栏下选择新建的终端EndDeviceEB-2,在App目录中,右键SampleApp.c文件,点击Options,勾上Exclude from build,之后Rebuild All完成编译过程。
byte temp[6],data; char dispT[20]; data = ReadDs18B20(); //获取温湿度 //将温湿度的转换成字符串 temp[0] = data/10+48; temp[1] = data%10+48; temp[2] = ' '; temp[3] = 'C'; temp[4] = '\0'; if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc, SAMPLEAPP_PERIODIC_CLUSTERID, 2, temp, &SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else { // Error occurred in request to send. }
将对应程序下载至ZigBee设备后,将协调器通过USB转TLL模块连接至电脑(或者连接至树莓派,后续介绍),打开串口调试助手,比对LCD屏显示结果观察数据。
DHT11.c
#include <ioCC2530.h> #include "OnBoard.h" typedef unsigned char uchar; typedef unsigned int uint; #define DATA_PIN P0_7 void Delay_us(void); void Delay_10us(void); void Delay_ms(uint Time); void COM(void); void DHT11(void); //温湿度定义 uchar ucharFLAG,uchartemp; uchar shidu_shi,shidu_ge,wendu_shi,wendu_ge=4; uchar ucharT_data_H,ucharT_data_L,ucharRH_data_H,ucharRH_data_L,ucharcheckdata; uchar ucharT_data_H_temp,ucharT_data_L_temp,ucharRH_data_H_temp,ucharRH_data_L_temp,ucharcheckdata_temp; uchar ucharcomdata; //延时函数 void Delay_us(void) //1 us延时 { MicroWait(1); } void Delay_10us(void) //10 us延时 { MicroWait(12); } void Delay_ms(uint Time)//n ms延时 { unsigned char i; while(Time--) { for(i=0;i<100;i++) Delay_10us(); } } //温湿度传感 void COM(void) // 温湿写入 { uchar i; for(i=0;i<8;i++) { ucharFLAG=2; while((!DATA_PIN)&&ucharFLAG++); Delay_10us(); Delay_10us(); Delay_10us(); uchartemp=0; if(DATA_PIN)uchartemp=1; ucharFLAG=2; while((DATA_PIN)&&ucharFLAG++); if(ucharFLAG==1)break; ucharcomdata<<=1; ucharcomdata|=uchartemp; } } void DHT11(void) //温湿传感启动 { DATA_PIN=0; Delay_ms(20); //>18MS DATA_PIN=1; P0DIR &= ~0x80; //重新配置IO口方向 Delay_10us(); Delay_10us(); Delay_10us(); Delay_10us(); if(!DATA_PIN) { ucharFLAG=2; while((!DATA_PIN)&&ucharFLAG++); ucharFLAG=2; while((DATA_PIN)&&ucharFLAG++); COM(); ucharRH_data_H_temp=ucharcomdata; COM(); ucharRH_data_L_temp=ucharcomdata; COM(); ucharT_data_H_temp=ucharcomdata; COM(); ucharT_data_L_temp=ucharcomdata; COM(); ucharcheckdata_temp=ucharcomdata; DATA_PIN=1; uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp); if(uchartemp==ucharcheckdata_temp) { ucharRH_data_H=ucharRH_data_H_temp; ucharRH_data_L=ucharRH_data_L_temp; ucharT_data_H=ucharT_data_H_temp; ucharT_data_L=ucharT_data_L_temp; ucharcheckdata=ucharcheckdata_temp; } wendu_shi=ucharT_data_H/10; wendu_ge=ucharT_data_H%10; shidu_shi=ucharRH_data_H/10; shidu_ge=ucharRH_data_H%10; } else //没用成功读取,返回0 { wendu_shi=0; wendu_ge=0; shidu_shi=0; shidu_ge=0; } P0DIR |= 0x80; //IO口需要重新配置 }
DHT11.h
#ifndef __DHT11_H__ #define __DHT11_H__ #define uchar unsigned char extern void Delay_ms(unsigned int xms); //延时函数 extern void COM(void); // 温湿写入 extern void DHT11(void); //温湿传感启动 extern uchar temp[2]; extern uchar temp1[5]; extern uchar humidity[2]; extern uchar humidity1[9]; extern uchar shidu_shi,shidu_ge,wendu_shi,wendu_ge; #endif
DS18B20.c
#include"iocc2530.h" #include"OnBoard.h" #include "ds18b20.h" #define Ds18b20IO P0_7 //温度传感器引脚 void Ds18b20Delay(unsigned int k); void Ds18b20InputInitial(void); void Ds18b20OutputInitial(void); unsigned char Ds18b20Initial(void); void Ds18b20Write(unsigned char infor); unsigned char Ds18b20Read(void); //时钟频率为32M void Ds18b20Delay(unsigned int k) { while (k--) { asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); } } void Ds18b20InputInitial(void)//设置端口为输入 { P0DIR &= 0x7f; } void Ds18b20OutputInitial(void)//设置端口为输出 { P0DIR |= 0x80; } //ds18b20初始化 初始化成功返回0x00,失败返回0x01 unsigned char Ds18b20Initial(void) { unsigned char Status = 0x00; unsigned int CONT_1 = 0; unsigned char Flag_1 = 1; Ds18b20OutputInitial(); Ds18b20IO = 1; //DQ复位 Ds18b20Delay(260); //稍做延时 Ds18b20IO = 0; //单片机将DQ拉低 Ds18b20Delay(750); //精确延时 大于 480us 小于960us Ds18b20IO = 1; //拉高总线 Ds18b20InputInitial();//设置IO输入 while((Ds18b20IO != 0)&&(Flag_1 == 1))//等待ds18b20响应,具有防止超时功能 { //等待约60ms左右 CONT_1++; Ds18b20Delay(10); if(CONT_1 > 8000)Flag_1 = 0; Status = Ds18b20IO; } Ds18b20OutputInitial(); Ds18b20IO = 1; Ds18b20Delay(100); return Status; //返回初始化状态 } void Ds18b20Write(unsigned char infor) { unsigned int i; Ds18b20OutputInitial(); for(i=0;i<8;i++) { if((infor & 0x01)) { Ds18b20IO = 0; Ds18b20Delay(6); Ds18b20IO = 1; Ds18b20Delay(50); } else { Ds18b20IO = 0; Ds18b20Delay(50); Ds18b20IO = 1; Ds18b20Delay(6); } infor >>= 1; } } unsigned char Ds18b20Read(void) { unsigned char Value = 0x00; unsigned int i; Ds18b20OutputInitial(); Ds18b20IO = 1; Ds18b20Delay(10); for(i=0;i<8;i++) { Value >>= 1; Ds18b20OutputInitial(); Ds18b20IO = 0;// 给脉冲信号 Ds18b20Delay(3); Ds18b20IO = 1;// 给脉冲信号 Ds18b20Delay(3); Ds18b20InputInitial(); if(Ds18b20IO == 1) Value |= 0x80; Ds18b20Delay(15); } return Value; } //温度读取函数 unsigned char ReadDs18B20(void) { unsigned char V1,V2; //定义高低8位 缓冲 unsigned char temp; //定义温度缓冲寄存器 Ds18b20Initial(); Ds18b20Write(0xcc); // 跳过读序号列号的操作 Ds18b20Write(0x44); // 启动温度转换 Ds18b20Initial(); Ds18b20Write(0xcc); //跳过读序号列号的操作 Ds18b20Write(0xbe); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度 V1 = Ds18b20Read(); //低位 V2 = Ds18b20Read(); //高位 temp = ((V1 >> 4)+((V2 & 0x07)*16)); //转换数据 return temp; } //温度读取函数 带1位小数位 float floatReadDs18B20(void) { unsigned char V1,V2; //定义高低8位 缓冲 unsigned int temp; //定义温度缓冲寄存器 float fValue; Ds18b20Initial(); Ds18b20Write(0xcc); // 跳过读序号列号的操作 Ds18b20Write(0x44); // 启动温度转换 Ds18b20Initial(); Ds18b20Write(0xcc); //跳过读序号列号的操作 Ds18b20Write(0xbe); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度 V1 = Ds18b20Read(); //低位 V2 = Ds18b20Read(); //高位 //temp = ((V1 >> 4)+((V2 & 0x07)*16)); //转换数据 temp=V2*0xFF+V1; fValue = temp*0.0625; return fValue; }
DS18B20.h
#ifndef __DS18B20_H__ #define __DS18B20_H__ extern unsigned char Ds18b20Initial(void); extern unsigned char ReadDs18B20(void); extern float floatReadDs18B20(void); #endif