ESP32入门开发·使用STA模式连接WIFI(过程详解,源码可直接移植)

目录

1.  功能列表

1.1  支持四个虚拟接口

1.2  三种网络拓扑模式

1.3  支持 IEEE 802.11b/g/n 和 API 配置协议模式

1.4  支持丰富的安全协议

1.5  支持高性能特性 (AMSDU, AMPDU, HT40, QoS)

1.6  支持 Modem-sleep

2.  station 模式下代码编写

2.1  准备工作

2.2  初始化阶段

2.3  配置阶段

2.4  启动阶段

2.5  连接阶段

2.6  获取IP阶段

2.7  完整代码


1.  功能列表

        一些相关功能介绍,了解一下都是什么含义。

1.1  支持四个虚拟接口

        支持 4 个虚拟接口,即 STA、AP、Sniffer 和 reserved。

  • STA (Station) 模式:作为客户端,连接到无线路由器。这是最常见的模式(如手机连Wi-Fi)。
  • AP (Access Point) 模式:作为热点,让其他设备连接到自己。
  • Sniffer (监控) 模式:一种特殊模式,可以捕获空中的所有 Wi-Fi 数据包,用于网络分析、调试或频谱监测。
  • Reserved (保留) 模式:通常为未来功能或特殊用例保留。

1.2  三种网络拓扑模式

        支持仅 station 模式、仅 AP 模式、station/AP 共存模式。

  • Station 模式:作为客户端,连接到现有的无线路由器(就像手机或笔记本电脑连接 Wi-Fi 一样)。这是最常用的模式。
  • SoftAP 模式:自身作为一个 Wi-Fi 热点,让其他设备(如手机、电脑)连接到它。
  • Station+SoftAP 模式:同时工作在两种模式下,既连接到路由器,又自身作为热点。

1.3  支持 IEEE 802.11b/g/n 和 API 配置协议模式

        支持使用 IEEE 802.11b、IEEE 802.11g、IEEE 802.11n 和 API 配置协议模式。

  • 802.11b/g/n:定义了其支持的 Wi-Fi 物理层标准,兼容目前几乎所有 2.4 GHz 频段的路由器。
  • API 配置:指可以通过编程接口(API)动态地配置和切换这些协议模式,例如为了省电或兼容性,可以强制只使用 g 模式。

1.4  支持丰富的安全协议

        支持 WPA/WPA2/WPA3/WPA2-企业版/WPA3-企业版/WAPI/WPS 和 DPP。

  • WPA/WPA2/WPA3:个人用户常用的安全协议,安全性逐代增强。WPA3 提供了更强的保护,防止离线字典攻击。
  • WPA2-企业版/WPA3-企业版:用于公司、学校等大型网络,需要用户名、密码和 RADIUS 服务器进行认证,安全性极高。
  • WAPI:中国强制推行的无线局域网安全标准。
  • WPS:简化路由器连接的功能。
  • DPP:一种更现代、更安全的配网协议,用于替代 WPS,通常通过扫描二维码完成。

1.5  支持高性能特性 (AMSDU, AMPDU, HT40, QoS)

        支持 AMSDU、AMPDU、HT40、QoS 以及其它主要功能。

  • AMSDUs & AMPDUs:将多个数据帧聚合在一起发送,减少了协议开销,大大提高了数据传输效率。
  • HT40:使用 40 MHz 频宽(而不是传统的 20 MHz),使数据传输速率翻倍。
  • QoS:服务质量,可以对网络流量区分优先级(例如,视频通话的数据优先于文件下载),保证关键应用的流畅性。

1.6  支持 Modem-sleep

        一种低功耗模式。在 CPU 工作时,Wi-Fi modem(调制解调器)可以暂时进入睡眠状态,并在预定的时间间隔醒来接收来自路由器的信标(Beacon)。如果路由器没有缓存数据给它,它会立刻再次入睡。

        更多详细可以了解乐鑫官方手册。

2.  station 模式下代码编写

        我们通过官方给定的这个流程去注册使用一下:

2.1  准备工作

        开始前新建一个空白工程,不熟悉可以参考:

