Skip to content
H2LongPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESP32 Web Server — 入门指南

一个面向初学者的 ESP32 Web 服务器项目。插上电,ESP32 会自动连上 Wi-Fi 并启动一个网页,你用手机或电脑打开浏览器就能访问。


目录


这个项目是做什么的

想象你的 ESP32 是一台微型计算机。这个项目让它做了两件事:

  1. 连上你家的 Wi-Fi(就像手机连接 Wi-Fi 一样)
  2. 开启一个网站(在浏览器中输入 ESP32 的 IP 地址,就能看到一个网页)

最终效果:你可以在浏览器中看到 ESP32 的在线状态,未来还可以添加按钮来控制 LED、查看温度、看摄像头画面等。


硬件准备

硬件 说明
ESP32 开发板 (推荐 ESP32-S3 或 ESP32-CAM) 主控芯片,项目运行的核心
Micro USB 数据线 给开发板供电 & 烧录程序
电脑(Windows / macOS / Linux) 用来编写和编译代码
Wi-Fi 热点(手机热点或家用路由器) ESP32 会连接这个网络

软件准备

在电脑上安装以下工具(如果已经装过可以跳过):

1. 安装 ESP-IDF(乐鑫官方开发框架)

打开终端,按下面的命令操作(以 Linux / macOS 为例):

# 克隆 ESP-IDF 仓库(大约 1GB)
git clone --recursive https://github.com/espressif/esp-idf.git ~/esp/esp-idf

# 安装工具链(编译器、调试器等)
cd ~/esp/esp-idf
./install.sh esp32s3

# 设置环境变量(每次打开新终端都要执行)
source ~/esp/esp-idf/export.sh

# 安装 Python 依赖
pip install --upgrade pip
pip install -r ~/esp/esp-idf/requirements.txt

Windows 用户建议使用 ESP-IDF 的 CMD 或 PowerShell 快捷方式,会自动设置好环境。

2. 验证安装

idf.py --version

如果看到版本号,说明安装成功。


项目结构(一次看懂所有文件)

esp_web/                          ← 项目根目录
│
├── CMakeLists.txt                ← 顶层配置文件(告诉 ESP-IDF 这是一个项目)
│
├── main/                         ← 主程序
│   ├── CMakeLists.txt            ← main 的配置
│   └── esp_web.c                 ← 入口文件,相当于"总指挥"
│
├── components/                   ← 自己写的功能模块
│   ├── CMakeLists.txt            ← 所有模块的编译配置
│   │
│   ├── Hardware/                 ← 硬件相关模块
│   │   └── wifi_sta/             ← Wi-Fi 模块
│   │       ├── wifi_sta.h        ← 头文件(公开哪些函数)
│   │       └── wifi_sta.c        ← 实现文件(具体怎么连 Wi-Fi)
│   │
│   └── Driver/                   ← 驱动相关模块
│       └── Web/                  ← Web 服务器模块
│           ├── web_server.h      ← 头文件(公开哪些函数)
│           └── web_server.c      ← 实现文件(具体怎么开网站)
│
├── build/                        ← 编译产生的文件(自动生成,不用管)
└── sdkconfig                     ← ESP-IDF 配置(自动生成,不用管)

系统启动流程(芯片通电后发生了什么)

把 ESP32 插上 USB 后,它就像电脑开机一样,按顺序执行代码。下面是完整的流程:

┌─────────────────────────────────────────────────────────┐
│                     ESP32 上电                           │
│   → 引导程序(ROM bootloader)启动                        │
│   → 加载主程序到内存                                      │
│   → 调用 app_main() ← 这就是我们写的入口函数               │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│  ① app_main() 启动(esp_web.c)                         │
│    ├── 打印 "系统启动"                                    │
│    └── 调用 wifista_init()  ← 去连 Wi-Fi                │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│  ② wifista_init() 开始工作(wifi_sta.c)                │
│    ├── 第1步:创建"事件组"(短信通知箱)                   │
│    ├── 第2步:初始化 NVS(类似于格式化存储卡)              │
│    ├── 第3步:启动 TCP/IP(先搭好网络通道)                 │
│    ├── 第4步:创建事件循环(搭好通信线路)                  │
│    ├── 第5步:注册回调(告诉芯片:Wi-Fi 有事就通知我)       │
│    ├── 第6步:创建 Wi-Fi 网卡                             │
│    ├── 第7步:初始化 Wi-Fi 驱动                           │
│    ├── 第8步:设置为 STA 模式(就像手机的"连接热点"模式)    │
│    ├── 第9步:设置你家 Wi-Fi 的 名字和密码                  │
│    ├── 第10步:启动 Wi-Fi(开始搜索信号)                   │
│    ├── 第11步:设置信号强度                                │
│    └── 第12步:等待 10 秒 → 等 Wi-Fi 连上                  │
│                                                          │
│    ┌─ 如果连上了? ──→ 返回 ESP_OK                        │
│    └─ 如果没连上? ──→ 返回 ESP_FAIL(但芯片继续运行)       │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│  ③ 回到 app_main()                                      │
│    ├── 检查 wifista_init() 返回值                        │
│    │   ├── 成功 → 继续                                    │
│    │   └── 失败 → 打印警告,继续(不阻塞)                  │
│    └── 调用 start_http_server()  ← 去开网站              │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│  ④ start_http_server() 开始(web_server.c)             │
│    ├── 第1步:拿到默认配置(端口80、栈大小4096等)          │
│    ├── 第2步:打开 LRU 清理(内存不够时自动断掉旧连接)     │
│    ├── 第3步:设置通配符匹配(支持 /path/* 这种灵活路由)    │
│    ├── 第4步:调用 httpd_start()  ← 真正创建服务器        │
│    │   ├── 创建 TCP 套接字(相当于装一部电话)              │
│    │   ├── 绑定端口 80(分配电话号码)                      │
│    │   ├── 开始监听(等待别人打电话进来)                    │
│    │   ├── 创建三个后台任务(接电话的、管事的、发消息的)     │
│    │   └── 进入主循环 → 有连接就处理                        │
│    │                                                      │
│    ├── 第5步:注册根路由 "/"                               │
│    │   └── 告诉服务器:如果有人访问首页 → 调用 root_handler │
│    └── 返回 ESP_OK                                        │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│  ⑤ app_main() 结束                                      │
│    └── 打印 "系统初始化完成!"                              │
│    └── 从此,ESP32 就静静地等着别人来访问它的网站了...        │
└─────────────────────────────────────────────────────────┘

当你在浏览器中输入 ESP32 的 IP 地址时:

你的浏览器 ──HTTP 请求 GET /──→ ESP32 的 HTTP 服务器
                                      │
                                      ▼
                           查找路由表 → 找到 "/" 对应 root_handler
                                      │
                                      ▼
                           执行 root_handler(web_server.c)
                              ├── 组装 HTML 页面
                              └── 通过 httpd_resp_send() 发回浏览器
                                      │
                                      ▼
你的浏览器 ←── HTML 网页 ───────── ESP32 返回响应

模块详解

1. 入口模块 — main/esp_web.c

这是整个程序的 "总指挥"。它只做三件事:

void app_main(void)
{
    ESP_LOGI(TAG, "系统启动");          // ① 说一声"我开始工作了"

    wifista_init();                     // ② 连 Wi-Fi(最多等10秒)

    if (start_http_server() != ESP_OK)  // ③ 开网站
        return;

    ESP_LOGI(TAG, "初始化完成");         // ④ 说一声"我搞定了"
}

关键设计:

  • Wi-Fi 即使超时失败,网站也会继续开。这样 ESP32 在没有网络时也能通过局域网访问。
  • 但如果网站开不起来(比如端口被占用了),程序就直接退出。

2. Wi-Fi 模块 — Hardware/wifi_sta

这个模块的任务就是:连上你家的 Wi-Fi。

头文件 wifi_sta.h(公开接口)

// 你可以在代码中改这两个宏来设置 Wi-Fi 名称和密码
#define DEFAULT_SSID    "hhlong"        // ← 改成你家的 Wi-Fi 名字
#define DEFAULT_PWD     "hhlong0326"    // ← 改成你家的 Wi-Fi 密码

esp_err_t wifista_init(void);           // 调用这个函数来连 Wi-Fi

实现文件 wifi_sta.c(背后做了什么)

事件回调机制(新人可能觉得难,这里用生活的例子来解释):

想象你叫了一份外卖:

  1. 你注册了一个回调:你告诉外卖小哥"到了打我电话"(esp_event_handler_register)
  2. 外卖小哥出发了(WIFI_EVENT_STA_START)→ 你什么都不用做,他到了会打你电话
  3. 外卖小哥到了小区门口(WIFI_EVENT_STA_CONNECTED)→ 你记了一下但还不用下楼
  4. 外卖小哥到了你家门口(IP_EVENT_STA_GOT_IP)→ 你终于可以开门拿外卖了!
  5. 外卖小哥走了(WIFI_EVENT_STA_DISCONNECTED)→ 你记了一下,并重新点一份(自动重连)

这就是 事件驱动编程:你不用一直盯着 Wi-Fi 的状态,芯片会在状态变化时自动通知你。

函数 wifista_init() 的 12 个步骤:

步骤 做了什么 生活类比
1 创建事件组(xEventGroupCreate) 准备一个通知板
2 初始化 NVS(nvs_flash_init) 检查存储卡是否正常
3 启动 TCP/IP(esp_netif_init) 搭好网线
4 创建事件循环(esp_event_loop_create_default) 搭好电话线
5 注册回调(esp_event_handler_register) 告诉系统:Wi-Fi 有事就通知我
6 创建网卡(esp_netif_create_default_wifi_sta) 装上网卡硬件
7 初始化 Wi-Fi 驱动(esp_wifi_init) 装上网卡驱动
8 设置为 STA 模式(esp_wifi_set_mode) 设置为"连接热点"模式
9 设置名称和密码(esp_wifi_set_config) 输入你家 Wi-Fi 名称和密码
10 启动 Wi-Fi(esp_wifi_start) 打开 Wi-Fi 开关
11 设置信号强度(esp_wifi_set_max_tx_power) 把发射功率调到最大
12 等待结果(xEventGroupWaitBits) 等外卖,最多等 10 秒

3. Web 服务器模块 — Driver/Web

这个模块的任务是:开一个网站,让别人能访问。

头文件 web_server.h(公开接口)

esp_err_t root_handler(httpd_req_t *req);     // 处理首页访问
esp_err_t start_http_server(void);            // 启动整个服务器

实现文件 web_server.c

start_http_server() 内部流程:

  1. 准备配置 → 拿到 ESP-IDF 的默认 HTTP 服务器配置
  2. 启动服务器 → 调用 httpd_start(),此时 ESP32 开始监听 80 端口
  3. 注册路由 → 告诉服务器:如果有人访问 /,就用 root_handler 处理

root_handler() 做了什么:

当浏览器访问 ESP32 时,这个函数会生成一段完整的 HTML 代码,返回给浏览器。这段 HTML 包含了:

  • 一个深色的卡片式页面
  • 显示 "ESP32 在线" 的状态文字
  • 一个"查看实时画面"按钮(按钮暂时不可用,留给以后扩展)

4. 构建配置 — CMakeLists.txt

顶层 CMakeLists.txt:

cmake_minimum_required(VERSION 3.22)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_web)

这 3 行是 ESP-IDF 项目的固定模板。include(...) 引入了 ESP-IDF 的构建系统,project(esp_web) 声明了项目名称。

components/CMakeLists.txt(最重要的配置):

# 告诉编译器:去这两个目录找源代码
set(src_dirs "Hardware/wifi_sta" "Driver/Web")

# 告诉编译器:去这两个目录找头文件
set(include_dirs "Hardware/wifi_sta" "Driver/Web")

# 告诉编译器:我们这个模块需要依赖以下 ESP-IDF 官方模块
set(requires
    esp_http_server    # HTTP 服务器(Web 模块需要)
    driver             # GPIO 驱动
    esp_driver_uart    # 串口驱动
    nvs_flash          # 存储配置(Wi-Fi 模块需要)
    esp_wifi           # Wi-Fi 功能(Wi-Fi 模块需要)
)

为什么需要 requires?

  • 你在代码里写了 #include "esp_http_server.h",编译器要去哪找这个文件?
  • requires 就是告诉编译器:去 esp_http_server 这个官方模块的目录里找。
  • 不加的话,编译器会报错 esp_http_server.h: No such file or directory。

如何使用

第一步:修改 Wi-Fi 信息

打开 components/Hardware/wifi_sta/wifi_sta.h,把你的 Wi-Fi 名称和密码填进去:

#define DEFAULT_SSID    "你的WiFi名字"      // 注意大小写,不要有中文
#define DEFAULT_PWD     "你的WiFi密码"

第二步:编译

在项目根目录打开终端,执行:

# 设置 ESP-IDF 环境(如果还没设置)
source ~/esp/esp-idf/export.sh

# 选择目标芯片
idf.py set-target esp32s3

# 编译
idf.py build

第一次编译会下载一些依赖,需要几分钟时间。

第三步:烧录到 ESP32

# 用 USB 连接 ESP32 和电脑
# 查看 ESP32 的端口号(Linux/macOS)
ls /dev/ttyUSB*   # 或者 /dev/ttyACM*

# 烧录(把 /dev/ttyUSB0 换成你实际的端口)
idf.py -p /dev/ttyUSB0 flash

# 或者直接烧录 + 打开串口监视器(看芯片的日志输出)
idf.py -p /dev/ttyUSB0 flash monitor

要退出串口监视器,按 Ctrl + ]。

第四步:打开网页

烧录成功后,串口监视器会输出类似这样的日志:

I (1234) wifi_sta: Wi-Fi 连接成功!IP 地址:192.168.1.100
I (1234) web_server: HTTP 服务器启动成功!监听端口 80
I (1234) esp_web: ===== 系统初始化完成!=====

记下 IP 地址(这里是 192.168.1.100),在浏览器的地址栏输入:

http://192.168.1.100

你就能看到 ESP32 的网页了!


如何自定义

想换个 Wi-Fi?

改 wifi_sta.h 中的 DEFAULT_SSID 和 DEFAULT_PWD 即可。

想改网页内容?

修改 web_server.c 中 root_handler() 函数的 html 字符串。HTML 代码就写在 C 代码里,你可以:

  • 修改标题文字
  • 修改按钮链接
  • 修改页面颜色

想添加新的页面路由?

在 web_server.c 的 start_http_server() 函数中,在后面添加:

// 添加 /hello 路由
httpd_uri_t hello_uri = {
    .uri       = "/hello",
    .method    = HTTP_GET,
    .handler   = hello_handler,   // 你需要先实现这个函数
    .user_ctx  = NULL
};
httpd_register_uri_handler(server, &hello_uri);

然后实现 hello_handler 函数:

esp_err_t hello_handler(httpd_req_t *req)
{
    httpd_resp_send(req, "Hello from ESP32!", 17);
    return ESP_OK;
}

想添加摄像头画面?

这个项目的 HTML 中已经预留了 /stream 按钮,后续可以接入 ESP32-CAM 的摄像头功能。


常见问题

Q: 编译时报错 esp_http_server.h: No such file or directory

原因: CMakeLists.txt 的 requires 中没有加上 esp_http_server。

解决: 检查 components/CMakeLists.txt 中是否包含:

set(requires
    esp_http_server    ← 确保这行存在
    ...
)

如果加了还报错,删除 build 目录重新编译:

rm -rf build
idf.py build

Q: 找不到 ESP32 的端口

系统 常见端口
Linux /dev/ttyUSB0 或 /dev/ttyACM0
macOS /dev/cu.usbserial-XXXX 或 /dev/cu.SLAB_USBtoUART
Windows COM3 或 COM4(在设备管理器查看)

如果 Linux 下没有权限,执行:

sudo usermod -a -G dialout $USER
# 然后注销重新登录

Q: ESP32 连不上 Wi-Fi

  1. 检查 SSID 和密码是否写对(注意大小写)
  2. 检查 Wi-Fi 是否是 2.4GHz(ESP32 不支持 5GHz)
  3. 检查 Wi-Fi 是否有中文名称(不支持,请用英文)
  4. 检查路由器是否开启了 MAC 地址过滤
  5. 如果以上都正常,可能是距离太远,把 ESP32 靠近路由器试试

Q: 烧录时报错 A fatal error occurred: Failed to connect to ESP32

原因: ESP32 没有进入下载模式。

解决:

  1. 检查 USB 线是否插紧(有些 USB 线只能充电不能传数据)
  2. 手动进入下载模式:按住 BOOT 键 → 按一下 RESET 键 → 松开 BOOT 键
  3. 然后再试一次烧录命令

下一步做什么

这个项目是一个起点,你可以在此基础上继续扩展:

  1. 添加传感器 — 在 Wi-Fi 模块中添加读取 DHT11 温湿度传感器的代码
  2. 添加控制功能 — 添加 POST 路由,让网页按钮能控制 GPIO 输出(如开关 LED)
  3. 添加摄像头 — 接入 ESP32-CAM 摄像头,实现 /stream 实时视频流
  4. 添加 MQTT — 连接到 MQTT 服务器,实现远程控制
  5. 添加 WebSocket — 实现网页与 ESP32 的实时双向通信

最后的话: 如果你是第一次接触 ESP32 和嵌入式开发,遇到问题很正常。记住三个原则:

  1. 看日志 — ESP32 会在串口输出详细的调试信息,大部分问题的答案都在日志里
  2. 问搜索引擎 — 你遇到的大多数问题,别人早就遇到并解决了
  3. 不要怕改代码 — 代码写错了最多重烧一次,不会烧坏芯片的

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages