智能创客,中国最大的极客空间,智能平台,免费教学,视频教程,手把手教你创造儿时梦想!

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 27470|回复: 29
打印 上一主题 下一主题

WIFI作品DIY教程08-《智能开关》电灯开关、插座(nrf24l01/zigbee)

  [复制链接]

110

主题

396

帖子

2329

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2329
QQ
跳转到指定楼层
楼主
发表于 2015-1-14 13:58:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
上篇WIFI作品DIY教程07-《wifi家居网关》家居控制中心zigbee/nrf24l01等完成了家居网关。
这篇我们就教大家如何DIY智能开关,可以用来做电灯开关,也可以做插座开关,并这次是3路控制满足一般家庭使用了。



我们需要的配件:多路开关板nrf24l01(或zigbee等)

多路开关板的原理:网关nrf24l01或zigbee发送{ck0030001}到多路开关板,收到字符后判断0001则是0路开,0000则是0路关,0011则是1路开,0010则是1路关,0021则是2路开,0020则是2路关。多路开关板使用arduino控制继电器间接控制220v电路。


第一部分:下载编译源代码
1、安装CH340驱动

在drivers目录里找到CH340驱动,然后按说明安装(之前安装了就不用再安装了)。


2、源代码
[C] 纯文本查看 复制代码

/*
 *NRF24l01针脚连接线
 * MISO -> 12
 * MOSI -> 11
 * SCK -> 13
 * Configurable:
 * CE -> 8
 * CSN -> 7
*/
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <EEPROM.h>

int sid=3;//模块类型
int nid=0;//模块编号


//无线串口通信处理(zigbee/bluetooth等)
unsigned long serial1nowlast;
char serial1buff[129]={0};
char serial1Data;
int serial1i=0;

//NRF24l01
unsigned long nrf24l01nowlast;
char nrf24l01buff[33]={0};
char nrf24l01Data;
int nrf24l01i=0;


//声名变量
int pinIn0=3;
int pinIn1=4;
int pinIn2=5;

int val0;
int val1;
int val2;

int pinOut0=A0;
int pinOut1=A1;
int pinOut2=A2;

int state0=0;
int state1=0;
int state2=0;

void setup()
{
    Serial.begin(115200);

    char client[10]={0};//client
    sprintf(client,"clie%d",sid); 
    //初始化Mirf,用于NRF24l01收发
    Mirf_Init(0,client,sid);

    pinMode(pinIn0,INPUT);
    pinMode(pinIn1,INPUT);
    pinMode(pinIn2,INPUT);

    pinMode(pinOut0,OUTPUT);
    pinMode(pinOut1,OUTPUT);
    pinMode(pinOut2,OUTPUT);

    pinMode(pinIn0,INPUT_PULLUP); //将管脚设置为输入并且内部上拉模式
    pinMode(pinIn1,INPUT_PULLUP); //将管脚设置为输入并且内部上拉模式
    pinMode(pinIn2,INPUT_PULLUP); //将管脚设置为输入并且内部上拉模式 

    digitalWrite(pinIn0, HIGH);
    digitalWrite(pinIn1, HIGH);
    digitalWrite(pinIn2, HIGH);

    state0 = EEPROM.read(0);
    state1 = EEPROM.read(1);
    state2 = EEPROM.read(2);

    Serial.println("zwifi_kaiguan");

    Serial.print("state0=");
    Serial.print(state0);
    Serial.print("/state1=");
    Serial.print(state1);
    Serial.print("/state2=");
    Serial.println(state2);

    if(state0==255) state0=0;
    if(state1==255) state1=0;
    if(state2==255) state2=0;    

}