ESP32入门开发·VScode空白项目搭建·点亮一颗LED灯-优快云博客

        头文件包含,首先我们想要使用 WIFI 的 API 函数,其头文件肯定要包含:

#include "esp_wifi.h"           // ESP32 WiFi功能库

        然后通过官方手册我们知道,Wi-Fi 事件处理是在 esp_event 库 的基础上进行的,因此我们需要将它的头文件也包含进来:

#include "esp_event.h"          // ESP32事件循环处理库

        然后加一些保存配置和打印日志的头文件,方便查找报错,完整头文件配置:

#include <stdio.h>
#include "nvs_flash.h"          // 非易失性存储(NVS)库,用于保存配置信息
#include "esp_wifi.h"           // ESP32 WiFi功能库
#include "esp_event.h"          // ESP32事件循环处理库
#include "esp_log.h"            // ESP32日志功能库
#include "esp_err.h"            // ESP32错误码定义
#include <string.h>             // 标准字符串操作库

2.2  初始化阶段

        根据流程图我们先进行初始化配置,首先通过调用函数 esp_netif_init() 创建一个 LwIP 核心任务,并初始化 LwIP 相关工作:

    // 初始化TCP/IP网络接口
    ESP_ERROR_CHECK(esp_netif_init());

        其中 ESP_ERROR_CHECK() 是错误检测函数,自动检查ESP-IDF函数的返回值,如果出现错误则立即终止程序执行并输出详细的错误信息。

        然后通过调用函数 esp_event_loop_create() 创建一个系统事件任务,并初始化应用程序事件的回调函数,不过这里我们使用默认事件循环函数 esp_event_loop_create_default() ,默认事件循环是一种特殊循环,用于处理系统事件(如 Wi-Fi 事件)。用户无法使用该循环的句柄,创建、删除、注册/注销处理程序以及事件发布均通过用户事件循环 API 的变体完成,两者其实没有多大差异,唯一区别在于默认事件循环的 API 不需要指定循环句柄,这样可以节省内存而无需创建自己的循环:

    // 创建默认事件循环
    ESP_ERROR_CHECK(esp_event_loop_create_default());

        然后是初始化wifi配置,首先绑定网络接口,我们可以调用函数 esp_netif_create_default_wifi_ap() 或 esp_netif_create_default_wifi_sta() 创建有 TCP/IP 堆栈的默认网络接口实例绑定 station 或 AP,这里我们使用 STA 模式因此调用:

    // 创建默认的WiFi站接口
    esp_netif_create_default_wifi_sta();

        然后同过调用函数 esp_wifi_init() 创建 Wi-Fi 驱动程序任务,并初始化 Wi-Fi 驱动程序,这里我们初始化默认配置,因此调用 wifi_init_config_t 结构体,让其值等于 WIFI_INIT_CONFIG_DEFAULT() ,这个宏会返回一个预配置的默认值集合,这些默认值经过官方测试和优化,适合大多数应用场景,我们直接调用即可:

    // 初始化WiFi配置为默认值
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

        然后创建一个应用程序任务,找到函数:

typedef void (*esp_event_handler_t)(
    void* event_handler_arg,      // 用户自定义参数
    esp_event_base_t event_base,  // 事件基类型
    int32_t event_id,            // 具体事件ID
    void* event_data             // 事件相关数据
);

        把其复制过来,稍微修改一下,创建一个 WIFI 和 IP 事件处理函数:

void wifi_event_handle(void* event_handler_arg, esp_event_base_t event_base,
                      int32_t event_id, void* event_data)
{
}

        内容下边使用的时候进行填充。

2.3  配置阶段

        首先注册WIFI事件处理函数,调用 esp_event_handler_register() 函数,其函数原型:

/**
 * @brief Register an event handler to the system event loop (legacy).
 *
 * This function can be used to register a handler for either: (1) specific events,
 * (2) all events of a certain event base, or (3) all events known by the system event loop.
 *
 *  - specific events: specify exact event_base and event_id
 *  - all events of a certain base: specify exact event_base and use ESP_EVENT_ANY_ID as the event_id
 *  - all events known by the loop: use ESP_EVENT_ANY_BASE for event_base and ESP_EVENT_ANY_ID as the event_id
 *
 * Registering multiple handlers to events is possible. Registering a single handler to multiple events is
 * also possible. However, registering the same handler to the same event multiple times would cause the
 * previous registrations to be overwritten.
 *
 * @param[in] event_base the base ID of the event to register the handler for
 * @param[in] event_id the ID of the event to register the handler for
 * @param[in] event_handler the handler function which gets called when the event is dispatched
 * @param[in] event_handler_arg data, aside from event data, that is passed to the handler when it is called
 *
 * @note the event loop library does not maintain a copy of event_handler_arg, therefore the user should
 * ensure that event_handler_arg still points to a valid location by the time the handler gets called
 *
 * @return
 *  - ESP_OK: Success
 *  - ESP_ERR_NO_MEM: Cannot allocate memory for the handler
 *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event ID
 *  - Others: Fail
 */
esp_err_t esp_event_handler_register(esp_event_base_t event_base,
                                     int32_t event_id,
                                     esp_event_handler_t event_handler,
                                     void *event_handler_arg);

        翻译一下:

/**
* @brief 将事件处理程序注册到系统事件循环(旧版)。*
此函数可用于为以下任一情况注册处理程序:(1)特定事件,(2)某个事件基的所有事件,或者(3)系统事件循环所知的所有事件。*
*  - 具体事件:指定确切的 event_base 和 event_id
*  - 某一基础的所有事件:指定确切的 event_base 并使用 ESP_EVENT_ANY_ID 作为 event_id
*  - 环中已知的所有事件:使用 ESP_EVENT_ANY_BASE 作为 event_base 并使用 ESP_EVENT_ANY_ID 作为 event_id*
可以为事件注册多个处理程序。也可以为多个事件注册单个处理程序。但是,多次为同一事件注册相同的处理程序会导致之前的注册被覆盖。*
* @param[in] event_base 要注册处理程序的事件的基础 ID
* @param[in] event_id 要注册处理程序的事件的 ID
* @param[in] event_handler 当事件分发时被调用的处理程序函数
* @param[in] event_handler_arg 调用处理程序时传递给它的除事件数据之外的数据*
* @注意:事件循环库不会保留 event_handler_arg 的副本,因此用户应确保在调用处理程序时,event_handler_arg 仍指向有效位置。*
* 返回值
*  - ESP_OK:成功
*  - ESP_ERR_NO_MEM:无法为处理程序分配内存
*  - ESP_ERR_INVALID_ARG:事件基和事件 ID 的组合无效
*  - 其他:失败*/

esp_err_t esp_event_handler_register(esp_event_base_t event_base,
                                     int32_t event_id,
                                     esp_event_handler_t event_handler,
                                     void *event_handler_arg);

        对于要注册处理的事件,我们这是wifi事件,所以我们调用 WIFI_EVENT 监听索引 wifi 事件,对于要处理的ID,我们选择所有事件 ID 因此调用 ESP_EVENT_ANY_ID ,调用函数用我们初始化配置的函数 wifi_event_handle ,本次调用数不需要传参因此为 NULL:

    // 注册WiFi事件处理函数
    esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handle, NULL);

        对于IP事件同样的操作:

    // 注册IP事件处理函数
    esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handle, NULL);

        然后是配置wifi链接参数,调用 wifi_config_t 结构体,其函数原型:

/** @brief Configuration data for device's AP or STA or NAN.
 *
 * The usage of this union (for ap, sta or nan configuration) is determined by the accompanying
 * interface argument passed to esp_wifi_set_config() or esp_wifi_get_config()
 *
 */
typedef union {
    wifi_ap_config_t  ap;  /**< configuration of AP */
    wifi_sta_config_t sta; /**< configuration of STA */
    wifi_nan_config_t nan; /**< configuration of NAN */
} wifi_config_t;

        翻译一下:

/** @brief 设备的 AP(接入点)、STA(站点)或 NAN(网络接入节点)的配置数据。*
此联合体的使用方式(适用于 ap、sta 或 nan 配置)由传递给 esp_wifi_set_config() 或 esp_wifi_get_config() 的相关接口参数来决定。*
*/
typedef 结构体如下:
{
    wifi_ap_config_t ap;  /* AP 的配置 */
    wifi_sta_config_t sta; /* STA 的配置 */
    wifi_nan_config_t nan; /* NAN 的配置 */
} wifi_config_t;

        这里对应的就是我们的三种模式,我们使用sta配置,对于sta其要配置的参数如下:

/** @brief STA configuration settings for the device */
typedef struct {
    uint8_t ssid[32];                         /**< SSID of target AP. */
    uint8_t password[64];                     /**< Password of target AP. */
    wifi_scan_method_t scan_method;           /**< do all channel scan or fast scan */
    bool bssid_set;                           /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/
    uint8_t bssid[6];                         /**< MAC address of target AP*/
    uint8_t channel;                          /**< channel of target AP. Set to 1~13 to scan starting from the specified channel before connecting to AP. If the channel of AP is unknown, set it to 0.*/
    uint16_t listen_interval;                 /**< Listen interval for ESP32 station to receive beacon when WIFI_PS_MAX_MODEM is set. Units: AP beacon intervals. Defaults to 3 if set to 0. */
    wifi_sort_method_t sort_method;           /**< sort the connect AP in the list by rssi or security mode */
    wifi_scan_threshold_t  threshold;         /**< When scan_threshold is set, only APs which have an auth mode that is more secure than the selected auth mode and a signal stronger than the minimum RSSI will be used. */
    wifi_pmf_config_t pmf_cfg;                /**< Configuration for Protected Management Frame. Will be advertised in RSN Capabilities in RSN IE. */
    uint32_t rm_enabled:1;                    /**< Whether Radio Measurements are enabled for the connection */
    uint32_t btm_enabled:1;                   /**< Whether BSS Transition Management is enabled for the connection */
    uint32_t mbo_enabled:1;                   /**< Whether MBO is enabled for the connection */
    uint32_t ft_enabled:1;                    /**< Whether FT is enabled for the connection */
    uint32_t owe_enabled:1;                   /**< Whether OWE is enabled for the connection */
    uint32_t transition_disable:1;            /**< Whether to enable transition disable feature */
    uint32_t reserved:26;                     /**< Reserved for future feature set */
    wifi_sae_pwe_method_t sae_pwe_h2e;        /**< Configuration for SAE PWE derivation method */
    wifi_sae_pk_mode_t sae_pk_mode;           /**< Configuration for SAE-PK (Public Key) Authentication method */
    uint8_t failure_retry_cnt;                /**< Number of connection retries station will do before moving to next AP. scan_method should be set as WIFI_ALL_CHANNEL_SCAN to use this config.
                                                   Note: Enabling this may cause connection time to increase incase best AP doesn't behave properly. */
    uint32_t he_dcm_set:1;                                        /**< Whether DCM max.constellation for transmission and reception is set. */
    uint32_t he_dcm_max_constellation_tx:2;                       /**< Indicate the max.constellation for DCM in TB PPDU the STA supported. 0: not supported. 1: BPSK, 2: QPSK, 3: 16-QAM. The default value is 3. */
    uint32_t he_dcm_max_constellation_rx:2;                       /**< Indicate the max.constellation for DCM in both Data field and HE-SIG-B field the STA supported. 0: not supported. 1: BPSK, 2: QPSK, 3: 16-QAM. The default value is 3. */
    uint32_t he_mcs9_enabled:1;                                   /**< Whether to support HE-MCS 0 to 9. The default value is 0. */
    uint32_t he_su_beamformee_disabled:1;                         /**< Whether to disable support for operation as an SU beamformee. */
    uint32_t he_trig_su_bmforming_feedback_disabled:1;            /**< Whether to disable support the transmission of SU feedback in an HE TB sounding sequence. */
    uint32_t he_trig_mu_bmforming_partial_feedback_disabled:1;    /**< Whether to disable support the transmission of partial-bandwidth MU feedback in an HE TB sounding sequence. */
    uint32_t he_trig_cqi_feedback_disabled:1;                     /**< Whether to disable support the transmission of CQI feedback in an HE TB sounding sequence. */
    uint32_t he_reserved:22;                                      /**< Reserved for future feature set */
    uint8_t sae_h2e_identifier[SAE_H2E_IDENTIFIER_LEN];/**< Password identifier for H2E. this needs to be null terminated string */
} wifi_sta_config_t;

        翻译一下:

/** @brief 设备的 STA 配置设置 */
typedef struct {
  uint8_t ssid[32];                         /**< 目标 AP 的 SSID。 */
  uint8_t password[64];                     /**< 目标 AP 的密码。 */
  wifi_scan_method_t scan_method;           /**< 是否进行所有信道扫描或快速扫描 */
  bool bssid_set;                           /**< 是否设置目标 AP 的 MAC 地址。通常,station_config.bssid_set 需要为 0;只有在用户需要检查 AP 的 MAC 地址时才需要设置为 1。 */
  uint8_t bssid[6];                         /**< 目标 AP 的 MAC 地址 */
  uint8_t channel;                          /**< 目标 AP 的信道。设置为 1~13 以从指定的信道开始扫描后再连接到 AP。如果 AP 的信道未知,则将其设置为 0。 */
  uint16_t listen_interval;                 /**< 当 WIFI_PS_MAX_MODEM 设置时,ESP32 站点接收信标时的监听间隔。单位:AP 信标间隔。默认值为 3,如果设置为 0 则为 0。 */
}*/
wifi_sort_method_t 类型的变量“sort_method”:/** 依据 rssi 或安全模式对列表中的连接 AP 进行排序 */
wifi_scan_threshold_t 类型的变量“threshold”:/** 当“scan_threshold”被设置时,只有那些认证模式比所选认证模式更安全且信号强度高于最小 RSSI 的 AP 才会被使用。 */*/
wifi_pmf_config_t pmf_cfg;  /**< 用于保护管理帧的配置。该配置将在 RSN 描述符中的 RSN 属性中进行通告。 */*/
uint32_t rm_enabled:1;  /**< 该连接是否启用无线电测量功能 */
uint32_t btm_enabled:1;  /**< 该连接是否启用 BSS 转换管理功能 */
uint32_t mbo_enabled:1;  /**< 该连接是否启用 MBO 功能 */
uint32_t ft_enabled:1;  /**< 该连接是否启用 FT 功能 */
uint32_t owe_enabled:1;  /**< 该连接是否启用 OWE 功能 */
uint32_t transition_disable:1;  /**< 是否启用连接过渡禁用功能 */
uint32_t reserved:26;  /**< 用于未来功能集预留 */
wifi_sae_pwe_method_t sae_pwe_h2e;  /**< SAE PWE 推导方法的配置 */
wifi_sae_pk_mode_t sae_pk_mode;  /**< SAE-PK(公钥)认证方法的配置 */
uint8_t failure_retry_cnt;  /**< 站点在移动到下一个 AP 之前将进行的连接重试次数。扫描方法应设置为 WIFI_ALL_CHANNEL_SCAN 以使用此配置。
注意:启用此功能可能会导致连接时间增加,如果最佳 AP 的表现不佳。  */*/
uint32_t he_dcm_set:1;                                        /**< 表示是否已设置传输和接收时 DCM(数字编码调制)的最大星座图参数。  */*/
uint32_t he_dcm_max_constellation_tx:2;                       /**< 表示 STA 支持的 TB PPDU 中 DCM 的最大星座数。0:不支持。1:BPSK;2:QPSK;3:16-QAM。默认值为 3。  */*/
uint32_t he_dcm_max_constellation_rx:2;                       /**< 表示 STA 支持的数据字段和 HE-SIG-B 字段中 DCM 的最大星座数。0:不支持。1:BPSK;2:QPSK;3:16-QAM。默认值为 3。  */*/
uint32_t he_mcs9_enabled:1;                                   /**< 是否支持 HE-MCS 0 到 9 的功能。默认值为 0。  */*/
uint32_t he_su_beamformee_disabled:1;                         /**< 是否禁用作为 SU 激发器进行操作的支持功能。  */*/
uint32_t he_trig_su_bmforming_feedback_disabled:1;  /**< 是否禁用在 HE TB 测量序列中支持 SU 反馈的传输功能。  */*/
uint32_t he_trig_mu_bmforming_partial_feedback_disabled:1;  /**< 是否禁用在 HE TB 测量序列中支持部分带宽 MU 反馈的功能。  */*/
uint32_t he_trig_cqi_feedback_disabled:1;  /**< 是否禁用在 HE TB 测量序列中支持 CQI 反馈的传输。  */*/
uint32_t he_reserved:22;                                      /**< 用于未来功能集预留 */
uint8_t sae_h2e_identifier[SAE_H2E_IDENTIFIER_LEN];/**< 用于 H2E 的密码标识符。此标识符需以空字符结尾的字符串 */
} wifi_sta_config_t

        上面说要的配置,在实际使用的时候我们可能不需要这么多,只去我们现在需要的,我这里只是举一个简单的例子,因此就只需要配置其需要连接的网络ID和密码,以及认证模式等:

