零知派【ESP32教程】Web网页控制彩色LED

​​ 零知派(零知开源)是一个专为电子初学者/电子兴趣爱好者设计的开源软硬件平台,在硬件上提供超高性价比STM32系列开发板、物联网控制板。取消了Bootloader程序烧录,让开发重心从“配置环境”转移到“创意实现”,极大降低了技术门槛。零知开源编程软件,内置上千个覆盖多场景的示例代码,支持项目源码一键下载,项目文章在线浏览。零知派(零知开源)平台通过软硬件协同创新,让你的创意快速转化为实物,来动手试试吧!

访问零知实验室,获取更多实战项目和教程资源吧!

www.lingzhilab.com

本教程将教你使用ESP32 搭建 Web 服务器,通过网页端颜色选择器实时、无刷新控制 RGB LED 灯的颜色,操作简单、响应流畅,手机 / 电脑浏览器均可使用。

一、软件和硬件

硬件清单

零知派 - ESP32 开发板

RGB 全彩 LED 模块(带限流电阻,3.3V/5V 通用,高电平点亮)

软件工具

零知派开发工具

硬件接线

RGB LED 引脚 ESP32 GPIO 引脚
红色引脚 GPIO25
绿色引脚 GPIO26
蓝色引脚 GPIO27

wKgZPGoBzw2AfuSzAAdQhgOugkE751.png

二、完整代码与使用说明

将代码中ssid(WiFi 名称)和password(WiFi 密码)修改为你自己的 WiFi 信息,其他代码无需改动。

/**************************************************************************************
 * 文件: LED.ino
 * 作者:零知派(深圳市在芯间科技有限公司)
 * -^^- 零知派,让电子制作变得更简单! -^^-
 * 时间: 2026-5-8 15:36:27
 * 说明: 
 * 功能:
***************************************************************************************/
#include <  WiFi.h  >

// 网络凭据
const char* ssid     = "你的WiFi名称";
const char* password = "你的WiFi密码";

// Web服务器
WiFiServer server(80);

// 引脚定义
const int redPin = 25;
const int greenPin = 26;
const int bluePin = 27;

// PWM 配置
const int freq = 5000;
const int resolution = 8;

// HTML 网页(修复乱码和颜色预览问题)
const char index_html[] PROGMEM = R"rawliteral(
<  !DOCTYPE html  >
<  html  >
<  head  >
    <  meta charset="UTF-8"  >
    <  meta name="viewport" content="width=device-width, initial-scale=1"  >
    <  link rel="icon" href="data:,"  >
    <  link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"  >
    <  style  >
        body { padding: 20px; }
        .container { max-width: 600px; margin: 0 auto; }
        .color-preview { 
            width: 100%; 
            height: 100px; 
            margin: 20px 0;
            border: 2px solid #ddd;
            border-radius: 5px;
            background-color: #000;
        }
        #colorPicker {
            width: 100%;
            height: 50px;
            border: 1px solid #ddd;
            border-radius: 5px;
            cursor: pointer;
        }
        .rgb-value {
            margin-top: 10px;
            padding: 10px;
            background-color: #f5f5f5;
            border-radius: 5px;
            text-align: center;
            font-family: monospace;
            font-size: 16px;
        }
        .status {
            margin-top: 10px;
            padding: 10px;
            text-align: center;
            font-size: 14px;
            border-radius: 5px;
        }
        .status.success {
            background-color: #d4edda;
            color: #155724;
        }
    <  /style  >