void loop()
{

  //检测无线串口数据处理 (zigbee/bluetooth等)
  {  
      unsigned long serial1now = millis();//获取现在的时间
      if(serial1now - serial1nowlast >= 5000)//如果数据间隔超过5秒而清空字符(为了防止数据错乱)
      { 
        serial1nowlast = millis(); 
        memset(serial1buff, 0, 129);
        serial1i=0;
      } 

      while( Serial.available() )//如果无线串口有数据
      {
        if(serial1i==0)
        {
          Serial.println("serial->");//打印出来方便调试
        }       
        serial1Data=(char)Serial.read();//读取串口数据
        //Serial.print(serial1Data);////这里不打印,否则检测到{ckxxxx}就认为是命令
        serial1buff[serial1i]=serial1Data;////保存到数组
        serial1i++;////数组长度+1
        if(serial1Data=='}' || serial1i>=129)//如果发现}而说明命令结束(并少于129个字符,太长会出错)
        {                
          serial1nowlast = millis(); //更新当前时间,不然5秒就超时了

          char body[129]={0};
          get_znck_body(serial1buff,body);//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式 
          //serial.println(body); 

          //如果命令格式真确则发送到无线串口
          if(strstr(body,"{ck") && strstr(body,"}") )
          { 
            //Serial.println(body);

            if(strlen(body)>10)
            {
              set_onoff(body);              

            }

          }
          serial1i=0;//字符长度为0
          Serial.println("-------------------");

          delay(100);
        }
      }

  }

  unsigned long nrf24l01now = millis();//获取现在的时间
  if(nrf24l01now - nrf24l01nowlast >= 5000)//如果数据间隔超过5秒而清空字符(为了防止数据错乱)
  { 
     nrf24l01nowlast = millis(); 
     memset(nrf24l01buff, 0, 33);
     nrf24l01i=0;
   }

   byte data[Mirf.payload];
   if(Mirf.dataReady()){//!Mirf.isSending() && 

    Mirf.getData(data);
    Mirf.rxFifoEmpty();   //清理24L01援存
    //Serial.println((char)*data);  

    for (int i = 0; i < Mirf.payload; i++) //把收到的信息拼起来
    {          
      if(nrf24l01i==0)
      {
        Serial.println("nrf24l01->");//打印出来方便调试
      }

      nrf24l01Data=(char)data[i];[/i]
      if( nrf24l01Data=='{') nrf24l01i=0;
      nrf24l01buff[nrf24l01i]=nrf24l01Data;//保存到数组
      nrf24l01i++;////数组长度+1
      if(nrf24l01Data=='}' || nrf24l01i>=33)//如果发现}而说明命令结束(并少于33个字符,太长会出错)
      {                
            nrf24l01nowlast = millis(); //更新当前时间,不然5秒就超时了

            char body[33]={0};
            get_znck_body(nrf24l01buff,body);//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式 
            //Serial.println(body); 

            //如果命令格式真确则发送到无线串口
            if(strstr(body,"{ck") && strstr(body,"}") )
            { 
              //Serial.println(body);

              if(strlen(body)>10)
              {
                  set_onoff(body);  

              }

            }
            memset(nrf24l01buff, 0, 33);
            nrf24l01i=0;//字符长度为0
            Serial.println("-------------------");

            delay(100);
      }
    }
   }    

  val0=digitalRead(pinIn0);//读取数字  
  if(val0==LOW)//检测按键是否按下
  {
    Serial.print("val0 state0=");
    Serial.println(state0);
    if(state0==0)
    {    
       digitalWrite(pinOut0,HIGH);
       state0=1;
       EEPROM.write(0, state0);
       delay(2000);
    }
    else
    { 
       digitalWrite(pinOut0,LOW);
       state0=0;
       EEPROM.write(0, state0);
       delay(2000);
    }
  }

  val1=digitalRead(pinIn1);//读取数字  
  if(val1==LOW)//检测按键是否按下
  {
    Serial.print("val1 state1=");
    Serial.println(state1);
    if(state1==0)
    {    
       digitalWrite(pinOut1,HIGH);
       state1=1;
       EEPROM.write(1, state1);
       delay(2000);
    }
    else
    { 
       digitalWrite(pinOut1,LOW);
       state1=0;
       EEPROM.write(1, state1);
       delay(2000);
    }
  }

  val2=digitalRead(pinIn2);//读取数字  
  if(val2==LOW)//检测按键是否按下
  {
    Serial.print("val2 state2=");
    Serial.println(state2);
    if(state2==0)
    {    
       digitalWrite(pinOut2,HIGH);
       state2=1;
       EEPROM.write(2, state2);       
       delay(2000);
    }
    else
    { 
       digitalWrite(pinOut2,LOW);
       state2=0;
       EEPROM.write(2, state2);
       delay(2000);
    }
  }



  //ON OFF SET
  if(state0==1)
  {
    digitalWrite(pinOut0,HIGH);
  }
  else
  {      
    digitalWrite(pinOut0,LOW);     
  }

  //ON OFF SET
  if(state1==1)
  {
    digitalWrite(pinOut1,HIGH);
  }
  else
  {      
    digitalWrite(pinOut1,LOW);     
  }

  //ON OFF SET
  if(state2==1)
  {
    digitalWrite(pinOut2,HIGH);
  }
  else
  {      
    digitalWrite(pinOut2,LOW);     
  }

}

