ماژول ESP-01 یک نسخه کوچک از ماژول های ESP8266 میباشد . این ماژول در جهت افزودن قابلیت WiFi به MCU ها طراحی شده است لذا تنها چند پین ESP8266EX در دسترس است . ESP-01 کاربرد های خاص خود را دارد لذا در بسیاری از موارد جایگزین کردن آن با مدل های ESP MOD و… مقرون به صرفه نمی باشد . در این پروژه قصد داریم LED های WS2812 را با استفاد از این ماژول راه اندازی کنیم . از آنجایی که WS2812 تنها به یک پین از MCU برای راه اندزای نیاز دارند لذا استفاده از ESP-01 ایده خوبی به نظر می رسد . ماژول ESP-01 بر خلاف دیگر برد های توسعه ESP8266 فاقد کلید های ریست و فلش است لذا باید به صورت دستی این برد را به حالت پروگرام ببرید .
ابتدا برد خود را همانند تصویر زیر به یک مبدل USB-TTL متصل کنید :
در مدار فوق با فشردن کلید ریست ماژول ریست می شود . همچنین اگر کلید Program رو نگه دارید و همزمان دکمه ریست را بزنید ماژول وارد مد پروگرام خواهد شد که می توانید کد های خود را بر روی برد آپلود کنید .
پس از بستن مدار فوق و انتخاب مد پروگرام ، در آردوینو IDE از منو Board گزینه ESP8266 را انتخاب کنید ( باید از قبل SDK های ESP8266 را در آردوینو IDE نصب کرده باشید . در آموزش های قبلی چگونگی این کار شرح داده شد ) .
کد های زیر را در آردوینو IDE کبی کنید و آن را در یک فولدر ذخیره نمایید :
#include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> #include <FastLED.h> #include <ESP8266WiFiMulti.h> #include <WebSocketsServer.h> #include <Hash.h> #include <EEPROM.h> // Wifi credentials const char* ssid = "نام وایفای خود را وارد کنید"; const char* password = "رمز وایفای خود را وارد کنید"; const char* espname = "your ESP name"; //Shows in router and in OTA-menu // Defining LED strip #define NUM_LEDS 30 //Number of LEDs in your strip #define DATA_PIN 2 //Using WS2812B -- if you use APA102 or other 4-wire LEDs you need to also add a clock pin CRGB leds[NUM_LEDS]; CRGBSet ledSet(leds, NUM_LEDS); //Trying LEDSet from FastLED //Some Variables byte myEffect = 1; //what animation/effect should be displayed byte myHue = 33; //I am using HSV, the initial settings display something like "warm white" color at the first start byte mySaturation = 168; byte myValue = 255; byte rainbowHue = myHue; //Using this so the rainbow effect doesn't overwrite the hue set on the website int flickerTime = random(200, 400); int flickerLed; int flickerValue = 110 + random(-3, +3); //70 works nice, too int flickerHue = 33; bool eepromCommitted = true; unsigned long currentTime = 0; unsigned long previousTime = 0; unsigned long lastChangeTime = 0; unsigned long currentChangeTime = 0; #include "LEDanimations.h" #include "LEDWebsockets.h" void setup() { EEPROM.begin(4); // Using simulated EEPROM on the ESP8266 flash to remember settings after restarting the ESP LEDS.addLeds<WS2812B,DATA_PIN,GRB>(leds,NUM_LEDS); // Initialize the LEDs // Reading EEPROM myEffect = EEPROM.read(0); // Only read EEPROM for the myEffect variable after you're sure the animation you are testing won't break OTA updates, make your ESP restart etc. or you'll need to use the USB interface to update the module. myHue = EEPROM.read(1); mySaturation = EEPROM.read(2); myValue = EEPROM.read(3); delay(100); //Delay needed, otherwise showcolor doesn't light up all leds or they produce errors after turning on the power supply - you will need to experiment LEDS.showColor(CHSV(myHue, mySaturation, myValue)); // Starting Wifi WiFi.hostname(espname); WiFi.mode(WIFI_STA); while (WiFi.waitForConnectResult() != WL_CONNECTED) { WiFi.begin(ssid, password); delay(500); } // All this below is for OTA-updates // Port defaults to 8266 // ArduinoOTA.setPort(8266); // Hostname defaults to esp8266-[ChipID] ArduinoOTA.setHostname(espname); // No authentication by default // ArduinoOTA.setPassword((const char *)"123"); ArduinoOTA.begin(); //Websocket server webSocket.begin(); webSocket.onEvent(webSocketEvent); } void loop() { ArduinoOTA.handle(); // handles OTA-updates // yield(); // uncomment if you run into watchdog resets webSocket.loop(); // handles websockets // yield(); // uncomment if you run into watchdog resets switch (myEffect) { // switches between animations case 1: // Solid Color EVERY_N_MILLISECONDS( 20 ) { ledSet = CHSV(myHue, mySaturation, myValue); LEDS.show(); } break; case 2: // Ripple effect ripple(); break; case 3: // Cylon effect cylon(); break; case 4: // Fire effect Fire2012(); break; case 5: // Turn off all LEDs EVERY_N_MILLISECONDS( 20 ) { ledSet.fadeToBlackBy(2); LEDS.show(); } break; case 6: // loop through hues with all leds the same color. Can easily be changed to display a classic rainbow loop EVERY_N_MILLISECONDS( 250 ) { rainbowHue = rainbowHue + 1; LEDS.showColor(CHSV(rainbowHue, mySaturation, myValue)); } break; case 7: // make a single, random LED act as a candle currentTime = millis(); ledSet.fadeToBlackBy(1); leds[flickerLed] = CHSV(flickerHue, 255, flickerValue); flickerTime = random(150, 500); if (currentTime - previousTime > flickerTime) { flickerValue = 110 + random(-10, +10); //70 works best flickerHue = 33; //random(33, 34); previousTime = currentTime; LEDS.show(); } break; default: LEDS.showColor(CRGB(0, 255, 0)); // Bright green in case of an error break; } // EEPROM-commit and websocket broadcast -- they get called once if there has been a change 1 second ago and no further change since. This happens for performance reasons. currentChangeTime = millis(); if (currentChangeTime - lastChangeTime > 1000 && eepromCommitted == false) { EEPROM.commit(); eepromCommitted = true; String websocketStatusMessage = "H" + String(myHue) + ",S" + String(mySaturation) + ",V" + String(myValue); webSocket.broadcastTXT(websocketStatusMessage); // Tell all connected clients which HSV values are running //LEDS.showColor(CRGB(0, 255, 0)); //for debugging to see when if-clause fires //delay(50); //for debugging to see when if-clause fires } }
قبل از کامپایل کد های فوق ، در پوشه مربوط به برنامه دو فایل txt ایجاد کرده و کد های زیر را در آن ها کپی کنید :
اسم فایل txt را به LEDanimations.h تغییر دهید ( اگر پیغامی مشاهده کردین ok بزنید )
int color; int center = 0; int step = -1; int maxSteps = 16; float fadeRate = 0.8; int diff; //background color uint32_t currentBg = random(256); uint32_t nextBg = currentBg; int wrap(int step) { if(step < 0) return NUM_LEDS + step; if(step > NUM_LEDS - 1) return step - NUM_LEDS; return step; } void one_color_allHSV(int ahue, int abright) { // SET ALL LEDS TO ONE COLOR (HSV) for (int i = 0 ; i < NUM_LEDS; i++ ) { leds[i] = CHSV(ahue, 255, abright); } } void ripple() { if (currentBg == nextBg) { nextBg = random(256); } else if (nextBg > currentBg) { currentBg++; } else { currentBg--; } for(uint16_t l = 0; l < NUM_LEDS; l++) { leds[l] = CHSV(currentBg, 255, 50); // strip.setPixelColor(l, Wheel(currentBg, 0.1)); } if (step == -1) { center = random(NUM_LEDS); color = random(256); step = 0; } if (step == 0) { leds[center] = CHSV(color, 255, 255); // strip.setPixelColor(center, Wheel(color, 1)); step ++; } else { if (step < maxSteps) { //Serial.println(pow(fadeRate,step)); leds[wrap(center + step)] = CHSV(color, 255, pow(fadeRate, step)*255); // strip.setPixelColor(wrap(center + step), Wheel(color, pow(fadeRate, step))); leds[wrap(center - step)] = CHSV(color, 255, pow(fadeRate, step)*255); // strip.setPixelColor(wrap(center - step), Wheel(color, pow(fadeRate, step))); if (step > 3) { leds[wrap(center + step - 3)] = CHSV(color, 255, pow(fadeRate, step - 2)*255); // strip.setPixelColor(wrap(center + step - 3), Wheel(color, pow(fadeRate, step - 2))); leds[wrap(center - step + 3)] = CHSV(color, 255, pow(fadeRate, step - 2)*255); // strip.setPixelColor(wrap(center - step + 3), Wheel(color, pow(fadeRate, step - 2))); } step ++; } else { step = -1; } } LEDS.show(); delay(50); } // RIPPLE END // Fire2012 Start #define FRAMES_PER_SECOND 25 bool gReverseDirection = false; #define COOLING 100 // SPARKING: What chance (out of 255) is there that a new spark will be lit? // Higher chance = more roaring fire. Lower chance = more flickery fire. // Default 120, suggested range 50-200. #define SPARKING 70 void Fire2012() { // Array of temperature readings at each simulation cell static byte heat[NUM_LEDS]; // Step 1. Cool down every cell a little for( int i = 0; i < NUM_LEDS; i++) { heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2)); } // Step 2. Heat from each cell drifts 'up' and diffuses a little for( int k= NUM_LEDS - 1; k >= 2; k--) { heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; } // Step 3. Randomly ignite new 'sparks' of heat near the bottom if( random8() < SPARKING ) { int y = random8(7); heat[y] = qadd8( heat[y], random8(160,255) ); } // Step 4. Map from heat cells to LED colors for( int j = 0; j < NUM_LEDS; j++) { CRGB color = HeatColor( heat[j]); int pixelnumber; if( gReverseDirection ) { pixelnumber = (NUM_LEDS-1) - j; } else { pixelnumber = j; } leds[pixelnumber] = color; } FastLED.show(); // display this frame FastLED.delay(1000 / FRAMES_PER_SECOND); } //Fire2012 End //CYLON START void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(200); } } void cylon(){ static uint8_t hue = 0; //Serial.print("x"); // First slide the led in one direction for(int i = 0; i < NUM_LEDS; i++) { // Set the i'th led to red leds[i] = CHSV(hue++, 255, 255); // Show the leds FastLED.show(); // now that we've shown the leds, reset the i'th led to black // leds[i] = CRGB::Black; fadeall(); // Wait a little bit before we loop around and do it again delay(25); } //Serial.print("x"); // Now go in the other direction. for(int i = (NUM_LEDS)-1; i >= 0; i--) { // Set the i'th led to red leds[i] = CHSV(hue++, 255, 255); // Show the leds FastLED.show(); // now that we've shown the leds, reset the i'th led to black // leds[i] = CRGB::Black; fadeall(); // Wait a little bit before we loop around and do it again delay(25); } }
کد های زیر را نیز در فایل txt دیگری کپی کرده و در آخر اسم فایل را به LEDWebsockets.h تغییر دهید .
WebSocketsServer webSocket = WebSocketsServer(81); void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) { switch(type) { case WStype_DISCONNECTED: //USE_SERIAL.printf("[%u] Disconnected!\n", num); break; case WStype_CONNECTED: { IPAddress ip = webSocket.remoteIP(num); //USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); // send message to client String websocketStatusMessage = "H" + String(myHue) + ",S" + String(mySaturation) + ",V" + String(myValue); //Sends a string with the HSV values to the client website when the conection gets established webSocket.sendTXT(num, websocketStatusMessage); String info = ESP.getResetInfo(); webSocket.sendTXT(num, info); //Handy for debugging } break; case WStype_TEXT: { //USE_SERIAL.printf("[%u] get Text: %s\n", num, payload); // send message to client // webSocket.sendTXT(num, "message here"); // send data to all connected clients // webSocket.broadcastTXT("message here"); String text = String((char *) &payload[0]); if (text.startsWith("a")) { String xVal = (text.substring(text.indexOf("a") + 1, text.length())); flickerLed = random(0,NUM_LEDS-1); if (myEffect != xVal.toInt()) { // only do stuff when there was a change myEffect = xVal.toInt(); rainbowHue = myHue; EEPROM.write(0, myEffect); //stores the variable but needs to be committed to EEPROM before being saved - this happens in the loop lastChangeTime = millis(); eepromCommitted = false; } } if (text.startsWith("b")) { String xVal = (text.substring(text.indexOf("b") + 1, text.length())); if (myHue != xVal.toInt()) { myHue = xVal.toInt(); rainbowHue = myHue; EEPROM.write(1, myHue); lastChangeTime = millis(); eepromCommitted = false; } } if (text.startsWith("c")) { String xVal = (text.substring(text.indexOf("c") + 1, text.length())); if (mySaturation != xVal.toInt()) { mySaturation = xVal.toInt(); EEPROM.write(2, mySaturation); lastChangeTime = millis(); eepromCommitted = false; } } if (text.startsWith("d")) { String xVal = (text.substring(text.indexOf("d") + 1, text.length())); if (myValue != xVal.toInt()) { myValue = xVal.toInt(); EEPROM.write(3, myValue); lastChangeTime = millis(); eepromCommitted = false; } } /*currentTime = millis(); if (currentTime - previousTime > 1000) { String websocketStatusMessage = "H" + String(myHue) + ",S" + String(mySaturation) + ",V" + String(myValue); webSocket.broadcastTXT(websocketStatusMessage); previousTime = currentTime; }*/ break; } case WStype_BIN: //USE_SERIAL.printf("[%u] get binary lenght: %u\n", num, lenght); hexdump(payload, lenght); // send message to client // webSocket.sendBIN(num, payload, lenght); break; } }
سپس کد های اصلی را کامپایل و آن را در فولدری که قبلا برای پروژه ساخته بودید ذخیره کنید . این فایل حتما باید در کنار دو فایل LEDWebsockets.h و LEDanimations.h ذخیره شود .
پس از کامپایل کردن برنامه کد ها را بر روی برد ESP-01 خود آپلود کنید . پس از آپلود کد ها وارد محیط Serial monitor آردوینو IDE شوید و یک بار ماژول را ریست کنید . IP را که نشان داده می شود به خاطر بسپارید . از این IP برای ارتباط با ماژول استفاده خواهد شد ( این IP را در تنظیمات مودم خود نیز می توانید پیدا کنید ) . سپس WS2812 را همانند تصویر زیر به ماژول متصل کنید :
پس از اتصال تغذیه و روشن شدن مدار ، IP ماژول را در مرورگر خود وارد کنید تا پنل کنترل LED باز شود .