ESP32 使用ESP-IDF WiFi一键配网 源码分享

ESP32 使用ESP-IDF WiFi一键配网 源码分享

  • 一、源码分享
  • [二、主流 WIFI 配网方式简介](#二、主流 WIFI 配网方式简介)
    • [1、SoftAP 配网](#1、SoftAP 配网)
    • [2、Smartconfig 配网](#2、Smartconfig 配网)
    • [3、Airkiss 配网](#3、Airkiss 配网)
  • 三、ESP-IDF详解
    • [1、ESP32 概述](#1、ESP32 概述)
    • [2、 ESP-IDF 详解](#2、 ESP-IDF 详解)
      • [2.1 、ESP-IDF 的核心组件与架构](#2.1 、ESP-IDF 的核心组件与架构)
      • [2.2 、ESP-IDF 开发环境与工具链](#2.2 、ESP-IDF 开发环境与工具链)
      • [2.3 、ESP-IDF 开发流程简述](#2.3 、ESP-IDF 开发流程简述)
      • [2.4、 示例代码结构 (最简单的 Hello World)](#2.4、 示例代码结构 (最简单的 Hello World))
      • [2.5、 优势与特点](#2.5、 优势与特点)
      • [2.6 、适用场景](#2.6 、适用场景)
    • 3、总结

一、源码分享

1、效果展示

2、开发环境搭建

参考我这篇博文:VS Code 在线安装ESP-IDF,ESP32开发环境搭建详细教程

3、源码分享

3.1、 main.c

cpp 复制代码
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_eap_client.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
#include "esp_mac.h"

static EventGroupHandle_t s_wifi_event_group;


static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "smartconfig_example";

static void smartconfig_example_task(void * parm);

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        esp_wifi_connect();
        xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
        ESP_LOGI(TAG, "Scan done");
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
        ESP_LOGI(TAG, "Found channel");
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
        ESP_LOGI(TAG, "Got SSID and password");

        smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
        wifi_config_t wifi_config;
        uint8_t ssid[33] = { 0 };
        uint8_t password[65] = { 0 };
        uint8_t rvd_data[33] = { 0 };

        bzero(&wifi_config, sizeof(wifi_config_t));
        memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
        memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));

#ifdef CONFIG_SET_MAC_ADDRESS_OF_TARGET_AP
        wifi_config.sta.bssid_set = evt->bssid_set;
        if (wifi_config.sta.bssid_set == true) {
            ESP_LOGI(TAG, "Set MAC address of target AP: "MACSTR" ", MAC2STR(evt->bssid));
            memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
        }
#endif

        memcpy(ssid, evt->ssid, sizeof(evt->ssid));
        memcpy(password, evt->password, sizeof(evt->password));
        ESP_LOGI(TAG, "SSID:%s", ssid);
        ESP_LOGI(TAG, "PASSWORD:%s", password);
        if (evt->type == SC_TYPE_ESPTOUCH_V2) {
            ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
            ESP_LOGI(TAG, "RVD_DATA:");
            for (int i=0; i<33; i++) {
                printf("%02x ", rvd_data[i]);
            }
            printf("\n");
        }

        ESP_ERROR_CHECK( esp_wifi_disconnect() );
        ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
        esp_wifi_connect();
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
        xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
    }
}

static void initialise_wifi(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    s_wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );

    ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );

    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}

static void smartconfig_example_task(void * parm)
{
    EventBits_t uxBits;
    ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
    smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
    while (1) {
        uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
        if(uxBits & CONNECTED_BIT) {
            ESP_LOGI(TAG, "WiFi Connected to ap");
        }
        if(uxBits & ESPTOUCH_DONE_BIT) {
            ESP_LOGI(TAG, "smartconfig over");
            esp_smartconfig_stop();
            vTaskDelete(NULL);
        }
    }
}

void app_main(void)
{
    ESP_ERROR_CHECK( nvs_flash_init() );
    initialise_wifi();
}

3.2、 运行日志

c 复制代码
I (478) wifi:Init static rx mgmt buffer num: 5
I (482) wifi:Init management short buffer num: 32
I (486) wifi:Init dynamic tx buffer num: 32
I (490) wifi:Init static rx buffer size: 1600
I (494) wifi:Init static rx buffer num: 10
I (498) wifi:Init dynamic rx buffer num: 32
I (502) wifi_init: rx ba win: 6
I (505) wifi_init: accept mbox: 6
I (508) wifi_init: tcpip mbox: 32
I (511) wifi_init: udp mbox: 6
I (513) wifi_init: tcp mbox: 6
I (516) wifi_init: tcp tx win: 5760
I (519) wifi_init: tcp rx win: 5760
I (523) wifi_init: tcp mss: 1440
I (526) wifi_init: WiFi IRAM OP enabled
I (529) wifi_init: WiFi RX IRAM OP enabled
I (534) phy_init: phy_version 4863,a3a4459,Oct 28 2025,14:30:06
I (609) wifi:mode : sta (e8:6b:ea:c4:46:e4)
I (610) wifi:enable tsf
I (611) main_task: Returned from app_main()
I (662) smartconfig: SC version: V3.0.3
I (5477) wifi:ic_enable_sniffer
I (5477) smartconfig: Start to find channel...
I (5478) smartconfig_example: Scan done
I (36916) smartconfig: TYPE: ESPTOUCH
I (36917) smartconfig: T|AP MAC: 18:f2:2c:df:fc:aa
I (36917) smartconfig: Found channel on 11-2. Start to get ssid and password...
I (36920) smartconfig_example: Found channel
I (39362) smartconfig: T|pswd: nimingzi
I (39362) smartconfig: T|ssid: VIP
I (39362) smartconfig: T|bssid: 18:f2:2c:df:fc:aa
I (39362) wifi:ic_disable_sniffer
I (39365) smartconfig_example: Got SSID and password
I (39369) smartconfig_example: Set MAC address of target AP: 18:f2:2c:df:fc:aa 
I (39376) smartconfig_example: SSID:VIP
I (39380) smartconfig_example: PASSWORD:nimingzi
W (39385) wifi:Password length matches WPA2 standards, authmode threshold changes from OPEN to WPA2
I (39408) wifi:new:<11,2>, old:<11,2>, ap:<255,255>, sta:<11,2>, prof:1, snd_ch_cfg:0x0
I (39408) wifi:state: init -> auth (0xb0)
I (39423) wifi:state: auth -> assoc (0x0)
I (39439) wifi:state: assoc -> run (0x10)
I (39533) wifi:connected with VIP, aid = 1, channel 11, 40D, bssid = 18:f2:2c:df:fc:aa
I (39533) wifi:security: WPA2-PSK, phy: bgn, rssi: -54
I (39537) wifi:pm start, type: 1

I (39538) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (39553) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (39581) wifi:<ba-add>idx:0 (ifx:0, 18:f2:2c:df:fc:aa), tid:6, ssn:2, winSize:64
I (41084) esp_netif_handlers: sta ip: 192.168.11.233, mask: 255.255.255.0, gw: 192.168.11.1
I (41084) smartconfig_example: WiFi Connected to ap
I (41240) wifi:<ba-add>idx:1 (ifx:0, 18:f2:2c:df:fc:aa), tid:0, ssn:0, winSize:64
I (44110) smartconfig_example: smartconfig over

3.3、APP下载

点我下载

二、主流 WIFI 配网方式简介

1、SoftAP 配网

ESP32的SoftAP(软件接入点)模式允许设备自身作为WiFi热点,使其他设备(如手机或电脑)能够直接连接。这一功能常用于设备初次配网,用户可通过连接ESP32的热点,在网页界面或专用APP中输入家庭WiFi的账号密码,完成网络配置。

工作原理

  1. 启动SoftAP模式

    ESP32启动时开启热点,生成独立网络:

    此时设备广播热点(如ESP32_AP),用户设备可搜索并连接。

  2. 提供配置接口

    通过HTTP服务器提供配网页面:

    用户通过浏览器访问192.168.4.1(默认AP网关)提交WiFi凭证。

  3. 保存并切换网络

    接收到凭证后,ESP32保存至非易失存储(NVS),并切换至STA模式连接路由器:

2、Smartconfig 配网

SmartConfig 是一种由乐鑫(Espressif)开发并推广的 Wi-Fi 配网技术,主要用于解决物联网设备(如 ESP32)在首次启动时,如何便捷地连接到目标 Wi-Fi 网络的问题。其核心思想是让设备在未预先知道 Wi-Fi 名称(SSID)和密码的情况下,通过监听手机 App 发送的特殊数据包来获取这些网络凭证。

工作原理

  1. 设备进入监听模式

    • 当 ESP32 首次启动或需要重新配网时,它会进入一个特殊的"监听"状态(通常是混杂模式)。
    • 在此状态下,ESP32 会扫描并捕获周围的 Wi-Fi 数据包。
  2. 手机 App 发送配置信息

    • 用户需要在同一 Wi-Fi 网络环境下(通常指手机已连接到目标路由器),打开专用的配网 App(如乐鑫的 Espressif Esptouch App 或其开源实现 ESP-Touch)。
    • 用户在 App 界面输入目标 Wi-Fi 的密码。
    • App 不会直接连接到 ESP32(因为 ESP32 此时还未联网),而是通过手机,向路由器发送一系列特殊格式的 UDP 广播包 或利用数据包长度编码等方式。这些数据包中隐含着目标 Wi-Fi 的 SSID 和密码信息。
  3. ESP32 捕获并解析信息

    • ESP32 在监听状态下捕获这些特殊的数据包。
    • 设备内置的 SmartConfig 协议栈会解析这些数据包,从中提取出加密的 SSID 和密码。
  4. 尝试连接网络

    • 获取到网络凭证后,ESP32 会尝试使用这些信息连接到指定的 Wi-Fi 路由器。
    • 连接成功后,ESP32 通常会通过 UDP 或 TCP 向手机 App(或指定的服务器)发送一个反馈,告知配网成功。此时 App 会显示成功提示。

3、Airkiss 配网

Airkiss 是微信平台推出的一种物联网设备无线网络配置协议,主要用于为 ESP32 等物联网设备提供免手动输入密码的 Wi-Fi 联网功能。其核心原理如下:

  1. 工作原理

    • 广播包传输:用户通过微信小程序向设备发送加密的 Wi-Fi 配置信息(SSID 和密码),数据以 UDP 广播包形式在局域网内传输。
    • 设备监听:ESP32 在混杂模式下监听广播包,通过解析特定格式的数据包获取网络凭证。
    • 加密信道:配置信息通过微信服务器加密传输,确保安全性。
  2. 优势

    • 免输入:用户无需在设备界面手动输入 Wi-Fi 密码。
    • 跨平台支持:兼容 Android/iOS 设备。
    • 低功耗:ESP32 可在低功耗模式下完成配网。

三、ESP-IDF详解

1、ESP32 概述

ESP32 是由乐鑫科技(Espressif Systems)推出的一款高性能、低功耗、高集成度的 Wi-Fi & 蓝牙双模系统级芯片(SoC)。它广泛应用于物联网(IoT)、智能家居、工业控制等领域。其关键特性包括:

  • 双核处理器(通常为 Xtensa LX6,某些型号为 RISC-V)
  • 集成 Wi-Fi (802.11 b/g/n) 和蓝牙 (包括经典蓝牙和低功耗蓝牙 BLE)
  • 丰富的外设接口: S P I SPI SPI, I 2 C I2C I2C, I 2 S I2S I2S, U A R T UART UART, A D C ADC ADC, D A C DAC DAC, P W M PWM PWM, 触摸传感器等
  • 充足的内存(RAM 和 Flash 选项多样)
  • 强大的安全特性(如加密加速器)
  • 超低功耗设计,支持多种休眠模式

2、 ESP-IDF 详解

ESP-IDF (Espressif IoT Development Framework) 是乐鑫官方为 ESP32、ESP32-S 系列、ESP32-C 系列等芯片提供的开发框架和 SDK(软件开发工具包)。它是开发基于 ESP32 芯片应用程序的首选和官方推荐工具。

2.1 、ESP-IDF 的核心组件与架构

ESP-IDF 是一个分层、模块化的框架:

  • 硬件抽象层 (HAL): 提供对芯片硬件资源(如 GPIO、UART、SPI、I2C、定时器、ADC、DAC、RTC、Wi-Fi、蓝牙等)进行操作的统一接口,屏蔽底层硬件细节。
  • 驱动 (Drivers): 在 HAL 之上,提供更易用、功能更丰富的设备驱动(如 SPI Flash 驱动、SD 卡驱动、以太网驱动等)。
  • FreeRTOS: ESP-IDF 深度集成了开源的 FreeRTOS 实时操作系统内核。它提供了任务管理、队列、信号量、软件定时器、中断管理等机制,充分利用 ESP32 的多核特性(任务可以在不同核心上运行)。
  • 中间件:
    • Wi-Fi 协议栈: 实现 Wi-Fi 的 Station(客户端)、SoftAP(接入点)、Promiscuous(监听)模式。
    • 蓝牙协议栈: 实现经典蓝牙和低功耗蓝牙 (BLE) 的各种角色(如 GATT Client/Server, GAP Central/Peripheral)。
    • TCP/IP 协议栈 (lwIP): 轻量级的 TCP/IP 协议栈,支持 IPv4/IPv6 (部分型号)、DHCP、DNS、Socket API 等。
    • 文件系统 (FATFS/VFS): 支持在 SPI Flash 或外部存储设备上使用 FAT 文件系统。
    • 加密库: 提供 AES、SHA、RSA 等加密算法的软件和硬件加速实现。
    • HTTP/WebSocket/MQTT 等协议库: 方便构建网络应用。
  • 应用程序: 用户编写的业务逻辑代码,运行在 FreeRTOS 的任务中,通过调用下层 API 实现功能。

2.2 、ESP-IDF 开发环境与工具链

  • 工具链: 基于 GNU GCC 编译器(针对 Xtensa 或 RISC-V 架构)。
  • 构建系统: 使用 CMake (早期版本使用 GNU Make)。开发者编写 CMakeLists.txt 文件来定义项目结构、源文件、依赖组件等。
  • 配置工具: menuconfig。这是一个基于文本的图形化配置工具(类似于 Linux Kernel 的 make menuconfig),用于配置 ESP-IDF 的众多选项,如:
    • 选择目标芯片型号
    • 配置 Wi-Fi/BT 参数
    • 调整 FreeRTOS 设置(任务栈大小、优先级等)
    • 配置日志输出级别和方式
    • 配置内存布局
    • 启用/禁用特定功能和外设驱动
  • 核心工具 - idf.py 这是 ESP-IDF 提供的命令行工具,用于执行构建、烧录、调试、监视串口输出等几乎所有开发任务。常用命令如:
    • idf.py set-target esp32 (设置目标芯片)
    • idf.py menuconfig (启动配置工具)
    • idf.py build (编译项目)
    • idf.py -p PORT flash (烧录固件到设备,PORT 为串口,如 COM3 或 /dev/ttyUSB0)
    • idf.py -p PORT monitor (启动串口监视器,查看设备日志输出)
    • idf.py fullclean (彻底清理构建目录)

2.3 、ESP-IDF 开发流程简述

  1. 环境搭建: 在 Windows、Linux 或 macOS 上安装 ESP-IDF 开发环境(包括工具链、Python、Git 等)。
  2. 创建项目: 使用 idf.py create-project 或复制示例项目模板。
  3. 编写代码:main 目录下编写应用程序代码 (通常是 main.capp_main() 函数)。
  4. 配置项目: 运行 idf.py menuconfig 根据需求进行配置。
  5. 编译项目: 运行 idf.py build 生成可执行固件 (.bin 文件)。
  6. 烧录固件: 将 ESP32 开发板连接到电脑,运行 idf.py -p PORT flash 将固件烧录到设备 Flash 中。
  7. 监视输出: 运行 idf.py -p PORT monitor 查看设备运行日志,进行调试。可以使用 ESP_LOGx (如 ESP_LOGI, ESP_LOGE) 函数打印不同级别的日志。

2.4、 示例代码结构 (最简单的 Hello World)

c 复制代码
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

static const char *TAG = "MAIN";

void app_main(void)
{
    while (1) {
        ESP_LOGI(TAG, "Hello World!"); // 打印 Info 级别日志
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 1000 毫秒 (FreeRTOS 延时)
    }
}

2.5、 优势与特点

  • 官方支持: 由芯片原厂维护,更新及时,与新芯片特性同步快。
  • 功能全面: 提供对 ESP32 所有硬件特性和外设的底层访问。
  • 性能优化: 针对 ESP32 硬件进行了深度优化(如 Wi-Fi/BT 共存)。
  • 稳定性高: 经过大量商业产品验证。
  • 社区活跃: 用户多,社区支持好,问题容易找到解决方案。
  • 文档完善: 官方提供详尽的 API 参考指南、编程指南和示例代码。
  • 模块化: 易于扩展和复用代码,方便管理大型项目。
  • 开源免费: 基于 Apache 2.0 许可证。

2.6 、适用场景

ESP-IDF 适用于需要深度控制硬件、追求高性能、高稳定性或需要使用 ESP32 特有功能(如超低功耗协处理器 ULP)的应用开发。对于快速原型开发,也可以考虑基于 ESP-IDF 构建的更高级框架(如 Arduino for ESP32、MicroPython),但这些框架最终都依赖于 ESP-IDF 的底层功能。

3、总结

ESP-IDF 是开发 ESP32 系列芯片的强大、灵活且功能完备的官方框架。它提供了从硬件操作到网络协议栈的全套解决方案,结合 FreeRTOS 实现了高效的多任务处理。虽然其学习曲线相对陡峭,尤其是对于不熟悉嵌入式开发和 RTOS 的开发者,但它提供了最直接、最强大的方式来充分利用 ESP32 的潜力,是开发复杂或高性能 ESP32 应用的基石。掌握 idf.py 工具链和 menuconfig 配置是使用 ESP-IDF 的关键。

相关推荐
风痕天际6 小时前
ESP32-S3开发教程6:硬件定时器
单片机·嵌入式硬件·嵌入式·esp32·freertos·esp32s3
小灰灰搞电子7 小时前
ESP32+ESP-IDF 使用MQTT协议连接阿里云物联网平台源码分享
物联网·阿里云·esp32
小灰灰搞电子1 天前
ESP32 使用ESP-IDF 驱动红外遥控器源码分享
esp32·红外遥控
勇敢牛牛_1 天前
ESP32 + Rust 开发的简易语音助手
rust·嵌入式·esp32·语音助手
liwulin05063 天前
【ESP32-S3】ESP32-S3 + YDLIDAR X2 + ROS2 远程导航完整落地方案
esp32·ros2·ydlidar
风痕天际3 天前
ESP32-S3开发教程五-按键中断2(使用FreeRTOS)
单片机·嵌入式硬件·esp32·vs code·esp32s3·esp-idf
戏舟的嵌入式开源笔记4 天前
基于ESP32(PIO+Arduino)简单上手LVGL9
esp32·嵌入式软件
小灰灰搞电子4 天前
ESP32 使用ESP-IDF 建立WiFi热点(AP模式)并使用TCP客户端通信源码分享
tcp/ip·esp32·esp-idf
whik11945 天前
ESP32-C3-DevKitM-1开发板深度上手评测
wifi·嵌入式·esp32·arduino·蓝牙·开发板·乐鑫