//初始化Mirf 0初始化1为接收2为发送
void Mirf_Init(int txrx,char *server,int channel){
    //初始化Mirf,用于NRF24l01收发        
    if(txrx==0)  {     
      Mirf.spi = &MirfHardwareSpi;
      Mirf.init();
      Mirf.setRADDR((byte *)server);//设置接收地址
    }

    if(txrx==1)  {     
      Mirf.setRADDR((byte *)server);//设置接收地址
    }
    if(txrx==2)  {
      Mirf.setTADDR((byte *)server);//设置发送地址
    }

    Mirf.payload = sizeof(char);//收发字节
    Mirf.channel = channel;
    Mirf.config();
}

//NRF24l01发送函数
void Mirf_Send(int channel,char *server,char *str){
  Mirf_Init(2,server,channel);
  int bufi=0;
  for(bufi=0;bufi<strlen(str);bufi++){//循环发送
    char words=str[bufi];//发送的字符
    Mirf.send((byte *)&words);//发送命令
    while(Mirf.isSending()){//等待发送完闭
    }
    delay(50);//延时,否则可能出现发送丢失现象
    //Serial.print(words);
  }
  //Serial.println(""); 
}


//获取只是{ckxxxxxx}的字符,因为这是我们的命令格式 
void get_znck_body(char *p,char *s){

  char rechar[33]={0};
  int bufi=0;

  bool isend=false;
  int charnum=0;    

  for(bufi=0;bufi<strlen(p);bufi++){
    //Serial.print(p[bufi]);

    if(p[bufi]=='{'){
      isend=true;
    }
    if(p[bufi]=='}' && isend==true){
      isend=false;
      rechar[charnum]=p[bufi];
      break;
    }
    if(isend){
      if(charnum<33)
      {
        rechar[charnum]=p[bufi];//Serial.print(rechar[charnum]);
        charnum++;        
      }
    }

  }
  //Serial.println(""); 
  //memcpy(s,rechar,33);
  sprintf(s,"%s",rechar);
}


//
void set_onoff(char *body){

    int s=get_sid(body); 
    int n=get_nid(body);
    int d=get_data(body);

    if(  s==sid && n==0 )
    {
      if( d==1 )
      {
        state0=1;
        EEPROM.write(0, state0);         
      }
      if( d==0 )
      {
        state0=0;
        EEPROM.write(0, state0);          
      }
    }

    if(  s==sid && n==1 )
    {
      if( d==1 )
      {
        state1=1;
        EEPROM.write(1, state1);         
      }
      if( d==0 )
      {
        state1=0;
        EEPROM.write(1, state1);          
      }
    }

    if(  s==sid && n==2 )
    {
      if( d==1 )
      {
        state2=1;
        EEPROM.write(2, state2);         
      }
      if( d==0 )
      {
        state2=0;
        EEPROM.write(2, state2);          
      }
    }

    if(  s==sid ){
      char server[10]={0};//server
      sprintf(server,"serv%d",1);
      //Serial.println(server);

      char updateData[33]={0};
      char front[10]={0};
      //memcpy(front,body,9);
      sprintf(front," {ck%03d%03d",s,n);
      sprintf(updateData,"%supdate}",front);
      Serial.println(updateData);

      Mirf_Send(1,server,updateData);

      char client[10]={0};//client
      sprintf(client,"clie%d",sid);
      Mirf_Init(1,client,sid);
    }


}


int get_sid(char *buff){

  if( strstr(buff,"{ck") && strstr(buff,"}") && strlen(buff)>10)
    {
      char charSid[4]={0};
      memcpy(charSid,buff+3,3);
      Serial.println(charSid);
      int intSid=atoi(charSid);
      Serial.println(intSid);
      return intSid;      
    }
    else
    {
      return 0;
    }

}

int get_nid(char *buff){

  if( strstr(buff,"{ck") && strstr(buff,"}") && strlen(buff)>10)
    {
      char charNid[4]={0};
      memcpy(charNid,buff+6,3);
      Serial.println(charNid);
      int intNid=atoi(charNid);
      Serial.println(intNid);
      return intNid;      
    }
    else
    {
      return 0;
    }

}

int get_data(char *buff){

  if( strstr(buff,"{ck") && strstr(buff,"}") && strlen(buff)>10)
    {
      char charData[4]={0};
      memcpy(charData,buff+9,1);
      Serial.println(charData);
      int intData=atoi(charData);
      Serial.println(intData);
      return intData;      
    }
    else
    {
      return 0;
    }

}



值得注意的是,我们采用了EEPROM的3个字节做为记录上次的状态,就算断电再供电,还会是原来的开或闭状态!


刷写arduino程序选哪个板?
请选择板是Arduino Uno,并记得选对对应的串口。

刷写ardruino源代码时,提示库不存在?
请联系qq610854837下载zwifi资料,软件下载目录里的arduino-1.0.5,里面包含了教程使用的所有库。




最后下载程序到arduino多路开关板。




第二部分:测试多路开关板通信

打开:http://192.168.1.1/znck007/mysqltest.php?mode=select


如图填写数据,然天点击添加!数据就会插入到数据库,网关会自动获取当前状态等于0,然后发送到003这个模块!



点击查看数据库记录,会看到你添加的记录。




当刷新发现status=1的话,那么说明网关和多路开关模块通信就正常了。
如果status不等于1,然后num等于6(num是超时计数),那么通信不正常,请用串口检查哪里出现问题!

同时也可以用数据库软件Navicat for MySQL直接操作!




《WIFI作品DIY教程系列》
WIFI作品DIY教程01-《wifi开发板》介绍和联网等配置教程
WIFI作品DIY教程02-《openwrt摄像头》3D外壳和diy介绍
WIFI作品DIY教程03-《WIFI音响/MP3播放器/电台》
WIFI作品DIY教程04-《WIFI烟雾煤气报警器》
WIFI作品DIY教程05-《家居服务器》web server(php+mysql+uhttpd)
WIFI作品DIY教程06-《openwrt后台程序》控制mysql、串口通信等
WIFI作品DIY教程07-《wifi家居网关》家居控制中心zigbee/nrf24l01等
WIFI作品DIY教程08-《智能开关》电灯开关、插座(nrf24l01/zigbee)
WIFI作品DIY教程09-《人体红外检测》安防入侵报警功能WIFI作品DIY教程10-《温湿传感器》DS18B20、DHT11应用。


