第16课 网页远程控制LED#
网页远程控制LED实验是智慧校园物联网应用的微型实践,通过ESP32搭建Web服务器,实现浏览器对LED的远程操控,直接映射校园中智能照明、设备管理等真实场景。
本课将带领你探索物联网的奇妙世界!通过ESP32开发板,编写代码,就能用手机网页远程控制LED灯的开关。一起来完成你的第一个"智慧校园"物联网项目吧!
16.1 工作原理#
注意:此课程涉及HTML、CSS、JS等课外知识, 只做简单介绍。

关键步骤:
(1)ESP32 变身微型服务器
ESP32 连接 WiFi 后,会变成一个 微型Web服务器(就像一台超迷你的电脑)。
它会有一个局域网 IP 地址(比如:
172.23.131.16),其他连接 同一WiFi 的设备都能访问它。
(2)网页交互设计
ESP32 托管一个简单的网页,网页上有两个按钮:
“LED开” 按钮 → 点击后发送
/ON请求“LED关” 按钮 → 点击后发送
/OFF请求
(3)请求处理流程
点击网页按钮 → 浏览器向 ESP32 发送请求
ESP32 接收请求
ESP32 收到请求后,通过 GPIO 引脚控制 LED:
开灯:引脚输出高电平 → LED 通电发光
关灯:引脚输出低电平 → LED 断电熄灭
(4)实时反馈
网页通过 JavaScript 动态更新状态,无需刷新页面(类似你刷手机时的即时响应)。
技术三要素
要素 |
作用 |
类比 |
|---|---|---|
WiFi通信 |
让浏览器和ESP32能对话 |
像两个人用对讲机通话 |
Web服务器 |
托管网页并处理按钮点击请求 |
像餐厅服务员接收你的点单 |
GPIO数字输出 |
把网页指令变成实际电流控制LED |
像你用手按下物理开关 |
16.2 流程图#

