ESP32 Web Server (WebSocket) 实现多控件多引脚调节(PWM)
本教程将展示如何构建一个ESP32 web服务器,该服务器可以显示带有多个滑块的网页。滑块控制不同PWM通道的占空比来控制多个led的亮度。也可以代替led,你可以使用这个项目来控制直流电机或其他需要PWM信号的驱动器。客户端与ESP32之间的通信是通过WebSocket协议完成的。此外,每当有一个变化,所有客户端同步更新他们的滑块值。
- 控制界面
- 所需库
Arduino_JSON在Arduino IDE 管理库搜索下载。
-
文件架构
-
编译信息
使用 1.0 版本的库 WiFi 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi
使用 1.1.1 版本的库 AsyncTCP 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\AsyncTCP
使用 1.0 版本的库 SPIFFS 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\SPIFFS
使用 1.0 版本的库 FS 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\FS
使用 1.2.3 版本的库 ESPAsyncWebServer-master 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\ESPAsyncWebServer-master
使用 1.0.1 版本的库 Wire 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\Wire
使用 0.1.0 版本的库 Arduino_JSON 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\Arduino_JSON
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\xtensa-esp32-elf-gcc\\1.22.0-97-gc752ad5-5.2.0/bin/xtensa-esp32-elf-size" -A "d:\\arduino\\MyHexDir/Multiple_Sliders32.ino.elf"
项目使用了 820374 字节,占用了 (6%) 程序存储空间。最大为 13369344 字节。
全局变量使用了39504字节,(12%)的动态内存,余留288176字节局部变量。最大为327680字节。
实例代码
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include "SPIFFS.h"
#include <ESPAsyncWebServer.h>
#include <Wire.h>
#include <ESPAsyncWebServer.h>
#include <Arduino_JSON.h>
const char *ssid = "MERCURY_D268G";
const char *password = "pba5ayzk";
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws");
// Set LED GPIO
const int ledPin1 = 12;
const int ledPin2 = 13;
const int ledPin3 = 14;
String message = "";
String sliderValue1 = "0";
String sliderValue2 = "0";
String sliderValue3 = "0";
int dutyCycle1;
int dutyCycle2;
int dutyCycle3;
// setting PWM properties
const int freq = 5000;
const int ledChannel1 = 0;
const int ledChannel2 = 1;
const int ledChannel3 = 2;
const int resolution = 8;
//Json Variable to Hold Slider Values
JSONVar sliderValues;
//Get Slider Values
String getSliderValues()
{
sliderValues["sliderValue1"] = String(sliderValue1);
sliderValues["sliderValue2"] = String(sliderValue2);
sliderValues["sliderValue3"] = String(sliderValue3);
String jsonString = JSON.stringify(sliderValues);
return jsonString;
}
// Initialize SPIFFS
void initFS()
{
if (!SPIFFS.begin())
{
Serial.println("An error has occurred while mounting SPIFFS");
}
else
{
Serial.println("SPIFFS mounted successfully");
}
}
// Initialize WiFi
void initWiFi()
{
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void notifyClients(String sliderValues)
{
ws.textAll(sliderValues);
}
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT)
{
data[len] = 0;
message = (char *)data;
if (message.indexOf("1s") >= 0)
{
sliderValue1 = message.substring(2);
dutyCycle1 = map(sliderValue1.toInt(), 0, 100, 0, 255);
Serial.println(dutyCycle1);
Serial.print(getSliderValues());
notifyClients(getSliderValues());
}
if (message.indexOf("2s") >= 0)
{
sliderValue2 = message.substring(2);
dutyCycle2 = map(sliderValue2.toInt(), 0, 100, 0, 255);
Serial.println(dutyCycle2);
Serial.print(getSliderValues());
notifyClients(getSliderValues());
}
if (message.indexOf("3s") >= 0)
{
sliderValue3 = message.substring(2);
dutyCycle3 = map(sliderValue3.toInt(), 0, 100, 0, 255);
Serial.println(dutyCycle3);
Serial.print(getSliderValues());
notifyClients(getSliderValues());
}
if (strcmp((char *)data, "getValues") == 0)
{
notifyClients(getSliderValues());
}
}
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
switch (type)
{
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
void initWebSocket()
{
ws.onEvent(onEvent);
server.addHandler(&ws);
}
void setup()
{
Serial.begin(115200);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
initFS();
initWiFi();
// configure LED PWM functionalitites
ledcSetup(ledChannel1, freq, resolution);
ledcSetup(ledChannel2, freq, resolution);
ledcSetup(ledChannel3, freq, resolution);
// attach the channel to the GPIO to be controlled
ledcAttachPin(ledPin1, ledChannel1);
ledcAttachPin(ledPin2, ledChannel2);
ledcAttachPin(ledPin3, ledChannel3);
initWebSocket();
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/index.html", "text/html"); });
server.serveStatic("/", SPIFFS, "/");
// Start server
server.begin();
}
void loop()
{
ledcWrite(ledChannel1, dutyCycle1);
ledcWrite(ledChannel2, dutyCycle2);
ledcWrite(ledChannel3, dutyCycle3);
ws.cleanupClients();
}
- 上传完代码后,需要上传FS文件
源码和相关文件资源
https://gitee.com/perseverance51/esp32-project/tree/master