本工程已托管到 GitHub,具体路径是 https://github.com/tidyjiang8/esp32-projects/tree/master/sta
功能说明:将 ESP32 当做一个 STA,连接到一个 WiFi 热点。
关于 ESP32 更多好玩、有趣、实用的项目,请查看 【ESP32 系列博客 - 目录】
COM\*
, Linux 是/dev/ttyUSB\*
)。sta
所在目录。make menuconfig
进行配置。 Demo Configuration --->
,然后在WiFi SSID
和WiFi Password
中填写你的 SSID 和密码。然后退出配置菜单,保存配置。make
进行编译make flash monitor
将编译生成的镜像烧写到 ESP32 开发板上面,并查看串口输出。串口输出如下图所示,从图中框出的部分可以看出,我们的 ESP32 已经成功连接到热点,并获取到 IP 地址了。
整个源码非常简单,一共就几十行代码,几乎都是在调用 ESP-IDF 给我们提供的接口,整个过程的流程如下:
上面这个流程中,我们需要强调的有三处:
esp_event_loop_init()
esp_wifi_set_mode()
esp_wifi_set_config()
在 ESP-IDF 中,整个 wifi 协议栈是一个状态机,它在各个时刻都有一个状态。用户可以根据自己的需要,让协议栈在某个状态时自动处理某些工作。在调用 esp_event_loop_init()
函数时 ,我们传入了一个参数 event_handler
,它是一个函数指针,当wifi状态机的状态变化时,会调用函数 event_handler()
,并给它传递适当的参数。这一部分内容我们将在下一篇博客中详细介绍,所以这里就不再说明,请参考深入分析 ESP32 的 WiFi 状态机
ESP32 支持三种 wifi 模式,它们被定义为三个枚举值:
typedef enum {
WIFI_MODE_NULL = 0, /**< null mode */
WIFI_MODE_STA, /**< WiFi station mode */
WIFI_MODE_AP, /**< WiFi soft-AP mode */
WIFI_MODE_APSTA, /**< WiFi station + soft-AP mode */
WIFI_MODE_MAX
} wifi_mode_t;
第一个枚举值WIFI_MODE_NULL
和最后一个枚举值WIFI_MODE_MAX
只是一个标记,不是真正支持的模式,因此支持的模式包括:
设置模式的接口为 esp_err_t esp_wifi_set_mode(wifi_mode_t mode);
,它需要的参数就是我们上面所看到的三种模式中的其中一个。
另外还有一个问题,WIFI_MODE_NULL
和 WIFI_MODE_MAX
有啥作用?在函数 esp_wifi_set_mode
内部,可以通过这两个值来进行入参检测,判断传入的参数是否有效。
在上面设置 wifi 模式时,wifi 库会根据我们传入的参数来分配接口。如果我们传入的参数是 WIFI_MODE_STA
,则 wifi 库会创建一个 sta 接口;如果我们传入的参数是 WIFI_MODE_AP
,则 wifi 库会创建一个 ap 接口;如果我们传入的参数是 WIFI_MODE_APSTA
,则 wif 库会同时创建一个 sta 接口和一个 ap 接口。wifi 库在运行时需要知道这些接口的参数,所以我们需要在启动 wifi 前设置接口的参数。
设置 wifi 接口参数的 API 原型是 esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf);
,包含两个参数:
wifi_interface_t ifx
,即需要配置的接口wifi_config_t *conf
,即传递给该接口的参数sta 接口和 ap 接口需要的参数是不同的,这里一定要注意,它们通过一个 联合体 来定义的:
typedef union {
wifi_ap_config_t ap; /**< AP 的配置 */
wifi_sta_config_t sta; /**< STA 的配置 */
} wifi_config_t;
对于 sta 接口,需要配置的参数一般包括 ssid
和 password
。注意,这里的ssid
和password
的长度是由限制的,具体请看结构体:
typedef struct {
uint8_t ssid[32]; /**< SSID of target AP*/
uint8_t password[64]; /**< password of target AP*/
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.*/
} wifi_sta_config_t;
对于 ap 接口,第一个需要确定的参数是 authmode
,即客户端连接到这个 AP 时的授权模式。如果配置的授权模式是 WIFI_AUTH_OPEN
,则不再需要配置其它参数。否则,则需要根据授权模式来判断还需要其它啥参数,不过一般都至少还需要 ssid
和 password
两个参数,其它参数的作用请自行研究。ap 接口的配置结构体如下:
typedef struct {
uint8_t ssid[32]; /**< SSID of ESP32 soft-AP */
uint8_t password[64]; /**< Password of ESP32 soft-AP */
uint8_t ssid_len; /**< Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len. */
uint8_t channel; /**< Channel of ESP32 soft-AP */
wifi_auth_mode_t authmode; /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */
uint8_t ssid_hidden; /**< Broadcast SSID or not, default 0, broadcast the SSID */
uint8_t max_connection; /**< Max number of stations allowed to connect in, default 4, max 4 */
uint16_t beacon_interval; /**< Beacon interval, 100 ~ 60000 ms, default 100 ms */
} wifi_ap_config_t;
虽然只有短短的几十行代码,但是如果我们仔细追踪源码的话,里面其实藏着很多干货的!
我们这里也只是简单分析了下源码,没有太深入,比如,tcp/ip 适配层初始化时都干了啥?事件调度器是干嘛的/wifi 状态机是如何运行是?对于后者,理解清楚了有利于我们编写出更好的应用程序,我们将在下一篇博客中介绍,请参考 分析 ESP32 的 WiFi 状态机;对于前者,如果有兴趣,请自行追踪源码,这部分内容也是开源的。