16.3 实验代码#
⚠️ 特别提醒: 打开代码文件后,需要分别将代码中的 YourWiFiSSID 和 YourWiFiPassword 替换为您自己的 WiFi名称 和 WiFi密码。
const char* ssid = "YourWiFiSSID"; // 修改为你的WiFi名称
const char* password = "YourWiFiPassword"; // 修改为你的WiFi密码
⚠️ 特别注意:请确保代码中的WiFi名称和WiFi密码与连接到您的电脑、手机/平板、ESP32开发板和路由器的网络相同,它们必须在同一局域网(WiFi)内。
⚠️ 特别注意:WiFi必须是2.4Ghz频率的,否则ESP32无法连接WiFi。
#include <WiFi.h>
#include <WebServer.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
// 设置WiFi名称和WiFi密码
const char* ssid = "YourWiFiSSID"; // 替换为你自己的WiFi名称
const char* password = "YourWiFiPassword"; // 替换为你自己的WiFi密码
// OLED 配置
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // 共享 I2C 重置操作
#define I2C_ADDRESS 0x3C // 默认0x3C地址
// 定义LED引脚
const int ledPin = 12; // GPIO12
WebServer server(80); // 创建Web服务器对象,端口80
// 创建一个显示对象
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// HTML网页内容(中文版)
const char* htmlContent = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP32 LED 控制</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin: 0 auto;
padding-top: 50px;
}
.button {
padding: 10px 20px;
font-size: 16px;
margin: 10px;
cursor: pointer;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
}
.button-off {
background-color: #f44336;
}
</style>
</head>
<body>
<h1>ESP32 LED 控制</h1>
<p>LED 状态:<span id="ledState">%LEDSTATE%</span></p>
<p>
<button class="button" onclick="controlLED('ON')">LED 开</button>
<button class="button button-off" onclick="controlLED('OFF')">LED 关</button>
</p>
<script>
function controlLED(state) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/" + state, true);
xhr.send();
// 更新页面状态显示
document.getElementById("ledState").innerHTML = (state === 'ON') ? '开' : '关';
}
</script>
</body>
</html>
)rawliteral";
void handleRoot() {
// 获取当前LED状态,返回中文
String ledState = (digitalRead(ledPin)) ? "开" : "关"; // 读取LED状态
// 替换HTML中的占位符
String html = htmlContent;
html.replace("%LEDSTATE%", ledState); // 动态更新网页中的LED状态
server.send(200, "text/html", html); // 发送网页给客户端
}
void handleLEDOn() {
digitalWrite(ledPin, HIGH); // 打开LED
server.send(200, "text/plain", "LED已开启");
}
void handleLEDOff() {
digitalWrite(ledPin, LOW); // 关闭LED
server.send(200, "text/plain", "LED已关闭");
}
void handleNotFound() {
server.send(404, "text/plain", "404: Not found");
}
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW); // 初始关闭LED
Wire.begin(); // 初始化I2C总线
// 初始化 OLED
if(!display.begin(I2C_ADDRESS, true)) { // 真正的分辨率是 128x64
Serial.println("SH1106初始化失败");
while(1); // 陷入困境且无法继续前进
}
// 清空屏幕并设置文本属性
display.clearDisplay();
display.setTextSize(1); // 文本尺寸
display.setTextColor(SH110X_WHITE); // 单色显示
display.setCursor(0, 0); // 设定起始位置
// 连接WiFi
WiFi.begin(ssid, password);
Serial.println("正在连接WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("已连接Wi-Fi.");
Serial.println("IP: ");
Serial.println(WiFi.localIP());
display.print("IP: ");
display.println(WiFi.localIP());
display.display();
// 设置路由器
server.on("/", handleRoot);
server.on("/ON", handleLEDOn);
server.on("/OFF", handleLEDOff);
server.onNotFound(handleNotFound);
// 启动服务器
server.begin();
Serial.println("HTTP服务器已启动.");
}
void loop() {
server.handleClient(); // 处理客户端请求
}
16.4 代码说明#
注意:此课程涉及HTML、CSS、JS等课外知识, 只做简单介绍。
1. 基础设置
#include <WiFi.h>
#include <WebServer.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
// 设置WiFi名称和WiFi密码
const char* ssid = "YourWiFiSSID"; // 替换为你自己的WiFi名称
const char* password = "YourWiFiPassword"; // 替换为你自己的WiFi密码
// OLED 配置
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1 // 共享 I2C 重置操作
#define I2C_ADDRESS 0x3C // 默认0x3C地址
// 定义LED引脚
const int ledPin = 12; // GPIO12
WebServer server(80); // 创建Web服务器对象,端口80
引入必要的库,设置WiFi账号名称与密码,定义LED引脚,OLED配置,初始化Web服务器。
⚠️ 注意:请将代码里的 WiFi名称和WiFi密码 替换为你自己的 WiFi名称和WiFi密码。
2. 初始化设置(setup函数)
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW); // 初始关闭LED
Wire.begin(); // 初始化I2C总线
// 初始化 OLED
if(!display.begin(I2C_ADDRESS, true)) { // 真正的分辨率是 128x64
Serial.println("SH1106初始化失败");
while(1); // 陷入困境且无法继续前进
}
// 清空屏幕并设置文本属性
display.clearDisplay();
display.setTextSize(1); // 文本尺寸
display.setTextColor(SH110X_WHITE); // 单色显示
display.setCursor(0, 0); // 设定起始位置
// 连接WiFi
WiFi.begin(ssid, password);
Serial.println("正在连接WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("已连接Wi-Fi.");
Serial.println("IP: ");
Serial.println(WiFi.localIP());
display.print("IP: ");
display.println(WiFi.localIP());
display.display();
// 设置路由器
server.on("/", handleRoot);
server.on("/ON", handleLEDOn);
server.on("/OFF", handleLEDOff);
server.onNotFound(handleNotFound);
// 启动服务器
server.begin();
Serial.println("HTTP服务器已启动.");
}
初始化串口(用于调试输出)。
设置LED引脚并初始化为关闭状态。
初始化OLED
连接WiFi,等待连接成功并打印IP地址。
串口窗口打印IP地址,OLED显示IP地址。
绑定URL路径到对应的处理函数。
启动Web服务器。
3. 主循环(loop函数)
void loop() {
server.handleClient(); // 处理客户端(浏览器)请求
}
持续监听来自浏览器的HTTP请求,并调用对应的处理函数(如
handleRoot、handleLEDOn等)。
4. HTML网页内容
const char* htmlContent = R"rawliteral(
<!DOCTYPE HTML>
...
</html>
)rawliteral";
HTML网页的代码,页面有两个按钮:LED 开(发送
/ON请求)和 LED 关(发送/OFF请求)。
5. 处理HTTP请求
根路径请求(显示网页)
void handleRoot() {
String ledState = (digitalRead(ledPin)) ? "开" : "关"; // 读取LED状态
String html = htmlContent;
html.replace("%LEDSTATE%", ledState); // 动态更新网页中的LED状态
server.send(200, "text/html", html); // 发送网页给客户端
}
当访问ESP32的IP地址时,返回HTML网页,并显示当前LED状态。
控制LED的请求
void handleLEDOn() {
digitalWrite(ledPin, HIGH); // 打开LED
server.send(200, "text/plain", "LED已开启"); // 返回响应
}
void handleLEDOff() {
digitalWrite(ledPin, LOW); // 关闭LED
server.send(200, "text/plain", "LED已关闭");
}
功能:当点击网页按钮时,ESP32收到
/ON或/OFF请求,控制LED亮灭。
16.5 实验结果#
外接电源,选择好正确的开发板板型(ESP32 Dev Module)和 适当的串口端口(COMxx),然后单击
按钮上传代码。代码上传成功后,设置波特率为 9600,可以看到打印的IP地址 (如果看不到,可以按下复位按键重新连接一次):
OLED屏上同步显示IP地址:

将IP地址输入到手机/电脑浏览器并打开,你将看到一个简单的控制页面。
⚠️ 注意:确保手机/电脑与ESP32主板连接到同一个 WiFi 。


点击 “LED开” 或 “LED关” 按钮控制LED灯的状态。

16.6 常见问题解决#
若串口监视器无任何信息打印,请按下ESP32主板的复位键:

若ESP32 一直没有获取到 IP 地址,通常是因为 WiFi 连接失败,解决办法:
确保代码里的 WiFi 名称和 WiFi密码已经替换为您自己的 Wi-Fi名称 和 WiFi密码。
确保你的 WiFi 网络是 2.4GHz 的,ESP32不支持 5GHz WiFi。
若输入IP地址无页面,解决办法:
确保IP地址输入正确。
检查手机/电脑是否与ESP32在同一网络。