Arduino筆記(49):NodeMCU 透過網頁控制彩色LED環形燈

最近想做一個小夜燈,可以用手機的網頁控制顏色,找出之前做的 Arduino筆記(26):控制圓形16位元5050全彩LED 看一下如何連接到 Arduino。這個實作改用 NodeMCU 連接,透過網頁設定RGB顏色值,再控制環形的16個 LED燈亮這個 RGB 顏色。轉一圈後,第二圈以隨機的方式產生顏色值,讓環形 LED 燈看起來有比較多的變化。以下是實作過程與紀錄:


[安裝Adafruit_NeoPixel Library]

Adafruit_NeoPixel 函式庫提供 LED 顯示的顏色、亮度等控制項目。

• 先到 Github 下載 Adafruit_NeoPixel,按右邊綠色選項「Clone or download」,再選「Download ZIP」。
• 將下載的壓縮檔解壓縮,放在 Arduino 主程式下的 libraries目錄內,以我的電腦來說,Arduino安裝在  C:\User\[登入的帳號]\Documents\Arduino,點進目錄有一個 libraries的子目錄,下載後解壓縮的目錄,整個放進  libraries 目錄,重新啟動 Arduino即可。

[材料]

• NodeMCU V3 x 1
• FC-102 16 LED 環形模組 x 1
• 連接線 x 3

[線路圖]

NodeMCU
16 LED 環形模組
VIN
VCC
GND
GND
D2
DOUT


[程式]

#include <ESP8266WiFi.h>
#include <Adafruit_NeoPixel.h>

// 設定網路基地台SSID跟密碼
const char* ssid     = "MyHome";
const char* password = "ceiling4895";

// Set web server port number to 80
WiFiServer server(80);

// HTTP GET 的值
String redString = "0";
String greenString = "0";
String blueString = "0";
int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;

// 儲存 HTTP 需求的值
String header;

const int PIN = 4;         // NodeMCU 的 D2 pin
const int NUMPIXELS = 16;  // 環形LED燈數

// 目前時間
unsigned long currentTime = millis();
// 前次時間
unsigned long previousTime = 0; 
// 定義 timeout 時間, 以 milliseconds 表示(example: 2000ms = 2s)
const long timeoutTime = 2000;

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(115200);
  
  // Wi-Fi 連線
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // 列出取得的 IP address 並啟用 Web Server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();

  pixels.begin();      // 初始化 LED NeoPixel 物件
  pixels.setBrightness(40);
}

void loop(){
  WiFiClient client = server.available();   // 等待 clients 連線

  if (client) {                             // 假使新的用戶端連線
    currentTime = millis();
    previousTime = currentTime;
    Serial.println("New Client.");          // 列印新連線
    String currentLine = "";                // 等待從用戶端輸入的值 
    while (client.connected() && currentTime - previousTime ≤ timeoutTime) {  // 當 client 繼續連線持續執行迴圈
      currentTime = millis();
      if (client.available()) {             // 如果從 Client 端讀到位元
        char c = client.read();             // 讀取位元
        Serial.write(c);                    // 印出到串列 Console
        header += c;
        if (c == '\n') {                    // 假使是換行符號
 
          // 假使目前的一行是空白且有兩個新行,就結束 client HTTP 的要求
          if (currentLine.length() == 0) {
            // HTTP 表頭開始時,會有回應碼 response code (如: HTTP/1.1 200 OK)
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
                   
            // 顯示 HTML 網頁
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
            client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
            client.println("</head><body<div class=\"container\"><div class=\"row\"><h1>ESP Color Picker</h1></div>");
            client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change Color</a> ");
            client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
            client.println("<script>function update(picker) {document.getElementById('rgb').innerHTML = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
            client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
            // HTTP 回應結束時,給一個空的新行
            client.println();

            // 回應需求範例 : /?r201g32b255&
            // Red = 201 | Green = 32 | Blue = 255
            if(header.indexOf("GET /?r") ≥ 0) {
              pos1 = header.indexOf('r');
              pos2 = header.indexOf('g');
              pos3 = header.indexOf('b');
              pos4 = header.indexOf('&');

              redString = header.substring(pos1+1, pos2);
              greenString = header.substring(pos2+1, pos3);
              blueString = header.substring(pos3+1, pos4);

              int ired = redString.toInt();
              int igreen = greenString.toInt();              
              int iblue = blueString.toInt();

              for(int i=0; i<NUMPIXELS; i++) {       // 每一個 LED 燈
                  // pixels.Color() 設定 RGB 的值, 從 0,0,0 到 255,255,255
                  pixels.setPixelColor(i, pixels.Color(ired, igreen, iblue));
                  pixels.show();   // 送出更新的色表值到給硬體
                  delay(100); // 等待 0.1秒
               }
               // 隨機產生不同顏色  
               for(int i=0; i<NUMPIXELS; i++) {       // 每一個 LED 燈
                  ired += random(0,255);
                  igreen += random(0,255);
                  iblue += random(0,255);
                  if (ired > 255) { ired = ired - 255;}
                  if (igreen > 255) { igreen = igreen - 255;}
                  if (iblue > 255) { iblue = iblue - 255;}
                  pixels.setPixelColor(i, pixels.Color(ired, igreen, iblue));
                  pixels.show();   // 送出更新的色表值到給硬體
                  delay(100); // 等待 0.1秒
               }         
        
            }
            break;
          } else {               // 假使有新的一行, 清除目前這一行
            currentLine = "";
          }
        } else if (c != '\r') {  /// 讀取到的不是換行符號 
          currentLine += c;      // 增加一個字元在本行最後
        }
      }
    }
    // 清除表頭變數
    header = "";
    // 關閉連線 connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

[實作結果]


[參考資料]

Post a Comment

較新的 較舊