ماژول 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 باز شود .



