【ESP32/ESP8266】TCP异步通讯点灯控制示例程序

【ESP32/ESP8266】TCP异步通讯点灯控制示例程序


  • ✨本示例基于Arduino框架下开发。✨
  • 🌻控制演示
    在这里插入图片描述

🍭TCP异步和同步说明

🧾同步连接,是指服务器端在与第一个访问者请求建立连接并通信时,在此期间如果有第二个访问者请求将会被阻塞。然而通过异步连接,就可以实现服务器可以同时响应多个请求。

🌻所需库说明

  • 🌿esp8266所需库:
  • 📍 ESPAsyncTCP:https://github.com/me-no-dev/ESPAsyncTCP
  • 🌿 esp32所需库:
  • 📍 AsyncTCP: https://github.com/me-no-dev/AsyncTCP
  • 🍃通用库:

-ESPAsyncWebServer: https://github.com/me-no-dev/ESPAsyncWebServer

📢将下载下来的库解压后放置到Arduino安装目录下的对应库文件夹内,例如:C:\Program Files (x86)\Arduino\libraries

📖程序代码

🎈本代码默认定义的是esp8266 GPIO引脚,如需修改为esp32只需修改对应的引脚定义即可。

//引入核心库
#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>//https://github.com/me-no-dev/AsyncTCP
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>//https://github.com/me-no-dev/ESPAsyncTCP
#endif

#include <ESPAsyncWebServer.h>//https://github.com/me-no-dev/ESPAsyncWebServer

// 填写自己的WiFi信息
const char* ssid = "***";
const char* password = "***";

const char* PARAM_INPUT_1 = "state"; //为输入状态定义字符串参数

//控制引脚定义
const int LED_OUTPUT  = 2; // GPIO 27 作为输出引脚
const int Push_Button = 14; // GPIO 26 作为输入引脚

// Variables will change:
int ledState = LOW;          // 当前输出引脚状态值
int buttonState;             // 读取当前输入引脚的状态
int lastButtonState = LOW;   // 存储输入引脚上一次的值

// 定义无符号长整型变量,因为以毫秒为单位的时间很快就会变成一个比存储在int中的时间更大的数字。
unsigned long lastDebounceTime = 0;  // 最后一次切换输出引脚时间
unsigned long debounceDelay = 50;    // 消抖时间

// 创建异步服务对象,端口号80
AsyncWebServer server(80);

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta charset="utf-8">
  <title>ESP32-ESP8266 Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 3.0rem;}
    p {font-size: 3.0rem;}
    body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
    .switch {position: relative; display: inline-block; width: 120px; height: 68px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #FF0000; border-radius: 34px}
    .slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 68px}
    input:checked+.slider {background-color:  #008000}
    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}
  </style>
</head>
<body>
  <center><h3 style="color: green;">ESP32-ESP8266网页控制界面</center><hr/>
  %BUTTONPLACEHOLDER%
<script>function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?state=1", true); }
  else { xhr.open("GET", "/update?state=0", true); }
  xhr.send();
}

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var inputChecked;
      var outputStateM;
      if( this.responseText == 1){ 
        inputChecked = true;
        outputStateM = "On";
      }
      else { 
        inputChecked = false;
        outputStateM = "Off";
      }
      document.getElementById("output").checked = inputChecked;
      document.getElementById("outputState").innerHTML = outputStateM;
    }
  };
  xhttp.open("GET", "/state", true);
  xhttp.send();
}, 1000 ) ;
</script>
</body>
</html>
)rawliteral";

// 将网页中的按钮部分替换为占位符
String processor(const String& var){
  //Serial.println(var);
  if(var == "BUTTONPLACEHOLDER"){
    String buttons ="";
    String outputStateValue = outputState();
    buttons+= "<h4 style='color: red;'>输出引脚 - GPIO 2 - 当前状态: <span id=\"outputState\"></span></h4><label class=\"switch\"><input type=\"checkbox\" οnchange=\"toggleCheckbox(this)\" id=\"output\" " + outputStateValue + "><span class=\"slider\"></span></label><br/>";
    return buttons;
  }
  return String();
}

String outputState(){
  if(digitalRead(LED_OUTPUT)){
    return "checked";
  }
  else {
    return "";
  }
  return "";
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(LED_OUTPUT, OUTPUT);
  digitalWrite(LED_OUTPUT, LOW);
  pinMode(Push_Button, INPUT);//按键控制
  
  //连接 Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  //打印IP地址
  Serial.println(WiFi.localIP());

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Send a GET request to <ESP_IP>/update?state=<inputMessage>
  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    String inputParam;
    // GET input1 value on <ESP_IP>/update?state=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      inputMessage = request->getParam(PARAM_INPUT_1)->value();
      inputParam = PARAM_INPUT_1;
      digitalWrite(LED_OUTPUT, inputMessage.toInt());
      ledState = !ledState;
    }
    else {
      inputMessage = "No message sent";
      inputParam = "none";
    }
    Serial.println(inputMessage);
    request->send(200, "text/plain", "OK");
  });

  // 发送GET请求 <ESP_IP>/state
  server.on("/state", HTTP_GET, [] (AsyncWebServerRequest *request) {
    request->send(200, "text/plain", String(digitalRead(LED_OUTPUT)).c_str());
  });
  // Start server
  server.begin();
}
  
void loop() {
  //读取开关状态到一个局部变量:
  int reading = digitalRead(Push_Button);

//检查一下你是否按了按钮
//(即输入从LOW到HIGH),你已经等待了足够长的时间
//从上次按下按钮开始忽略任何杂音:

  // 如果开关改变,判断是否由于干扰或真的按下:开始计时
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
//判断按键是否按下
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // 判断按键状态是否改变
    if (reading != buttonState) {
      buttonState = reading;

      // 按钮状态为高时切换LED状态
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // 设置初始状态
  digitalWrite(LED_OUTPUT, ledState);

  // 保存状态:
  lastButtonState = reading;
}

🎯程序代码

//引入核心库
#ifdef ESP32
  #include <WiFi.h>
  #include <AsyncTCP.h>//https://github.com/me-no-dev/AsyncTCP
#else
  #include <ESP8266WiFi.h>
  #include <ESPAsyncTCP.h>//https://github.com/me-no-dev/ESPAsyncTCP
#endif

#include <ESPAsyncWebServer.h>//https://github.com/me-no-dev/ESPAsyncWebServer

// 填写自己的WiFi信息
const char* ssid = "***";
const char* password = "***";

const char* PARAM_INPUT_1 = "state"; //为输入状态定义字符串参数

//控制引脚定义
const int LED_OUTPUT  = 2; // GPIO 27 作为输出引脚
const int Push_Button = 14; // GPIO 26 作为输入引脚

// Variables will change:
int ledState = LOW;          // 当前输出引脚状态值
int buttonState;             // 读取当前输入引脚的状态
int lastButtonState = LOW;   // 存储输入引脚上一次的值

// 以下变量是无符号长整型变量,因为以毫秒为单位的时间很快就会变成一个比存储在int中的时间更大的数字。
unsigned long lastDebounceTime = 0;  // 最后一次切换输出引脚时间
unsigned long debounceDelay = 50;    // 消抖时间

// 创建异步服务对象,端口号80
AsyncWebServer server(80);

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta charset="utf-8">
  <title>ESP32-ESP8266 Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    h2 {font-size: 3.0rem;}
    p {font-size: 3.0rem;}
    body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
    .switch {position: relative; display: inline-block; width: 120px; height: 68px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #FF0000; border-radius: 34px}
    .slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 68px}
    input:checked+.slider {background-color:  #008000}
    input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}
  </style>
</head>
<body>
  <center><h3 style="color: green;">ESP32-ESP8266网页控制界面</center><hr/>
  %BUTTONPLACEHOLDER%
<script>function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?state=1", true); }
  else { xhr.open("GET", "/update?state=0", true); }
  xhr.send();
}

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var inputChecked;
      var outputStateM;
      if( this.responseText == 1){ 
        inputChecked = true;
        outputStateM = "On";
      }
      else { 
        inputChecked = false;
        outputStateM = "Off";
      }
      document.getElementById("output").checked = inputChecked;
      document.getElementById("outputState").innerHTML = outputStateM;
    }
  };
  xhttp.open("GET", "/state", true);
  xhttp.send();
}, 1000 ) ;
</script>
</body>
</html>
)rawliteral";

