基于ZIGBEE和ESP8266的智能生态系统(一)

前言

博主是利用两个zigbee作为终端分别采集不同区域的温湿度和光照数据,采集的数据与设定的阈值进行比较,再控制电机等进行自我调节,终端可利用点播方式将状态传至另一个作为协调器的zigbee,协调器再通过串口发至esp8266,8266收到正确数据后上传至机智云,手机上的机智云app即可以显示各地的状态(包括温湿度,阈值,电机状态)也可以远程控制。

设备准备

ZigBee用的是网蜂CC2530核心板,温湿度传感器用的是DHT11,光照用的是BH1750,电机等先用的是LED灯代替,之后用继电器控制,esp8266用的是ESP8266 NodeMcu。

ZigBee部分

博主是直接在温湿度的例程上修改的,因为原有的例程已经有了温湿度采集,所以只要将光照添加进去即可。

bh1750.c

static unsigned char IIC_Read_Byte(unsigned char ack)
{
   unsigned char i,receive=0;
	SDA_IN();//SDAéè???aê?è?
    for(i=0;i<8;i++ )
	{
        SCL=0; 
        Delay_us(2);
		SCL=1;
        receive<<=1;
        if(SDA)receive++;   
		Delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//·¢?ínACK
    else
        IIC_Ack(); //·¢?íACK   
    return receive;
}

/**************************************
向IIC总线发送一个字节数据
**************************************/
static void BH1750_SendByte(char dat)
{
  unsigned int i;
  SDA_OUT(); 
  SCL = 0;
  for (i=0; i<8; i++)         //8????
  {
    //dat <<= 1;              //????????
    if((dat&0X80)>>7)
    {
      SDA = 1; 
    }
    else
    {
      SDA = 0; 
    }//????
    dat<<=1;                //?????
    Delay_us(2);             //??
    SCL = 1; 
    Delay_us(2);
    SCL = 0;                //?????
    Delay_us(2);             //??
  }
	
}

void Single_Write_BH1750(unsigned char REG_Address)
{
    BH1750_Start();                  //起始信号
    BH1750_SendByte(SlaveAddress);   //发送设备地址+写信号
    while(IIC_Wait_Ack());
    BH1750_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf22页  
    while(IIC_Wait_Ack());
    BH1750_Stop();                   //发送停止信号
    Delay_ms(5);  
}


//*********************************************************
//
//连续读出BH1750内部数据
//
//*********************************************************
void Multiple_read_BH1750(void)
{
    unsigned char i;	
    BH1750_Start();                          //起始信号
    BH1750_SendByte(SlaveAddress+1);         //发送设备地址+读信号
    while(IIC_Wait_Ack());
    BUF[0] = IIC_Read_Byte(1); 
    BUF[1] = IIC_Read_Byte(0);  
    BH1750_Stop();                        
    Delay_ms(5);
}


//初始化BH1750,根据需要请参考pdf进行修改****
void Init_BH1750(void)
{
   P1SEL &= 0x80;
   P1SEL &= 0x40;
   SDA_OUT();
   SCL_OUT();
 
   Single_Write_BH1750(0x01);   // power on
   Single_Write_BH1750(0x10);   // H- resolution mode

   Delay_ms(180);              //延时180ms
}

int BH1750_READ(void)
{  
    float temp;
    int   data;
    
    Multiple_read_BH1750();       //连续读出数据,存储在BUF中
    
    data = BUF[0];
    data = (data<<8) | BUF[1];//合成数据 
    
    temp = (float)data/1.2;
    data = (int)temp;

    return data; 
}

bh1750.h

#define	SlaveAddress   0x46	//定义器件在IIC总线中的从地址,根据SA0地址引脚不同修改
#define SCL P1_6      //IIC时钟引脚定义
#define SDA P1_7      //IIC数据引脚定义

#define SDA_OUT()   P1DIR |= 0x80
#define SDA_IN()    P1DIR &= ~0x80
#define SCL_OUT()   P1DIR |= 0x40

BH1750主要用的是I2C通信,买模块的话卖家会给51的例程,其实差不多,我用的以前32上写的移植过来修改的。大家修改的话主要就是延时函数,还有IO口需要改,网蜂给了一些例程中也有I2C控制的传感器,看看就容易懂了。ZigBee的IO口配置主要就是这两个寄存器PXSEL和PXDIR。

然后进入SampleApp.c,在前面定义一些变量,详情看注释

#define LED   P1_4		
#define FAN   P1_5
#define open  1
#define close 0
int fan_start = 20;			//温度的阈值,超过就启动风扇
int led_start = 100;		//光照的阈值,低于就开启LED
unsigned char manual = 0;	//手动的标志

然后在SampleApp_Init中加入一些初始化,其余不变。

void SampleApp_Init( uint8 task_id )
{
  SampleApp_TaskID = task_id;
  SampleApp_NwkState = DEV_INIT;
  SampleApp_TransID = 0;
  
  MT_UartInit();//串口初始化
  MT_UartRegisterTaskID(task_id);//登记任务号
  HalUARTWrite(0,"Hello World\n",12); //(串口0,'字符',字符个数。)
  P0SEL &= 0xbf;	//温湿度IO
  P1SEL &= 0x30;	//继电器IO P1.4,1.5
  P1DIR |= 0x30;	//继电器IO输出
  LED = close;		//初始化时关闭
  FAN = close;		//初始化时关闭
  Init_BH1750();	//光照初始化
  .............

接着在周期事件中,每五秒采一次数据发送至协调器。

if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
  {
    int light;
    int temp, humidity;
    uint8 buf[30];     //温度+提示符 
    DHT11();   //温度检测   
    temp = wendu_shi*10 + wendu_ge;
    humidity = shidu_shi*10 + shidu_ge;
    light = BH1750_READ();
    if (light > 255)	//设置一个上限
    {
      light = 255;
    }
    
    if (manual == 0)	//若是自动
    {
        if (light <= led_start)
        {
            LED = open;
        }
        
        else
        {
            LED = close;
        }
        
        if (temp >= fan_start)
        {
            FAN = open;
        }
        
        else
        {
            FAN = close;
        }  
    }
    
    sprintf(buf, "@A%d%d%d#%d#%d#%d#%d#", LED, FAN, temp, humidity, light, fan_start, led_start);
    SampleApp_SendPointToPointMessage(buf);//点播函数

    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
        (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

    // return unprocessed events
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }

这里主要就是在原有基础上加入了光照,然后将数据存入buf中发送,@A%d%d%d#%d#%d#%d#%d#,是数据的格式,A代表着区域名,即A点,后两位是继电器状态,紧接着温湿度和光照等,由于数据时变化的,所以这些用#分开判断。@是我设置的一个帧头,不设置帧头数据可能会错误,这是博主在调试时候发现的一个bug。不知道为什么当协调器收到8266发过来的数据时,过长的数据好像会打印出来,为了避免8266接收到错误数据,所以设置了一个帧头,不然8266很容易进入异常。

接下来看到case SAMPLEAPP_POINT_TO_POINT_CLUSTERID:

 case SAMPLEAPP_POINT_TO_POINT_CLUSTERID:
      
      HalUARTWrite(0,&pkt->cmd.Data[0],strlen(pkt->cmd.Data));	//调试用
      HalUARTWrite(0,"\n",1);
      if (!strcmp(pkt->cmd.Data, "manual!"))	//开启手动模式
      {
          manual = open;
      }
      
      else if (!strcmp(pkt->cmd.Data, "auto!"))		//开启自动模式
      {
          manual = close;
      }
      
      if (!strcmp(pkt->cmd.Data, "A_LED_ON!") && (manual == open))
      {
          LED = open;
      }
      
      else if (!strcmp(pkt->cmd.Data, "A_LED_OFF!") && (manual == open))
      {
          LED = close;
      }
      
      else if (!strcmp(pkt->cmd.Data, "A_FAN_ON!") && (manual == open))
      {
          FAN = open;
      }
      
      else if (!strcmp(pkt->cmd.Data, "A_FAN_OFF!") && (manual == open))
      {
          FAN = close;
      }
      
      else if (!strncmp(pkt->cmd.Data, "A_LED_START:", 12))
      {
          led_start = extract(pkt->cmd.Data + 12);
      }
      
      else if (!strncmp(pkt->cmd.Data, "A_FAN_START:", 12))
      {
          fan_start = extract(pkt->cmd.Data + 12);
      }

      break;

这里又有一个注意点,协调器发过来的数据中,最后默认都有一个!号,如果知道的朋友也可以告诉我一下为啥,我这里就软件处理了一下。如果是手动模式的话就可以机智云远程控制LED和风扇,此时关闭自动调节。
else if (!strncmp(pkt->cmd.Data, “A_LED_START:”, 12))
{
led_start = extract(pkt->cmd.Data + 12);
}
这个是接收阈值的改变,手动自动只是控制LED这些设备,因为数据后有个!而且发过来的是字符,所以自己写了一个函数,将需要的数据提取出来。

uint16 mypow(uint16 x, uint16 y)
{
  if (y == 0)
  {
    return 1;
  }
  
  while(--y)
  {
    x *= x;
  }
    
  return x;
}

uint16 extract(uint8 *buf)
{
  uint8 *temp = buf;
  uint16 num = 0;
  uint16 data = 0;
  while(*buf++ != '!')
  {
    num++;
  }

  while(num--)
  {
    data += ((*temp++) - '0') * mypow(10,num);
  }
  
  return data;
}

至此终端部分大致完成,下一篇会讲协调器部分。这个小项目只是一个简单的模型,没有做的特别的完善,大家可以根据需求增添自己的idea,博主也是小白,欢迎大佬指点。

  • 10
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
本文首发于DF创客社区作者:2877137721 原文链接: DIY属于你的智能家居系统,zigbee,esp8266,51单片机 DIY家庭智能家居控制系统(2)51,zigbeeesp8266 相关附件于原文下方下载 【介绍】 随着微功耗处理器以及通讯芯片的发展,以往较为耗能的有线通讯方式越来越阻碍了通讯网络的发展,于是一大批的无线通讯方案应运而生,例如NBIOT,蓝牙4.0,zigbee等等。同时微功耗无线处理器的流行使得传统家电带上了智能的色彩,智能家居必将是未来家庭的必备。某些高科技企业也在揶揄这块市场,纷纷推出了自家的智能家居解决方案,比较知名的有米家方案以及阿里智能的解决方案。但是回到现实的使用上来说,每个家庭的条件环境其实不一样,同样的产品未必在每个家庭上都可以使用方便,所以个性化的定制产品才可以更好的方便我们的生活。 于是在暑假期间,萌生了DIY一套智能家居方案的想法,具有各种智能开关和传感器等节点,并且对接物联平台实现联网控制以及数据的上传。由于家庭中将会使用到的智能设备种类繁多,所以我将采用模块化的设计思路,即采用核心板加外围功能部分的思路,像搭积木一样的构建各个智能设备。大家有同样想制作的想法可以参考。 截至发帖前,我完成了智能网关,智能墙壁开关,无线遥控开关以及无线气象站的设计制作,之后有新的设备加入的话,我会及时的更新。 【准备事项】 完成这个涉及到多方面的项目,需要的硬件设备以及开发环境较多,所以我先大概给出一个列表: 软件篇: ArduinoIDE:用于给ESP8266编程使用 KEIL uVision5 :用于给51单片机编程使用 串口调试器:用于监控单片机输出数据 lceda设计软件:绘制电路原理图,设计PCB电路板 硬件篇: NodeMCU开发板一块 亿佰特zigbee模块若干(视节点数量而定) STC8F2系列单片机若干 核心的主要控制器件在此列出,其他元器件会在制作过程中一一说明。 【制作过程】 我构想了一张智能家庭的网络拓扑图,大家可以欣赏以下,后期图上的设备都将加入进来: 由于涉及到多个设备的设计制作,所以本个报名贴先奉上智能家居核心板,智能网关以及无线气象站的制作过程: #制作过程之核心板篇# >>>本项目使用zigbee网络进行智能家居之间的通信。 好早之前就接触过zigbee组网,对于这种低成本低功耗的网络还是抱有很大信心的。这里讲解选择这个网络的几大理由: mesh结构的网络很适合智能家居的控制结构,在入网的任何一个节点都可以访问到所有节点的数据,这点很适合网关控制各个设备。 低功耗使得终端设备甚至可以采用电池供电,使得所有的模组都尽量可能的无线化。 多跳传输,无线方案中最大的问题就是数据发送的不稳定以及障碍物对信号的遮挡导致数据无法正确传输,而ZigBee的多跳恰好解决了这个问题,节点会自动选择优质的传输路线多跳传输,保证信号质量。 总结一下:zigbee网络确实是好,但是对于我这种比较懒惰的人并不想去学习那复杂的传输理论以及zigbee通讯芯片的编程,于是我选择上网购买ZigBee模块,最后选择了一种小型的串口转zigbee模块,比较方便单片机通讯。 说到模块化,那么就需要核心的控制板。本质来说就是将单片机以及购买的zigbee模块集成到一张电路板上,并且预留各种接口,方便后期移植到各种设备上,这样一张电路板就可以适用各种智能家居设备了。 在保证功能足够的同时,体积也是我需要考虑的问题,如果核心板做的过大,会导致无法安装到某些空间狭小的智能设备中,所以小体积是我所着重考虑的。 基于多方面考虑之后,stc8F2k08s2进入了我的视线,小巧的sop16封装以及简单的外围电路,足够的IO口(14个)。这款芯片成为了核心板的控制单片机。于是一番绘制原理图以及PCB之后,成品大概明朗了: 焊接好的成品如下: 这将会成为以后所有我的智能家居方案的核心控制板。 #制作过程之智能网关篇# 完成了核心板的制作,网关成为了下一个比较关注的对象,因为家中的所有智能设备的控制以及通讯都会由他来完成,包括链接到互联网上传数据,所以说对于网关的硬件选取也是重中之重。上联互联网,下接zigbee小型通讯网,网关担任了一个家庭控制中心的角色,对于它的选择我认为esp8266是个不错的方案,可以支持arduino ide编程,这对于不太了解网络通讯协议的我来说是个好消息,因为在arduino的编程中,我可以借助强大的库函数来完成我想要的功能。 ESP8266是一个拥有了近80Mhz的主频的32位处理器,内置了wifi模组省去了网线,并且拥有丰富的外设以及较高的性能,可以胜任智能网关的工作。当然,近期乐鑫发布的ESP32系列芯片也会是个好的选择,更高的主频以及wifi蓝牙双模的设计让其拥有更加方便的接

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值