ESP32C3Wi-Fi连接初体验

本文详细介绍了如何使用ESP-IDF组件控制ESP32-C3设备在STA模式下连接到路由器,包括初始化、配置、启动、连接、获取IP、断开和清理等步骤,涉及Wi-Fi事件处理和LwIP组件的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


1. 设定STA模式,连接到AP

处于STA模式下的ESP32-C3,可以作为STA连接到AP,在此模式下设备可以通过AP分配的IP地址直接访问外网和内网。可以通过menuconfig->Example_Configuration中配置Wi-Fi的SSID以及Password。

在这里插入图片描述



2. 如何使用ESP-IDF的组件控制设备连接到路由器

使用ESP-IDF的组件控制设备连接到路由器的流程如图所示。

在这里插入图片描述



(1)初始化阶段:
  • 初始化LwIP。创建LwIP核心任务并初始化与LwIP相关的工作。
ESP_ERROR_CHECK(esp_netif_init());
  • 初始化事件。Wi-Fi事件处理基于esp-event组件,Wi-Fi驱动程序会将事件发送到默认事件循环。应用程序可以在esp_event_handler_register()中的回调函数中处理这些事件。esp_netif组件还会处理Wi-Fi事件,以提供一组默认行为。 例如,当ESP32-C3连接到AP时,esp_netif将自动启动DHCP客户端(默认情况下)。初始化事件的代码如下:
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();

//...

esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                    ESP_EVENT_ANY_ID,
                                                    &event_handler,
                                                    NULL,
                                                    &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                    IP_EVENT_STA_GOT_IP,
                                                    &event_handler,
                                                    NULL,
                                                    &instance_got_ip));
  • 初始化Wi-Fi。创建Wi-Fi驱动程序任务,并初始化Wi-Fi驱动程序。 初始化Wi-Fi的代码如下:
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));

(2)配置阶段

Wi-Fi驱动程序初始化成功后,进入配置阶段。在该阶段中,Wi-Fi驱动程序处于STA模式,调用esp_wifi_set_mode(WIFI_MODE_STA)函数将ESP32-C3模式配置为STA模式。

wifi_config_t wifi_config = {
    .sta = {
        .ssid = EXAMPLE_ESP_WIFI_SSID,
        .password = EXAMPLE_ESP_WIFI_PASS,
    },
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

(3)启动阶段

调用esp_wifi_start()函数启动Wi-Fi驱动程序,Wi-FI驱动程序将WIFI_EVENT_STA_START发布到事件任务,事件任务将执行一些常规操作,并将调用应用程序事件回调函数。应用程序事件回调函数将WIFI_EVENT_STA_START中继到应用程序任务,此时调用函数esp_wifi_connect()。

ESP_ERROR_CHECK(esp_wifi_start());

(4)连接阶段

一旦esp_wifi_connect()函数被调用,Wi-Fi驱动程序将开始内部扫描/连接过程。如果内部扫描/连接过程成功,则生成WIFI_EVENT_STA_CONNECTED。在事件任务中,将启动DHCP客户端,该客户端最终将触发DHCP进程。(底层实现)

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) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

(5)获取IP阶段

初始化DHCP客户端后,将进入获取IP地址阶段,如果从DHCP服务器成功接收到IP地址,则将触发IP_EVENT_STA_GOT_IP事件,并在事件任务中进行常规处理。在应用程序事件回调函数中,IP_EVENT_STA_GOT_IP被传递到应用程序任务。对于基于LwIP的应用程序已准备就绪,可以开始其他任务。但在接收IP之前,请勿进行与套接字相关的工作。


(6)断开阶段

由于主动断开连接、密码错误、找不到AP等原因,Wi-FI连接可能会失败。在这种情况下,会触发WIFI_EVENT_STA_DISCONNECTED事件并提供失败的原因,如调用esp_wifi_disconnect()函数以主动断开连接。


ESP_ERROR_CHECK(esp_wifi_disconnect());
(7)IP更改阶段

如果IP地址发生变化,将触发IP_EVENT_STA_GOT_IP事件,在该事件中将ip_change设置为true。


(8)清理阶段

包括断开Wi-Fi连接、终止Wi-Fi驱动程序、清理Wi-Fi驱动程序等。

ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));

ESP_ERROR_CHECK(esp_wifi_stop());
ESP_ERROR_CHECK(esp_wifi_deinit());

