包含必要的库
#include <WiFi.h>
- 这行代码包含了ESP32开发板使用的WiFi库。它是必要的,因为我们需要使用WiFi功能来建立网络连接和服务器。
定义WiFi凭据和服务器端口
const char* ssid = "your_SSID"; // 替换为你的WiFi名称
const char* password = "your_PASSWORD"; // 替换为你的WiFi密码
WiFiServer server(80); // 设置服务器端口为80
- 这几行定义了连接到WiFi网络所需的SSID(WiFi名称)和密码。用户需要将其替换为自己的网络信息。
- 创建了一个
WiFiServer
对象,用于在HTTP标准端口80上侦听传入的连接。
定义LED控制引脚和变量
int ledPin = 2; // GPIO2用于控制LED
String header; // HTTP请求头
- 将GPIO 2定义为用于控制LED的引脚。
- 创建一个
String
类型的变量header
,用来存储来自客户端的HTTP请求头部信息。
初始化设置
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT); // 设置ledPin为输出模式
digitalWrite(ledPin, LOW); // 确保LED开始时是关闭的
...
}
setup()
函数在ESP32启动时运行一次。Serial.begin(115200);
初始化串行通信,波特率设置为115200。这对调试很有帮助。pinMode(ledPin, OUTPUT);
将LED控制引脚设置为输出模式。digitalWrite(ledPin, LOW);
确保在启动时LED是关闭的。
连接到WiFi网络
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
// 启动服务器
server.begin();
}
- 这些代码实现了连接到WiFi网络的功能。
WiFi.begin(ssid, password);
开始尝试连接到指定的WiFi网络。 - 循环检查WiFi是否已连接。如果还未连接,就等待500毫秒再次检查。
- 连接成功后,通过串行监视器输出“WiFi connected.”。
server.begin();
启动Web服务器,开始监听端口80上的传入连接。
主循环
void loop(){
WiFiClient client = server.available(); // 监听客户端连接
...
}
loop()
函数在setup()
之后不断运行。WiFiClient client = server.available();
检查是否有客户端(例如Web浏览器)尝试连接到服务器。
处理客户端连接
if (client) { // 如果有客户端连接
String currentLine = ""; // 创建一个字符串来保存收到的数据
while (client.connected()) { // loop while the client's connected
if (client.available()) { // 如果有字节可读
char c = client.read(); // 读取一个字节
header += c;
if (c == '\n') { // 如果字节是换行符
...
}
}
}
...
}
- 当客户端连接时,进入这个
if
块。 String currentLine = "";
用于暂存来自客户端的每一行数据。while (client.connected()) { ... }
循环持续运行,直到客户端断开连接。if (client.available()) { ... }
检查是否有来自客户端的数据可以读取。char c = client.read();
从客户端读取一个字符。header += c;
将读取的字符添加到请求头字符串中。
if (c == '\n') { ... }
检查是否到达了请求的行尾。
解析HTTP请求并控制LED
if (currentLine.length() == 0) {
...
// 检查请求的URL
if (header.indexOf("GET /2/on") >= 0) {
Serial.println("GPIO 2 on");
digitalWrite(ledPin, HIGH);
} else if (header.indexOf("GET /2/off") >= 0) {
Serial.println("GPIO 2 off");
digitalWrite(ledPin, LOW);
}
} else {
currentLine = "";
}
} else if (c != '\r') {
currentLine += c;
}
}
}
// 清除请求头
header = "";
// 关闭连接
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
- 当收到一个完整的HTTP请求头后(
currentLine.length() == 0
),程序将检查请求的URL。 - 如果URL包含
GET /2/on
,则将GPIO 2设置为高电平,打开LED。 - 如果URL包含
GET /2/off
,则将GPIO 2设置为低电平,关闭LED。 - 在处理完请求后,清空
header
字符串并关闭客户端连接。
响应客户端请求并发送HTML内容
// 发送HTTP响应头
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
...
client.println("</body></html>");
这部分代码用于向连接的客户端发送HTTP响应和HTML内容。
首先发送标准的HTTP响应头,表明响应是成功的(200 OK)。
然后发送HTML内容,包括用于控制LED的按钮。
这允许用户通过点击按钮来发送打开或关闭LED的请求。
源码
#include <WiFi.h> // 引入WiFi库,用于网络连接 // 网络凭据:请替换为你的网络SSID和密码 const char* ssid = "your_SSID"; const char* password = "your_PASSWORD"; WiFiServer server(80); // 创建一个在HTTP标准端口80上监听的服务器 int ledPin = 2; // 定义用于LED的GPIO引脚编号 String header; // 用于存储HTTP请求头部的字符串 void setup() { Serial.begin(115200); // 初始化串行通信,并设置波特率为115200 pinMode(ledPin, OUTPUT); // 设置LED引脚为输出模式 digitalWrite(ledPin, LOW); // 确保程序启动时LED是关闭的 // 连接到WiFi网络 Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected."); server.begin(); // 启动服务器,开始监听新的客户端连接 } void loop(){ WiFiClient client = server.available(); // 监听是否有客户端尝试连接 if (client) { // 如果有客户端连接 String currentLine = ""; // 用来暂存从客户端接收到的每一行数据 while (client.connected()) { // 当客户端保持连接状态时 if (client.available()) { // 如果有数据可以读取 char c = client.read(); // 读取一个字符 header += c; // 将读取的字符添加到header字符串 if (c == '\n') { // 如果字符是换行符,则表示一行的结束 if (currentLine.length() == 0) { // HTTP请求头部已接收完毕,发送HTTP响应 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("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}"); client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;"); client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}"); client.println(".button2 {background-color: #555555;}</style></head>"); // 显示LED状态和控制按钮 client.println("<body><h1>ESP32 Web Server</h1>"); client.println("<p>GPIO 2 - State " + String((digitalRead(ledPin) ? "On" : "Off")) + "</p>"); client.println("<p><a href=\"/2/on\"><button class=\"button\">ON</button></a></p>"); client.println("<p><a href=\"/2/off\"><button class=\"button button2\">OFF</button></a></p>"); client.println("</body></html>"); client.println(); // 结束HTTP响应 break; // 退出客户端连接循环 } else { // 如果currentLine不是空的,那么它是请求的一部分,但不是请求的结尾 currentLine = ""; // 清空currentLine,准备读取下一行 } } else if (c != '\r') { // 如果字符不是回车符,则是请求的一部分 currentLine += c; // 将字符添加到currentLine } // 检查请求的URL,如果是控制LED的命令,则执行相应操作 if (header.indexOf("GET /2/on") >= 0) { digitalWrite(ledPin, HIGH); // 打开LED } else if (header.indexOf("GET /2/off") >= 0) { digitalWrite(ledPin, LOW); // 关闭LED } } } // 请求处理完毕,清除header,并关闭客户端连接 header = ""; client.stop(); Serial.println("Client disconnected."); } }