这一篇,博主将教你们怎么去实现一个WiFi RGB彩灯。
先来一个博主已经实现功能的图片,以下:html
固然,博主也拍了运行视频,请点击 传输门。android
本篇须要用到如下知识点:git
这里的局域网,博主理解为手机、ESP8266均链接同一个路由wifi,而后8266是做为服务端,手机做为客户端,手机再经过wifi给8266发送数据,8266接收到数据再把数据分发给Arduino,而后Arduino解析协议数据以达到控制效果。
设计图以下:
github
咱们本应用须要分红两个部分的设计——Mega2560 Arduino端以及ESP8266端。须要分别往两块板子烧录代码以及链接电路。json
往8266烧入如下代码:服务器
/** * 日期:2019/02/18 * 功能:wifi lamp 8266端 * 加入SmartConfig功能 * 做者:单片机菜鸟 **/ #include <ESP8266WiFi.h> #define MAX_SRV_CLIENTS 3 //最大同时联接数,即你想要接入的设备数量,8266tcpserver只能接入五个,哎 #define LED 2 #define DEBUG //是否开启debug功能 #ifdef DEBUG #define DebugPrintln(message) Serial.println(message) #else #define DebugPrintln(message) #endif #ifdef DEBUG #define DebugPrint(message) Serial.print(message) #else #define DebugPrint(message) #endif const unsigned long BAUD_RATE = 115200;// serial connection speed WiFiServer server(8266);//你要的端口号,随意修改,范围0-65535 WiFiClient serverClients[MAX_SRV_CLIENTS]; int flag = HIGH;//默认当前灭灯 /** * @Desc 初始化操做 */ void setup() { Serial.begin(BAUD_RATE); pinMode(LED,OUTPUT); digitalWrite(LED, HIGH); if(!autoConfig()){ smartConfig(); DebugPrint("Connecting to WiFi");//写几句提示,哈哈 while (WiFi.status() != WL_CONNECTED) { //这个函数是wifi链接状态,返回wifi连接状态 delay(500); DebugPrint("."); } } delay(1000); digitalWrite(LED, LOW); DebugPrintln("IP address: "); DebugPrintln(WiFi.localIP());//WiFi.localIP()返回8266得到的ip地址 server.begin(); server.setNoDelay(true); //加上后才正常些 //使能软件看门狗的触发间隔 ESP.wdtEnable(5000); } /** * @Desc 主函数 */ void loop() { uint8_t index; if (server.hasClient()){ for (index = 0; index < MAX_SRV_CLIENTS; index++){ if (!serverClients[index] || !serverClients[index].connected()){ if (serverClients[index]) serverClients[index].stop();//未联接,就释放 serverClients[index] = server.available();//分配新的 continue; } } //8266tcpserver只能接入五个 超出的须要释放 WiFiClient serverClient = server.available(); if (serverClient){ serverClient.stop(); } } for (index = 0; index < MAX_SRV_CLIENTS; index++){ if (serverClients[index] && serverClients[index].connected()){ //处理客户端发过来的数据 if (serverClients[index].available()){ while (serverClients[index].available()) //把数据发送给mega Serial.write(serverClients[index].read()); } } } if(Serial.available()>0){ char ch = Serial.read(); //收到ardunio发过来的进入smartconfig模式的命令 if(ch == '1'){ smartConfig(); delay(1000); digitalWrite(LED, LOW); DebugPrintln("IP address: "); DebugPrintln(WiFi.localIP());//WiFi.localIP()返回8266得到的ip地址 } } //喂狗 ESP.wdtFeed(); } /** * 自动链接20s 超过以后自动进入SmartConfig模式 */ bool autoConfig(){ WiFi.mode(WIFI_AP_STA); //设置esp8266 工做模式 WiFi.begin(); delay(2000);//刚启动模块的话 延时稳定一下 DebugPrintln("AutoConfiging ......"); for(int index=0;index<20;index++){ int wstatus = WiFi.status(); if (wstatus == WL_CONNECTED){ DebugPrintln("AutoConfig Success"); DebugPrint("SSID:"); DebugPrintln(WiFi.SSID().c_str()); DebugPrint("PSW:"); DebugPrintln(WiFi.psk().c_str()); return true; }else{ DebugPrint("."); delay(1000); flag = !flag; digitalWrite(LED, flag); } } DebugPrintln("AutoConfig Faild!"); return false; } /** * 开启SmartConfig功能 */ void smartConfig() { WiFi.mode(WIFI_STA); delay(2000); DebugPrintln("Wait for Smartconfig"); // 等待配网 WiFi.beginSmartConfig(); while (1){ DebugPrint("."); delay(500); flag = !flag; digitalWrite(LED, flag); if (WiFi.smartConfigDone()){ //smartconfig配置完毕 DebugPrintln("SmartConfig Success"); DebugPrint("SSID:"); DebugPrintln(WiFi.SSID().c_str()); DebugPrint("PSW:"); DebugPrintln(WiFi.psk().c_str()); WiFi.mode(WIFI_AP_STA); //设置esp8266 工做模式 WiFi.setAutoConnect(true); // 设置自动链接 break; } } }
整个代码的流程是这样的:网络
这里代码功能其实就是把8266当作服务端,8266链接上路由wifi,而后监听链接进来的客户端(这里是手机)app
读者安装好app以后,会看到以下的手机配置页面,请一步步设置:tcp
若是提示失败,通常都是由于你的8266模块并无进入到SmartConfig模式,能够尝试重启一下。再者就是,smartconfig不保证配网成功率100%;函数
烧写如下代码到mega2560板子,代码以下:
/** * 日期:2019/02/18 * 功能: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控制亮度 #define PIN_KEY 7// 按键 #else #define PIN_RED 2 #define PIN_GREEN 3 #define PIN_BLUE 4 #define PIN_ENABLE 5 #define PIN_KEY 6 #endif int red = 0,green = 0,blue = 0; int type = 4;//当前模式 1亮度 2颜色 3呼吸 4开关 int frequency = 1;//频率 int switch_status = 1;//关闭 or 开启 int bright = 1;//亮度 char response[MAX_CONTENT_SIZE]; int fadeValue = 0;//当前亮度 bool isAdd = true;//是不是从暗到亮 // 定义记录按键当前状态的变量 int state_btn; // 定义记录按键最近一次状态变化的变量,并初始化状态为LOW。 int lastButtonState = LOW; // 定义记录最近一次抖动的时间变量,并初始化时间为0毫秒。 long lastDebounceTime = 0; // 定义延迟抖动的时间变量 long debouncdDelay = 60; /** * @Desc 初始化操做 */ void setup() { pinMode(PIN_RED, OUTPUT); pinMode(PIN_GREEN, OUTPUT); pinMode(PIN_BLUE, OUTPUT); pinMode(PIN_ENABLE, OUTPUT); pinMode(PIN_KEY,INPUT); 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); } checkButton(); } /** * 读取串口缓冲区里面的数据 */ 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 checkButton(){ int buttonState = digitalRead(PIN_KEY);//读取当前按键状态 if(buttonState != lastButtonState){ //若是按键发生了变化 则从新设置最近一次抖动的时间 //方法millis()能够获取当前时间,单位统一为毫秒。 lastDebounceTime = millis(); } // 判断按键按下状态时间间隔是否大于延迟抖动的时间长度。 if(millis()-lastDebounceTime>debouncdDelay){ // 判断当前的按键状态是否和以前有所变化 if(buttonState != state_btn){ // 若是发生了变化, // 则更新按键状态变量。 state_btn = buttonState; if(state_btn == HIGH){ //再次确认是否真的按下了按键 DBGLN("smartconfig"); WifiSerial.write('1'); } } } // 更新按键最近一次状态变化的变量 lastButtonState = buttonState; } void clrEsp8266ResponseBuffer(void){ memset(response, 0, MAX_CONTENT_SIZE); //清空 }
代码解释:
这里咱们用到了一个按键,按下按键就给8266发个命令进入SmartConfig模式(Arduino和8266经过串口1通讯)。
加上读者已经配置成功Smartconfig了,那么咱们链接好电路以后就能够进行控制操做了。请看app控制页面:
接下来,若是有使能Debug的话,应该会打印如下信息:
注意:
博主简单介绍如何基于以前讲的基础知识来作一个简单项目,但愿你们巩固认识。