ESP_ERROR_CHECK(esp_wifi_clear_default_wifi_driver_and_handlers(station_netif));
esp_netif_destroy(station_netif);
<think>我们被要求配置ESP32-C2通过Web服务器连接Wi-Fi。这通常意味着我们要在ESP32-C2上运行一个Web服务器,当设备启动时,它进入配置模式(作为AP),用户可以通过浏览器访问该Web服务器,输入本地Wi-Fi网络的SSID和密码,然后设备将这些凭证保存并尝试连接到该网络。 参考引用[1]和[2]提到ESP32-C2支持Wi-Fi和BLE,我们可以利用其Wi-Fi功能。引用[5]提供了一个使用esp-idfWi-Fi初始化的示例代码,但我们需要的是更高级的配置:通过Web服务器接收Wi-Fi凭证。 步骤概述: 1. 初始化ESP32-C2的Wi-Fi为AP模式,创建一个配置用的热点。 2. 启动一个Web服务器,提供简单的配置页面。 3. 用户通过浏览器访问该页面,输入目标Wi-Fi的SSID和密码。 4. Web服务器接收表单数据,保存到非易失性存储(NVS)。 5. 设备重启或切换为STA模式,使用保存的凭证连接目标Wi-Fi。 6. 如果连接成功,则关闭AP模式(或保持双模式,根据需求),并告知用户配置成功。 我们将使用ESP-IDF框架进行开发。由于引用[5]中提到了使用esp-idf-v5.1.1,我们将基于此版本编写代码。 详细步骤: 步骤1:设置项目环境 确保已安装ESP-IDF v5.1.1,并设置好环境。 步骤2:包含必要的头文件 在main.c中包含以下头文件: ```c #include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" #include "esp_http_server.h" #include "nvs_flash.h" #include "esp_system.h" #include "esp_netif.h" ``` 步骤3:初始化NVS(非易失性存储) 用于保存Wi-Fi凭证。 ```c void initialize_nvs() { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); } ``` 步骤4:创建默认事件循环和网络接口 参考引用[5]的示例。 步骤5:配置AP模式 设置一个热点,用户可以通过手机或电脑连接此热点,然后访问Web服务器。 步骤6:启动Web服务器 使用ESP-IDF的HTTP服务器组件,创建一个简单的Web服务器,提供配置页面。 步骤7:处理HTTP请求 我们需要两个基本的HTTP请求处理: - GET /:返回一个HTML表单,用于输入SSID和密码。 - POST /configure:接收表单提交的SSID和密码,保存到NVS,然后尝试连接。 步骤8:保存凭证并连接目标Wi-Fi 从POST请求中获取SSID和密码,保存到NVS,然后重启设备(或直接切换模式尝试连接)。 步骤9:连接目标Wi-Fi 使用保存的凭证连接目标Wi-Fi。 步骤10:处理连接结果 连接成功则切换到STA模式(关闭AP模式可选),失败则返回配置页面(或保持AP模式以便重新配置)。 考虑到代码量较大,这里只给出关键部分的代码示例。 代码示例: 首先,定义一些全局变量和常量: ```c static const char *TAG = "wifi_config"; // 用于存储Wi-Fi配置的结构体 typedef struct { char ssid[32]; char password[64]; } wifi_config_t; ``` 初始化AP模式: ```c void start_ap_mode() { esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); wifi_config_t wifi_ap_config = { .ap = { .ssid = "ESP32-C2_Config", // AP的SSID .password = "12345678", // 密码,至少8位 .ssid_len = strlen("ESP32-C2_Config"), .max_connection = 4, .authmode = WIFI_AUTH_WPA_WPA2_PSK }, }; if (strlen("12345678") == 0) { wifi_ap_config.ap.authmode = WIFI_AUTH_OPEN; } ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_ap_config)); ESP_ERROR_CHECK(esp_wifi_start()); ESP_LOGI(TAG, "AP mode started. SSID: %s, Password: %s", wifi_ap_config.ap.ssid, wifi_ap_config.ap.password); } ``` 创建HTTP服务器: ```c httpd_handle_t start_webserver(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); httpd_handle_t server = NULL; if (httpd_start(&server, &config) == ESP_OK) { // 注册URI处理函数 httpd_register_uri_handler(server, &uri_get); httpd_register_uri_handler(server, &uri_post); return server; } return NULL; } ``` 定义GET和POST的URI处理结构体: ```c // GET处理函数:返回配置页面 static const httpd_uri_t uri_get = { .uri = "/", .method = HTTP_GET, .handler = get_handler, .user_ctx = NULL }; // POST处理函数:接收配置数据 static const httpd_uri_t uri_post = { .uri = "/configure", .method = HTTP_POST, .handler = post_handler, .user_ctx = NULL }; ``` GET处理函数返回一个简单的HTML表单: ```c static esp_err_t get_handler(httpd_req_t *req) { const char* html_form = "<!DOCTYPE html><html><body>" "<h2>Wi-Fi Configuration</h2>" "<form action=\"/configure\" method=\"post\">" "SSID: <input type=\"text\" name=\"ssid\"><br>" "Password: <input type=\"password\" name=\"password\"><br>" "<input type=\"submit\" value=\"Connect\">" "</form></body></html>"; httpd_resp_set_type(req, "text/html"); httpd_resp_send(req, html_form, strlen(html_form)); return ESP_OK; } ``` POST处理函数接收表单数据,保存到NVS,并尝试连接: ```c static esp_err_t post_handler(httpd_req_t *req) { char content[100]; size_t recv_size = MIN(req->content_len, sizeof(content)); int ret = httpd_req_recv(req, content, recv_size); if (ret <= 0) { return ESP_FAIL; } content[recv_size] = &#39;\0&#39;; // 解析表单数据(简单起见,这里假设只有两个字段) char ssid[32] = {0}; char password[64] = {0}; // 实际应用中应使用更健壮的解析方式(如urldecode和字符串解析) // 这里仅作示例,假设表单数据格式为: ssid=...&password=... char *ptr = strstr(content, "ssid="); if (ptr) { ptr += 5; // 跳过"ssid=" char *end = strchr(ptr, &#39;&&#39;); if (end) { *end = &#39;\0&#39;; url_decode(ptr, ssid, sizeof(ssid)); } else { // 如果没有&,则取到字符串末尾 url_decode(ptr, ssid, sizeof(ssid)); } } ptr = strstr(content, "password="); if (ptr) { ptr += 9; // 跳过"password=" url_decode(ptr, password, sizeof(password)); } // 保存到NVS save_wifi_config(ssid, password); // 返回响应,提示正在连接 const char* response = "<html><body><h1>Configuration saved. Connecting to Wi-Fi...</h1></body></html>"; httpd_resp_send(req, response, strlen(response)); // 延迟一段时间后重启(或者直接切换模式连接) vTaskDelay(2000 / portTICK_PERIOD_MS); esp_restart(); return ESP_OK; } ``` 注意:这里需要实现`url_decode`函数和`save_wifi_config`函数。 保存Wi-Fi配置到NVS的示例: ```c void save_wifi_config(const char* ssid, const char* password) { nvs_handle_t nvs; ESP_ERROR_CHECK(nvs_open("storage", NVS_READWRITE, &nvs)); ESP_ERROR_CHECK(nvs_set_str(nvs, "ssid", ssid)); ESP_ERROR_CHECK(nvs_set_str(nvs, "password", password)); ESP_ERROR_CHECK(nvs_commit(nvs)); nvs_close(nvs); } ``` 在`app_main`函数中,我们需要: 1. 初始化NVS 2. 尝试从NVS读取保存的Wi-Fi配置,如果存在则连接目标Wi-Fi(STA模式) 3. 如果连接失败(或没有保存的配置),则进入AP模式并启动Web服务器 连接目标Wi-Fi的函数可以参考引用[5]中的`example_connect()`,但这里我们需要自己实现。 注意:为了简化,我们可能需要在连接失败时重新进入配置模式。在实际应用中,可能需要一个超时机制,比如尝试连接多次失败后重新开启AP模式。 由于代码较长,以上仅为核心步骤和代码片段。实际开发中还需要考虑错误处理、内存释放、事件处理等。 最后,编译并烧录到ESP32-C2设备。 相关问题: 1. 如何从NVS中读取保存的Wi-Fi配置? 2. 如何实现URL解码(url_decode)? 3. 如何实现连接目标Wi-Fi的函数? 4. 如何让设备在连接目标Wi-Fi失败后自动回到配置模式? 5. 如何优化Web界面,使其更美观易用? 6. 如何增加安全性(例如,配置热点的密码强度,防止未授权访问)? 根据用户要求,生成相关问题如下:</think>### ESP32-C2 通过 Web 服务器配置 Wi-Fi 连接指南 以下是基于 ESP-IDF 框架的详细配置步骤(以 V5.1.1 为例): --- #### **步骤 1:初始化基础组件** ```c #include "esp_wifi.h" #include "esp_http_server.h" #include "nvs_flash.h" #include "esp_event.h" void app_main() { // 初始化 NVS 存储(保存 Wi-Fi 凭证) esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); // 初始化网络和事件循环 ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); } ``` --- #### **步骤 2:启动 AP 模式(配置热点)** ```c void start_ap_mode() { esp_netif_create_default_wifi_ap(); // 创建 AP 接口 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // 设置 AP 配置 wifi_config_t ap_config = { .ap = { .ssid = "ESP32-C2_Config", // 热点名称 .password = "12345678", // 至少 8 位密码 .max_connection = 4, .authmode = WIFI_AUTH_WPA_WPA2_PSK } }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &ap_config)); ESP_ERROR_CHECK(esp_wifi_start()); } ``` --- #### **步骤 3:创建 Web 服务器** ```c // 处理根目录请求(返回配置页面) static esp_err_t root_handler(httpd_req_t *req) { const char* html_form = "<form action=&#39;/save&#39; method=&#39;post&#39;>" "SSID: <input type=&#39;text&#39; name=&#39;ssid&#39;><br>" "Password: <input type=&#39;password&#39; name=&#39;password&#39;><br>" "<input type=&#39;submit&#39; value=&#39;Connect&#39;>" "</form>"; httpd_resp_set_type(req, "text/html"); httpd_resp_send(req, html_form, HTTPD_RESP_USE_STRLEN); return ESP_OK; } // 处理表单提交 static esp_err_t save_handler(httpd_req_t *req) { char content[100]; int recv_len = httpd_req_recv(req, content, sizeof(content)); // 解析 SSID 和密码 char ssid[32] = {0}; char password[64] = {0}; sscanf(content, "ssid=%[^&]&password=%s", ssid, password); // 保存到 NVS nvs_handle_t nvs; nvs_open("wifi_config", NVS_READWRITE, &nvs); nvs_set_str(nvs, "ssid", ssid); nvs_set_str(nvs, "password", password); nvs_commit(nvs); nvs_close(nvs); // 返回响应 httpd_resp_send(req, "Wi-Fi配置已保存!设备将重启连接...", HTTPD_RESP_USE_STRLEN); vTaskDelay(2000 / portTICK_PERIOD_MS); esp_restart(); // 重启以连接新网络 return ESP_OK; } // 启动 Web 服务器 void start_webserver() { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); httpd_handle_t server = NULL; if (httpd_start(&server, &config) == ESP_OK) { httpd_register_uri_handler(server, &(httpd_uri_t){ .uri = "/", .method = HTTP_GET, .handler = root_handler }); httpd_register_uri_handler(server, &(httpd_uri_t){ .uri = "/save", .method = HTTP_POST, .handler = save_handler }); } } ``` --- #### **步骤 4:连接目标 Wi-Fi(重启后执行)** ```c void connect_to_wifi() { // 从 NVS 读取凭证 char ssid[32], password[64]; nvs_handle_t nvs; nvs_open("wifi_config", NVS_READONLY, &nvs); nvs_get_str(nvs, "ssid", ssid, sizeof(ssid)); nvs_get_str(nvs, "password", password, sizeof(password)); nvs_close(nvs); // 配置 STA 模式 esp_netif_create_default_wifi_sta(); wifi_config_t sta_config = { .sta = { .ssid = "", .password = "", } }; strcpy((char*)sta_config.sta.ssid, ssid); strcpy((char*)sta_config.sta.password, password); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &sta_config)); ESP_ERROR_CHECK(esp_wifi_connect()); } ``` --- #### **主函数逻辑** ```c void app_main() { initialize_nvs(); // 步骤 1 // 检查是否已有保存的凭证 nvs_handle_t nvs; if (nvs_open("wifi_config", NVS_READONLY, &nvs) == ESP_OK) { size_t ssid_len = 0; if (nvs_get_str(nvs, "ssid", NULL, &ssid_len) == ESP_OK && ssid_len > 0) { connect_to_wifi(); // 步骤 4 return; } } // 无凭证则进入配置模式 start_ap_mode(); // 步骤 2 start_webserver(); // 步骤 3 } ``` --- ### **关键说明** 1. **工作流程** - 设备首次启动时创建热点 `ESP32-C2_Config` - 用户连接热点后访问 `http://192.168.4.1` 输入 Wi-Fi 凭证 - 凭证保存后设备重启并自动连接目标网络 2. **安全建议** - 在 `save_handler` 中增加输入验证(如 SSID 长度检查) - 使用 HTTPS 需配置 SSL 证书(需额外存储空间) 3. **优化方向** - 添加连接状态反馈(如 LED 指示灯) - 实现 **双重模式(AP+STA)**,配置时不中断服务 - 通过 `esp_event_handler` 监听 `WIFI_EVENT_STA_CONNECTED` 事件[^5] > **注意**:ESP32-C2 的 RISC-V 架构需使用 ESP-IDF 的 RISC-V 工具链编译[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值