<  /head  >

    
        
            
                <  h1  >ESP32 颜色选择器<  /h1  >
            
        
        
            
                
            
        
        
            
                <  input type="color" id="colorPicker" value="#000000"  >
            
        
        
            
                RGB: 0, 0, 0
            
        
        
            
                
            
        
    
    
    <  script  >
        var colorPicker = document.getElementById('colorPicker');
        var previewDiv = document.getElementById('colorPreview');
        var rgbDiv = document.getElementById('rgbValue');
        var statusDiv = document.getElementById('status');
        
        // 发送颜色到ESP32
        function sendColor(r, g, b) {
            var url = '/?r' + r + 'g' + g + 'b' + b + '&';
            
            fetch(url)
                .then(function(response) {
                    // 显示成功状态
                    statusDiv.style.display = 'block';
                    statusDiv.className = 'status success';
                    statusDiv.innerHTML = ' 颜色已更新: RGB(' + r + ', ' + g + ', ' + b + ')';
                    
                    // 2秒后隐藏状态
                    setTimeout(function() {
                        statusDiv.style.display = 'none';
                    }, 1000);
                })
                .catch(function(error) {
                    console.log('发送失败: ' + error);
                    statusDiv.style.display = 'block';
                    statusDiv.className = 'status';
                    statusDiv.style.backgroundColor = '#f8d7da';
                    statusDiv.style.color = '#721c24';
                    statusDiv.innerHTML = ' 发送失败';
                    setTimeout(function() {
                        statusDiv.style.display = 'none';
                    }, 1000);
                });
        }
        
        // 实时更新预览并发送颜色(无需点击按钮)
        colorPicker.addEventListener('input', function() {
            var hex = this.value;
            
            // 更新预览
            previewDiv.style.backgroundColor = hex;
            
            // 转换HEX到RGB
            var r = parseInt(hex.substr(1, 2), 16);
            var g = parseInt(hex.substr(3, 2), 16);
            var b = parseInt(hex.substr(5, 2), 16);
            
            // 显示RGB值
            rgbDiv.innerHTML = 'RGB: ' + r + ', ' + g + ', ' + b;
            
            // 自动发送颜色到ESP32
            sendColor(r, g, b);
        });
        
        // 初始化:发送初始颜色
        var initialHex = colorPicker.value;
        var initialR = parseInt(initialHex.substr(1, 2), 16);
        var initialG = parseInt(initialHex.substr(3, 2), 16);
        var initialB = parseInt(initialHex.substr(5, 2), 16);
        sendColor(initialR, initialG, initialB);
    <  /script  >
<  /body  >
<  /html  >
)rawliteral";

const long timeoutTime = 2000;

// 初始化 PWM 功能
void setupPWM() {
    Serial.println("正在初始化 PWM...");
    
    // 检查 ledcAttach 是否可用
    if (ledcAttach(redPin, freq, resolution)) {
        Serial.println("红色引脚 PWM 初始化成功");
    } else {
        Serial.println("红色引脚 PWM 初始化失败");
    }
    
    if (ledcAttach(greenPin, freq, resolution)) {
        Serial.println("绿色引脚 PWM 初始化成功");
    } else {
        Serial.println("绿色引脚 PWM 初始化失败");
    }
    
    if (ledcAttach(bluePin, freq, resolution)) {
        Serial.println("蓝色引脚 PWM 初始化成功");
    } else {
        Serial.println("蓝色引脚 PWM 初始化失败");
    }
}

// 连接 WiFi
void connectWiFi() {
    Serial.println("n=================================");
    Serial.print("正在连接到 WiFi: ");
    Serial.println(ssid);
    
    WiFi.begin(ssid, password);
    
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts < 30) {  // 增加尝试次数到30
        delay(500);
        Serial.print(".");
        attempts++;
        
        // 每5秒显示一次状态
        if (attempts % 10 == 0) {
            Serial.println();
            Serial.print("仍在尝试连接... 已尝试 ");
            Serial.print(attempts);
            Serial.println(" 次");
        }
    }
    
    Serial.println();  // 换行
    
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println(" WiFi 连接成功!");
        Serial.print("IP 地址: ");
        Serial.println(WiFi.localIP());
        Serial.println("=================================");
        Serial.println("n 请在浏览器中输入以上 IP 地址 ");
        Serial.println("例如: http://" + WiFi.localIP().toString());
        Serial.println("=================================n");
    } else {
        Serial.println(" WiFi 连接失败!");
        Serial.print("错误代码: ");
        Serial.println(WiFi.status());
        Serial.println("请检查:");
        Serial.println("1. WiFi 密码是否正确");
        Serial.println("2. WiFi 名称是否正确(注意大小写)");
        Serial.println("3. ESP32 是否在信号范围内");
    }
}

// 设置 RGB 颜色值
void setColor(int red, int green, int blue) {
    ledcWrite(redPin, red);
    ledcWrite(greenPin, green);
    ledcWrite(bluePin, blue);
}

// 解析 HTTP 请求
bool parseColorRequest(String header, int& red, int& green, int& blue) {
    int rPos = header.indexOf("/?r");
    if (rPos == -1) return false;
    
    int gPos = header.indexOf('g', rPos);
    int bPos = header.indexOf('b', gPos);
    int endPos = header.indexOf('&', bPos);
    
    if (gPos == -1 || bPos == -1 || endPos == -1) return false;
    
    red = header.substring(rPos + 3, gPos).toInt();
    green = header.substring(gPos + 1, bPos).toInt();
    blue = header.substring(bPos + 1, endPos).toInt();
    
    red = constrain(red, 0, 255);
    green = constrain(green, 0, 255);
    blue = constrain(blue, 0, 255);
    
    return true;
}