《Arduino开源智能家居DIY教程系列》
Arduino开源智能家居《花絮1》zigbee小底板DIY成功
Arduino开源智能家居《认识Zigbee》zigbee功能和自组网介绍
Arduino开源智能家居《zigbee开发板》手机/按键点亮LED
Arduino开源智能家居01《网关》升级版网关正式教程(zigbee)
Arduino开源智能家居02《温湿传感器》什么样温湿度才适居
Arduino开源智能家居03《开发板套件》学习zigbee家居-性价比高
Arduino开源智能家居04《插座开关》手机控制:网扇、空调...
Arduino开源智能家居05《红外线》手机红外线控制电器

《百元智能家居DIY教程系列》
《智能家居网关》DIY制作图文教程01-百元智能家居系列
《智能温湿度》DIY制作图文教程02-百元智能家居系列
《智能插座》DIY制作图文教程03-百元智能家居系列
《智能电灯开关》DIY制作图文教程04-百元智能家居系列
《手机红外线》DIY制作图文教程05-百元智能家居系列
关注@智能创客  微信:znck007(打造DIY创客平台)






分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 支持支持 反对反对
回复

使用道具 举报

0

主题

4

帖子

18

积分

新手上路

Rank: 1

积分
18
沙发
发表于 2015-1-14 17:48:42 | 只看该作者
我是初学者  我看完之后第一个感觉是 我知道要怎么做了 可问题来了 我需要买哪些东西呢?
希望楼主可以把需要买的东西来个淘宝链接
回复 支持 反对

使用道具 举报

110

主题

396

帖子

2329

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2329
QQ
板凳
 楼主| 发表于 2015-1-15 00:23:42 | 只看该作者
韩文博 发表于 2015-1-14 17:48
我是初学者  我看完之后第一个感觉是 我知道要怎么做了 可问题来了 我需要买哪些东西呢?
希望楼主可以把需 ...

你好呀。http://item.taobao.com/item.htm? ... &id=41584503200拍下这个联系我们旺旺就可以了。
回复 支持 反对

使用道具 举报

0

主题

8

帖子

114

积分

注册会员

Rank: 2

积分
114
地板
发表于 2015-1-16 16:37:03 | 只看该作者
编译不通过
回复 支持 反对

使用道具 举报

0

主题

8

帖子

114

积分

注册会员

Rank: 2

积分
114
5#
发表于 2015-1-16 16:41:23 | 只看该作者
#include
#include
#include
#include
这几个库文件没有?
回复 支持 反对

使用道具 举报

110

主题

396

帖子

2329

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2329
QQ
6#
 楼主| 发表于 2015-1-16 16:48:46 | 只看该作者
老催 发表于 2015-1-16 16:41
#include
#include
#include

编辑的时候可能文字丢失了,已重新更新了。
回复 支持 反对

使用道具 举报

110

主题

396

帖子

2329

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2329
QQ
7#
 楼主| 发表于 2015-1-16 16:48:51 | 只看该作者
老催 发表于 2015-1-16 16:41
#include
#include
#include

编辑的时候可能文字丢失了,已重新更新了。
回复 支持 反对

使用道具 举报

0

主题

10

帖子

60

积分

注册会员

Rank: 2

积分
60
8#
发表于 2015-3-3 19:55:44 | 只看该作者
zwifi+zigbee+多路开关板一直调试不通过
回复 支持 反对

使用道具 举报

110

主题

396

帖子

2329

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2329
QQ
9#
 楼主| 发表于 2015-3-4 10:32:52 | 只看该作者
坏的刚刚好 发表于 2015-3-3 19:55
zwifi+zigbee+多路开关板一直调试不通过

qq联系。
回复 支持 反对

使用道具 举报

0

主题

19

帖子

148

积分

注册会员

Rank: 2

积分
148
10#
发表于 2015-3-22 19:23:39 | 只看该作者
楼主请问下,开关的数据库数据是不是只有一条记录,而其他传感器是不是每几秒就更新一条数据上去,那样服务器端不会太过频繁访问数据库了?这样会不会造成容易奔溃之类的
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|手机版|智能创客 ( 桂ICP备14000828号

GMT+8, 2024-4-19 17:46 , Processed in 0.183926 second(s), 32 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表