這一篇,博主將教你們怎麼去實現一個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的話,應該會打印如下信息:
注意:
博主簡單介紹如何基於以前講的基礎知識來作一個簡單項目,但願你們鞏固認識。