// 处理客户端请求
void handleClient(WiFiClient& client) {
    unsigned long currentTime = millis();
    unsigned long previousTime = currentTime;
    String header = "";
    String currentLine = "";
    
    while (client.connected() && currentTime - previousTime <= timeoutTime) {
        currentTime = millis();
        
        if (client.available()) {
            char c = client.read();
            header += c;
            
            if (c == 'n') {
                if (currentLine.length() == 0) {
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-type:text/html;charset=utf-8");
                    client.println("Connection: close");
                    client.println();
                    client.print(index_html);
                    
                    int red, green, blue;
                    if (parseColorRequest(header, red, green, blue)) {
                        setColor(red, green, blue);
                        Serial.printf("颜色已设置为 红:%d 绿:%d 蓝:%dn", red, green, blue);
                    }
                    
                    client.println();
                    break;
                } else {
                    currentLine = "";
                }
            } else if (c != 'r') {
                currentLine += c;
            }
        }
    }
}

// 初始化
void setup() {
    Serial.begin(115200);
    delay(1000);  // 等待串口就绪
    
    Serial.println("nn=================================");
    Serial.println("ESP32 RGB LED 控制器启动中...");
    Serial.println("=================================");
    
    setupPWM();
    connectWiFi();
    server.begin();
    
    Serial.println("HTTP 服务器已启动");
    
    // 初始化为关闭状态
    setColor(0, 0, 0);
    
    // 如果 WiFi 连接成功,闪烁 LED 提示
    if (WiFi.status() == WL_CONNECTED) {
        for (int i = 0; i < 3; i++) {
            setColor(255, 255, 255);  // 白光
            delay(200);
            setColor(0, 0, 0);        // 关闭
            delay(200);
        }
    }
}

// 主循环
void loop() {
    WiFiClient client = server.available();
    
    if (client) {
        Serial.println("新客户端已连接");
        handleClient(client);
        client.stop();
        Serial.println("客户端已断开");
    }
}
/******************************************************************************
 * 深圳市在芯间科技有限公司
 * 淘宝店铺:在芯间科技零知板
 * 店铺网址:https://shop533070398.taobao.com
 * 版权说明:
 *  1.本代码的版权归【深圳市在芯间科技有限公司】所有,仅限个人非商业性学习使用。
 *  2.严禁将本代码或其衍生版本用于任何商业用途(包括但不限于产品开发、付费服务、企业内部使用等)。
 *  3.任何商业用途均需事先获得【深圳市在芯间科技有限公司】的书面授权,未经授权的商业使用行为将被视为侵权。
******************************************************************************/

三、上传与使用步骤

新建工程:打开零知派开发工具,新建一个空白工程。

粘贴代码:将上方完整代码复制到工程中,修改 WiFi 名称和密码

选择开发板:在软件右侧开发板列表中,选择ESP32

编译上传:点击「验证」→「上传」,将程序烧录到 ESP32 开发板。

查看服务器地址:打开软件串口调试窗口,等待 WiFi 连接成功,复制打印的IP 地址(如:192.168.3.165)。

网页控制:用手机 / 电脑浏览器(需和 ESP32 连接同一个 WiFi),输入复制的 IP 地址,打开控制页面。

实时调色:点击颜色选择器,无需刷新页面、无需点击按钮,LED 会实时同步你选择的颜色,同时页面显示当前 RGB 数值和操作状态。

wKgZO2oBzy6AUacUAADvsNieZQg258.png

四、功能亮点

无刷新实时控制:选择颜色的瞬间,LED 立即变色,操作流畅无延迟。

可视化操作:网页自带颜色预览框、RGB 数值显示、操作成功 / 失败提示。

自适应界面:手机、电脑浏览器均可完美适配,操作简单。

安全稳定:PWM 软件调光,保护 LED 不被烧坏,WiFi 连接稳定。

状态提示:串口打印连接日志、网页实时提示操作结果。

五、常见问题排查

WiFi 连接失败:检查 WiFi 名称 / 密码是否正确、ESP32 是否在 WiFi 信号范围内。

网页打不开:确保手机 / 电脑和 ESP32 连接同一个 WiFi,IP 地址输入无误。

LED 不亮:检查接线是否对应(红 25、绿 26、蓝 27),确认 RGB 模块是高电平点亮。

颜色异常:检查引脚接线是否松动,PWM 初始化是否正常(查看串口日志)。

总结

核心原理:ESP32 开启 WiFi+Web 服务器,网页通过fetch无刷新发送颜色数据,ESP32 解析后用 PWM 控制 RGB LED。

操作极简:修改 WiFi 信息→上传代码→浏览器访问 IP→实时调色,全程无需额外硬件。

扩展性强:可自行修改网页样式、添加开关、调整 PWM 参数,适配更多 RGB 灯模块。

​审核编辑 黄宇

Gravatar

About 奥洁自由人

作者文章