// 将网页中的按钮部分替换为占位符
String processor(const String& var){
  //Serial.println(var);
  if(var == "BUTTONPLACEHOLDER"){
    String buttons ="";
    String outputStateValue = outputState();
    buttons+= "<h4 style='color: red;'>输出引脚 - GPIO 2 - 当前状态: <span id=\"outputState\"></span></h4><label class=\"switch\"><input type=\"checkbox\" οnchange=\"toggleCheckbox(this)\" id=\"output\" " + outputStateValue + "><span class=\"slider\"></span></label><br/>";
    return buttons;
  }
  return String();
}

String outputState(){
  if(digitalRead(LED_OUTPUT)){
    return "checked";
  }
  else {
    return "";
  }
  return "";
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(LED_OUTPUT, OUTPUT);
  digitalWrite(LED_OUTPUT, LOW);
  pinMode(Push_Button, INPUT);//按键控制
  
  //连接 Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  //打印IP地址
  Serial.println(WiFi.localIP());

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Send a GET request to <ESP_IP>/update?state=<inputMessage>
  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    String inputParam;
    // GET input1 value on <ESP_IP>/update?state=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      inputMessage = request->getParam(PARAM_INPUT_1)->value();
      inputParam = PARAM_INPUT_1;
      digitalWrite(LED_OUTPUT, inputMessage.toInt());
      ledState = !ledState;
    }
    else {
      inputMessage = "No message sent";
      inputParam = "none";
    }
    Serial.println(inputMessage);
    request->send(200, "text/plain", "OK");
  });

  // 发送GET请求 <ESP_IP>/state
  server.on("/state", HTTP_GET, [] (AsyncWebServerRequest *request) {
    request->send(200, "text/plain", String(digitalRead(LED_OUTPUT)).c_str());
  });
  // Start server
  server.begin();
}
  
void loop() {
  //读取开关状态到一个局部变量:
  int reading = digitalRead(Push_Button);

//检查一下你是否按了按钮
//(即输入从LOW到HIGH),你已经等待了足够长的时间
//从上次按下按钮开始忽略任何杂音:

  // 如果开关改变,判断是否由于干扰或真的按下:开始计时
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // 判断按键状态是否改变
    if (reading != buttonState) {
      buttonState = reading;

      // 按钮状态为高时切换LED状态
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // 设置初始状态
  digitalWrite(LED_OUTPUT, ledState);

  // 保存状态:
  lastButtonState = reading;
}
  • 选择esp8266- nodemcu1.0编译信息
使用 1.0  版本的库 ESP8266WiFi 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\ESP8266WiFi 
使用 1.2.2  版本的库 ESPAsyncTCP 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\ESPAsyncTCP 
使用 1.2.3  版本的库 ESPAsyncWebServer 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\ESPAsyncWebServer 
使用 1.0  版本的库 Hash 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\libraries\Hash 
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\xtensa-lx106-elf-gcc\\3.0.4-gcc10.3-1757bed/bin/xtensa-lx106-elf-size" -A "d:\\arduino\\MyHexDir/ESP_WebServer_Key.ino.elf"
项目使用了 302605 字节,占用了 (28%) 程序存储空间。最大为 1044464 字节。
全局变量使用了30248字节,(36%)的动态内存,余留51672字节局部变量。最大为81920字节。

⛳程序源码资源

链接:https://pan.baidu.com/s/1DKwllDwNbPDmhtBx2kr58g 
提取码:zp22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值