用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

点击进入授权页面

只需一步,快速开始

  • QQ空间
  • 回复
  • 收藏
  • TA的每日心情
    开心
    2018-4-22 09:39
  • 签到天数: 391 天

    [LV.9]以坛为家II

    本帖最后由 单片机菜鸟 于 2017-10-26 09:34 编辑

    一、前言
        楼主研究了几天ESP8266,慢慢对它有一定的了解。之前也写了几篇帖子,仅仅是介绍了基本使用方法。这次我们直接做个实际的小系统,我把它命名为《局域网:ESP8266+路由+RGB彩灯+App》,算是巩固一下所学的知识。
        在这里我们用到了不少知识,大家可以参考以下博文:
        1.ESP8266简介 参考 博哥玩物联网系列1-ESP8266基础知识
       2.蓝牙彩灯 参考 《博哥玩Arduino》- 蓝牙七彩灯基础版
        3.ArduinoJson库 参考 博哥玩物联网系列2-ArduinoJson库
          接下来先上最终的效果,有图有真相:
        5Y6B)A`@GRMBI784])IXGT0.png
        http://v.youku.com/v_show/id_XMzAyNjEwMTMwOA==.html?spm=a2h3j.8428770.3416059.1

          帖子视频看不了的话  直接点这个 链接
    二、设计思路
       
        这里的局域网,楼主理解为手机、ESP8266均连接同一个路由wifi,然后8266是作为服务端,手机作为客户端,手机再通过wifi给8266发送数据,8266接收到数据再把数据分发给Arduino,然后Arduino解析协议数据以达到控制效果。
        设计图如下:
        IMG_1632.JPG

    三、撸代码


       代码烧写分为两个部分:
        1.先烧写代码到ESP8266 烧写方法参考 《博哥ESP8266系列1》- Arduino IDE for esp8266
        代码如下(直接看代码注释):
       
    /**
    * 日期:2017/09/14
    * 功能:wifi lamp 8266端
    * 作者:单片机菜鸟
    **/
    #include <ESP8266WiFi.h>

    #define MAX_SRV_CLIENTS 3   //最大同时联接数,即你想要接入的设备数量,8266tcpserver只能接入五个,哎
    #define led 2
      
    const char* ssid     = "360wifilulu";         // XXXXXX -- 使用时请修改为当前你的 wifi ssid
    const char* password = "6206908you11011010";         // XXXXXX -- 使用时请修改为当前你的 wifi 密码
      
    const unsigned long BAUD_RATE = 115200;                   // serial connection speed
    const unsigned long HTTP_TIMEOUT = 5000;               // max respone time from server
      
    WiFiServer server(8266);//你要的端口号,随意修改,范围0-65535
    WiFiClient serverClients[MAX_SRV_CLIENTS];
      
    /**
    * @Desc 初始化操作
    */
    void setup() {
      WiFi.mode(WIFI_AP_STA);     //设置esp8266 工作模式
      Serial.begin(BAUD_RATE);
      pinMode(led,OUTPUT);
      digitalWrite(led, HIGH);
      delay(2000);//刚启动模块的话 延时稳定一下
      Serial.println();
      Serial.println();
      Serial.print("Connecting to ");//写几句提示,哈哈
      Serial.println(ssid);
      WiFi.begin(ssid, password);   //连接wifi
      while (WiFi.status() != WL_CONNECTED) {
        //这个函数是wifi连接状态,返回wifi链接状态
        delay(500);
        Serial.print(".");
      }
      Serial.println("");
      Serial.println("WiFi connected");
      delay(500);
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());//WiFi.localIP()返回8266获得的ip地址
      server.begin();
      server.setNoDelay(true);  //加上后才正常些
    }
      
    /**
    * @Desc  主函数
    */
    void loop() {
      uint8_t i;
      if (server.hasClient()){
            for (i = 0; i < MAX_SRV_CLIENTS; i++){
                if (!serverClients || !serverClients.connected()){
                    if (serverClients) serverClients.stop();//未联接,就释放
                    serverClients = server.available();//分配新的
                    continue;
                }
            }
            //8266tcpserver只能接入五个  超出的需要释放
            WiFiClient serverClient = server.available();
            if (serverClient){
              serverClient.stop();
            }
      }
      
      for (i = 0; i < MAX_SRV_CLIENTS; i++){
            if (serverClients && serverClients.connected()){
                //处理客户端发过来的数据
                if (serverClients.available()){
                    while (serverClients.available())
                        Serial.write(serverClients.read());
                }
            }
       }
    }


          这里代码功能其实就是把8266当做服务端,8266连接上路由wifi,然后监听连接进来的客户端(这里是手机),正常情况下烧写运行成功打开串口会有如下打印信息:
        %X4P@)UC7@WS1FIOHE@(_E3.png
          这里有我们手机端需要用到的IP地址,端口号固定为8266;
        当然,你也可以直接去你的wifi路由去查找分配的IP地址

        2.烧写代码到Arduino(楼主这里是Mega2560)
         代码如下:
          
    /**
    * 日期:2017/09/14
    * 功能:wifi lamp arduino端
    * 作者:单片机菜鸟
    **/
    #include <SoftwareSerial.h>
    #include <ArduinoJson.h>
      
    const unsigned long BAUD_RATE = 115200;                   // serial connection speed
    const size_t MAX_CONTENT_SIZE = 50;
    const size_t t_bright=1,t_color=2,t_frequency=3,t_switch=4;

    //#define UNO      //uncomment this line when you use it with UNO board
    #define MEGA    //uncomment this line when you use it with MEGA board

    #ifdef UNO
    SoftwareSerial mySerial(10,11);
    #endif
      
    #ifdef UNO
    #define WifiSerial  Serial
    #define MyDebugSerial mySerial
    #endif
       
    #ifdef MEGA
    #define WifiSerial Serial1
    #define MyDebugSerial Serial
    #endif  

    //该条语句用于使能DEBUG输出信息,屏蔽掉就不会输出debug调试信息
    #define DEBUG
    //该条语句用于使能是共阴RGB  屏蔽掉就是共阳RGB
    //#define COMMON_GND

    #ifdef DEBUG
    #define DBGLN(message)    MyDebugSerial.println(message)
    #else
    #define DBGLN(message)
    #endif

    #ifdef UNO
    #define PIN_RED 3 //red 引脚
    #define PIN_GREEN 5 //green 引脚
    #define PIN_BLUE 6 //blue 引脚
    #define PIN_ENABLE 9  //使能引脚 pwm控制亮度
    #else
    #define PIN_RED 2
    #define PIN_GREEN 3
    #define PIN_BLUE 4
    #define PIN_ENABLE 5  
    #endif

    int red = 0;//红色
    int green = 0;//绿色
    int blue = 0;//蓝色

    int frequency = 1;//频率
    int switch_status = 1;//关闭 or 开启
    int bright = 1;//亮度

    int type = 4;//当前模式 1亮度 2颜色 3呼吸 4开关
    char response[MAX_CONTENT_SIZE];
    int fadeValue = 0;//当前亮度
    bool isAdd = true;//是否是从暗到亮
      
    /**
    * @Desc 初始化操作
    */
    void setup() {
      pinMode(PIN_RED, OUTPUT);
      pinMode(PIN_GREEN, OUTPUT);
      pinMode(PIN_BLUE, OUTPUT);
      pinMode(PIN_ENABLE, OUTPUT);
      
      WifiSerial.begin(BAUD_RATE);
      #ifdef DEBUG
        #ifdef UNO
          MyDebugSerial.begin(9600);//软串口9600稳定
        #else
          MyDebugSerial.begin(BAUD_RATE);
        #endif
      #endif
      DBGLN("Arduino Init End");
    }
      
    /**
    * @Desc  主函数
    */
    void loop() {
      if(WifiSerial.available()>0){
        clrEsp8266ResponseBuffer();
        int data_size = ReceiveMessage(response, sizeof(response));
        if(data_size>0){
          //开始解析数据
          parseData(response);
        }
      }

      if(type == t_frequency){
        //呼吸灯效果
        breatheRGB(frequency);
      }
      
    }

    /**
    * 读取串口缓冲区里面的数据
    */
    int ReceiveMessage(char* content, size_t maxSize){
      //不用 readBytes 因为比较耗时
      size_t length = WifiSerial.readBytesUntil('}',content, maxSize);
      content[length] = '}';
      content[++length] = 0;
      DBGLN(content);
      return length;
    }

    /**
         * @Desc 解析json
         * 有三种
         * 1.亮度控制页面(0 暗 1正常 2亮)
         * {
         *     "t": 1,
         *     "bb": 2
         * }
         * 2.颜色控制页面
         * {
         *     "t": 2,
         *     "cr": 154,
         *     "cg": 147,
         *     "cb": 255
         * }
         * 3.呼吸灯控制页面(0 慢呼吸 1正常 2快)
         * {
         *    "t": 3,
         *    "gf": 1
         * }
         * 4.开关控制(0关闭 1开启)
         * {
         *    "t": 4,
         *    "ss": 1
         * }
         **/
    bool parseData(char* content) {
    //    -- 根据我们需要解析的数据来计算JSON缓冲区最佳大小
    //   如果你使用StaticJsonBuffer时才需要
    //    const size_t BUFFER_SIZE = 1024;
    //   在堆栈上分配一个临时内存池
    //    StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
    //    -- 如果堆栈的内存池太大,使用 DynamicJsonBuffer jsonBuffer 代替
      DynamicJsonBuffer jsonBuffer;
       
      JsonObject& root = jsonBuffer.parseObject(content);
       
      if (!root.success()) {
        Serial.println("JSON parsing failed!");
        return false;
      }
       
      type = root["t"];
      switch(type){
        case t_bright:
             bright = root["bb"];
             brightRGB(bright);
             break;
        case t_color:
             red = root["cr"];
             green = root["cg"];
             blue = root["cb"];
             colorRGB(red,green,blue);
             break;
        case t_frequency:
             frequency = root["gf"];
             break;
        case t_switch:
             switch_status = root["ss"];
             bool enable = switch_status == 1;
             switchRGB(enable);
             break;     
      }
      return true;
    }

    /**
    * 控制灯亮度
    */
    void brightRGB(int bright){
      int level = bright%3;
      int bright_level;
      switch(level){
        case 0://暗  50
          bright_level = 50;
          break;
        case 1://正常 100
          bright_level = 100;
          break;
        case 2://亮  200
          bright_level = 200;
          break;
      }
        #ifdef COMMON_GND
         //共地
         analogWrite(PIN_ENABLE,bright_level);
        #else
         analogWrite(PIN_ENABLE,255-bright_level);
        #endif
    }

    /**
    * 控制RGB颜色
    */
    void colorRGB(int red, int green, int blue){
      #ifdef COMMON_GND
         analogWrite(PIN_RED,constrain(red,0,255));
         analogWrite(PIN_GREEN,constrain(green,0,255));
         analogWrite(PIN_BLUE,constrain(blue,0,255));
      #else
         analogWrite(PIN_RED,constrain(255-red,0,255));
         analogWrite(PIN_GREEN,constrain(255-green,0,255));
         analogWrite(PIN_BLUE,constrain(255-blue,0,255));
      #endif
    }

    /**
    * 控制亮灭
    */
    void switchRGB(bool enable){
      if(enable){
        //打开
        #ifdef COMMON_GND
         //共地
         analogWrite(PIN_ENABLE,255);
        #else
         analogWrite(PIN_ENABLE,0);
        #endif
      }else{
        //关闭
        #ifdef COMMON_GND
         //共地
         analogWrite(PIN_ENABLE,0);
        #else
         analogWrite(PIN_ENABLE,255);
        #endif
      }
    }

    /**
    * 呼吸灯
    */
    void breatheRGB(int frequency){
      int level = frequency%3;
      int f_level;
      switch(level){
        case 0://慢  50
          f_level = 3;
          break;
        case 1://正常 100
          f_level = 10;
          break;
        case 2://快  200
          f_level = 20;
          break;
      }
      if(isAdd){
        //递增方向
         fadeValue +=f_level;
         if(fadeValue>=255){
           fadeValue = 255;
           isAdd =false;
         }
      }else{
        //递减方向
        fadeValue -=f_level;
         if(fadeValue<=0){
           fadeValue = 0;
           isAdd =true;
         }
      }
      analogWrite(PIN_ENABLE,fadeValue);
      delay(20);
    }

    void clrEsp8266ResponseBuffer(void){
        memset(response, 0, MAX_CONTENT_SIZE);      //清空
    }


        具体的代码功能请直接看注释,无非就是收到8266通过串口发过来的数据然后根据协议解析。楼主这里是用到了Mega2560的串口1来和8266通信,串口0用来打印调试信息。


        当以上两个步骤做完,并且连接好硬件之后,我们就可以用我们的app控制了,前提手机也连入了路由wifi。
        至于App 协议数据的介绍,以前帖子有详细介绍,可以参考 《博哥玩Arduino》Wifi版本 彩灯
       
          LU_EFK(25`]}8JI(Y5}GU7K.png Q}XBDH6@IB?L@2DU{IJHM.png C2V8AL$$`VOKAVXJLBN@K@G.png 9@B]0`6U7X811S3(D%BYU.png U~DSPBY6PULJN3H@YZI`5.png


         正常情况下,串口调试窗口会打印以下数据:
           Z2KFNKD74N7F)8TT9JX]1ZI.png


          注意:最后下载到板子的时候,最好把调试信息去掉,会影响到解析速度。注释掉 #define DEBUG


          最后附上APP下载地址: 下载

            APP源码下载地址
    游客,如果您要查看本帖隐藏内容请回复









    打赏作者鼓励一下!
    楼主做好冷板凳
    打赏作者鼓励一下!
    赞!很棒的教程!可以加个好友吗?
    如果觉得对你有所帮助的话可以打赏一下我哦(~ ̄▽ ̄)~
    博哥666666
    诚哥崽 发表于 2017-9-16 12:07
    赞!很棒的教程!可以加个好友吗?

    哈哈哈  在我这里没什么不可以
    打赏作者鼓励一下!

    一般6666 都要附上点赞
    打赏作者鼓励一下!
    很好,学习了
    好东西,谢谢
    不错的帖子,赞
    发表评论
    高级模式  
    您需要登录后才可以回帖 登录 | 立即注册  
    关闭

    推荐主题 上一条 /2 下一条