wifi_config_t wifi_config = {
    .sta = {
        .ssid = "Your_SSID",                    // WiFi名称
        .password = "Your_Password",            // WiFi密码
        .threshold.authmode = WIFI_AUTH_WPA2_PSK, // 认证模式
        .pmf_cfg = {
            .capable = true,      // 支持PMF
            .required = false     // 不强制要求PMF
        },
    }
};

        注意这里的wifi是你想要链接的wifi和密码,我这里手机开了一个热点链接,其宏定义:

#define Your_SSID      "Honor"  // 要连接的WiFi网络名称
#define Your_Password  "www11011211"  // WiFi密码

        不过这里我为了防止之前的数据,因此做了一个清空操作:

    // 配置WiFi连接参数
    wifi_config_t wifi_config = {
        .sta.threshold.authmode = WIFI_AUTH_WPA2_PSK,  // 认证模式为WPA2
        .sta.pmf_cfg.capable = true,      // 支持受保护的管理帧(PMF)
        .sta.pmf_cfg.required = false,    // 不强制要求PMF
    };

    // 清空并设置SSID
    strncpy((char*)wifi_config.sta.ssid, TEST_SSID, sizeof(wifi_config.sta.ssid) - 1);
    wifi_config.sta.ssid[sizeof(wifi_config.sta.ssid) - 1] = '\0'; // 确保null终止

    // 清空并设置密码
    strncpy((char*)wifi_config.sta.password, TEST_PASSWORD, sizeof(wifi_config.sta.password) - 1);
    wifi_config.sta.password[sizeof(wifi_config.sta.password) - 1] = '\0';

        然后调用函数 esp_wifi_set_mode() (WIFI_MODE_STA) 将 Wi-Fi 模式配置为 station 模式。可通过调用其它 esp_wifi_set_xxx API 进行更多设置,例如:协议模式、国家代码、带宽等。请参阅 ESP32-S3 Wi-Fi 配置

    // 设置WiFi为站模式(STA)
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

        调用 esp_wifi_set_config() 应用上述配置:

    // 应用WiFi配置
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

2.4  启动阶段

        调用函数 esp_wifi_start() 启动 Wi-Fi 驱动程序:

    // 启动WiFi
    ESP_ERROR_CHECK(esp_wifi_start());

2.5  连接阶段

        调用函数 esp_wifi_connect() 后,Wi-Fi 驱动程序将启动内部扫描/连接过程,如果内部扫描/连接过程成功,将产生 WIFI_EVENT_STA_CONNECTED 事件。然后,事件任务将启动 DHCP 客户端服务,最终触发 DHCP 程序:

    if(event_base == WIFI_EVENT)  // 处理WiFi相关事件
    {
        switch (event_id)
        {
        case WIFI_EVENT_STA_START:  // 站模式(STA)启动事件
            esp_wifi_connect();     // 开始连接AP
            break;
        case WIFI_EVENT_STA_CONNECTED:  // 成功连接到AP
            ESP_LOGI(TAG,"ESP32已连接到AP!");
            break;
        case WIFI_EVENT_STA_DISCONNECTED:  // 从AP断开连接
            esp_wifi_connect();     // 尝试重新连接
            ESP_LOGI(TAG,"ESP32连接AP失败! 正在重试...");
            break;
        default:
            break;
        }
    }

2.6  获取IP阶段

        DHCP 客户端初始化完成,Wi-Fi 驱动程序将进入获取 IP 阶段,如果 Wi-Fi 成功从 DHCP 服务器接收到 IP 地址,则将引发 IP_EVENT_STA_GOT_IP 事件,事件任务将执行正常处理:

    else if(event_base == IP_EVENT)  // 处理IP相关事件
    {
        switch (event_id)
        {
        case IP_EVENT_STA_GOT_IP:  // 成功获取IP地址
            ESP_LOGI(TAG,"ESP32已获取IP地址");
            break;
        
        default:
            break;
        }
    }

2.7  完整代码

#include <stdio.h>
#include "nvs_flash.h"          // 非易失性存储(NVS)库,用于保存配置信息
#include "esp_wifi.h"           // ESP32 WiFi功能库
#include "esp_event.h"          // ESP32事件循环处理库
#include "esp_log.h"            // ESP32日志功能库
#include "esp_err.h"            // ESP32错误码定义
#include <string.h>             // 标准字符串操作库

#define TEST_SSID      "Honor"  // 要连接的WiFi网络名称
#define TEST_PASSWORD  "www11011211"  // WiFi密码

#define TAG "sta"  // 日志标签

// WiFi和IP事件处理函数
void wifi_event_handle(void* event_handler_arg, esp_event_base_t event_base,
                      int32_t event_id, void* event_data)
{
    if(event_base == WIFI_EVENT)  // 处理WiFi相关事件
    {
        switch (event_id)
        {
        case WIFI_EVENT_STA_START:  // 站模式(STA)启动事件
            esp_wifi_connect();     // 开始连接AP
            break;
        case WIFI_EVENT_STA_CONNECTED:  // 成功连接到AP
            ESP_LOGI(TAG,"ESP32已连接到AP!");
            break;
        case WIFI_EVENT_STA_DISCONNECTED:  // 从AP断开连接
            esp_wifi_connect();     // 尝试重新连接
            ESP_LOGI(TAG,"ESP32连接AP失败! 正在重试...");
            break;
        default:
            break;
        }
    }
    else if(event_base == IP_EVENT)  // 处理IP相关事件
    {
        switch (event_id)
        {
        case IP_EVENT_STA_GOT_IP:  // 成功获取IP地址
            ESP_LOGI(TAG,"ESP32已获取IP地址");
            break;
        
        default:
            break;
        }
    }
}

// 主应用程序入口
void app_main(void)
{
    // 初始化NVS(非易失性存储)
    ESP_ERROR_CHECK(nvs_flash_init());
    // 初始化TCP/IP网络接口
    ESP_ERROR_CHECK(esp_netif_init());
    // 创建默认事件循环
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    // 创建默认的WiFi站接口
    esp_netif_create_default_wifi_sta();
    
    // 初始化WiFi配置为默认值
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    // 注册WiFi事件处理函数
    esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handle, NULL);
    // 注册IP事件处理函数
    esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handle, NULL);

    // 配置WiFi连接参数
    wifi_config_t wifi_config = {
        .sta.threshold.authmode = WIFI_AUTH_WPA2_PSK,  // 认证模式为WPA2
        .sta.pmf_cfg.capable = true,      // 支持受保护的管理帧(PMF)
        .sta.pmf_cfg.required = false,    // 不强制要求PMF
    };

    // 清空并设置SSID
    strncpy((char*)wifi_config.sta.ssid, TEST_SSID, sizeof(wifi_config.sta.ssid) - 1);
    wifi_config.sta.ssid[sizeof(wifi_config.sta.ssid) - 1] = '\0'; // 确保null终止

    // 清空并设置密码
    strncpy((char*)wifi_config.sta.password, TEST_PASSWORD, sizeof(wifi_config.sta.password) - 1);
    wifi_config.sta.password[sizeof(wifi_config.sta.password) - 1] = '\0';

    // 设置WiFi为站模式(STA)
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    // 应用WiFi配置
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    // 启动WiFi
    ESP_ERROR_CHECK(esp_wifi_start());

    return;
}

        验证一下,我们先打开手机热点,将程序下载到板子上:

        可以发现此时板子的IP为192.168.3.45,能够正常获取到IP,假如我们此时关闭手机热点:

        可以看到此时移植在重新连接。

ESP32学习笔记_时光の尘的博客-优快云博客

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光の尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值