WIFI
ESP32 支持三种 Wi-Fi 模式:Station (STA)、Access Point (AP) 和 Station + Access Point (STA+AP)。每种模式都有其特定的应用场景和使用建议。下面将详细介绍这三种模式的异同点,并给出相应的使用建议。
1. Station (STA) 模式
定义
- 在 Station 模式下,ESP32 作为客户端连接到现有的 Wi-Fi 网络(接入点)。它类似于手机或电脑连接到家庭路由器的方式。
特点
- 功能:可以连接到现有的 Wi-Fi 网络,获取 IP 地址,访问互联网或其他网络资源。
- 应用场景:
- 当你需要让 ESP32 连接到一个已有的 Wi-Fi 网络,并通过该网络进行数据传输时使用。
- 例如,智能家居设备连接到家庭 Wi-Fi 网络以实现远程控制或数据上传。
优缺点
- 优点:
- 可以利用现有 Wi-Fi 网络基础设施,无需额外配置。
- 能够访问互联网,便于数据上传或与云端服务通信。
- 缺点:
- 需要预先知道 SSID 和密码。
- 如果没有可用的 Wi-Fi 网络,则无法连接到网络。
使用建议
- 如果你的项目需要通过 Wi-Fi 网络与外界通信(如云服务器、其他设备等),则应选择 Station 模式。
- 确保在代码中正确配置 SSID 和密码,并处理可能的断开重连逻辑。
wifi_config_t wifi_config = {
.sta = {
//编译器优化了,所以可以将字符串赋值给数组类型
.ssid = "your-SSID",
.password = "your-PASSWORD",
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
},
};
2. Access Point (AP) 模式
定义
- 在 Access Point 模式下,ESP32 本身充当无线接入点,允许其他设备(如手机、电脑)直接连接到 ESP32 的 Wi-Fi 网络。
特点
- 功能:创建一个独立的 Wi-Fi 网络,供其他设备连接。
- 应用场景:
- 当你希望直接与 ESP32 设备交互而不需要外部 Wi-Fi 网络时使用。
- 例如,在设备初始配置阶段,用户可以通过手机连接到 ESP32 的 AP,设置 Wi-Fi 凭证。
优缺点
- 优点:
- 不依赖外部 Wi-Fi 网络,适用于临时或无网络环境下的设备配置。
- 允许设备直接与 ESP32 通信,适合本地调试或配置。
- 缺点:
- 不能直接访问互联网。
- 通常仅用于短时间内的配置或调试,不适合长期运行。
使用建议
- 使用 AP 模式进行设备初始化配置,尤其是在设备首次启动时需要输入 Wi-Fi 凭证的情况下。
- 确保为 AP 设置一个唯一的 SSID 和强密码,避免与其他网络冲突。
wifi_config_t wifi_config = {
.ap = {
.ssid = "ESP32_AP",
.password = "12345678",
.authmode = WIFI_AUTH_WPA2_PSK,
.max_connection = 4, // 最大连接数
.ssid_hidden = 0, // 是否隐藏SSID
},
};
3. Station + Access Point (STA+AP) 模式
定义
- 在 STA+AP 模式下,ESP32 同时作为 Station 和 Access Point 工作。这意味着它可以连接到一个外部 Wi-Fi 网络,同时也可以被其他设备连接。
特点
- 功能:既可以连接到外部 Wi-Fi 网络,又可以提供自己的 Wi-Fi 网络供其他设备连接。
- 应用场景:
- 当你需要让 ESP32 同时连接到外部网络并允许其他设备直接与其通信时使用。
- 例如,智能家居设备既需要连接到家庭 Wi-Fi 网络以实现远程控制,又需要允许本地设备直接连接进行配置或调试。
优缺点
- 优点:
- 提供了更大的灵活性,既能够连接到外部网络,又能接受本地设备的直接连接。
- 适合需要远程和本地交互的复杂应用场景。
- 缺点:
- 增加了功耗和资源占用。
- 实现较为复杂,需要注意管理两个网络接口之间的冲突。
使用建议
- 在需要同时支持远程和本地交互的场景下使用 STA+AP 模式。
- 注意合理分配资源,确保不会因为双模式运行导致性能下降或不稳定。
wifi_config_t wifi_config_sta = {
.sta = {
.ssid = "your-SSID",
.password = "your-PASSWORD",
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
},
};
wifi_config_t wifi_config_ap = {
.ap = {
.ssid = "ESP32_STA_AP",
.password = "12345678",
.authmode = WIFI_AUTH_WPA2_PSK,
.max_connection = 4,
.ssid_hidden = 0,
},
};
// 启用 STA+AP 模式
esp_wifi_set_mode(WIFI_MODE_STA_AP);
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta);
esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config_ap);
总结与对比
特性/模式 | Station (STA) | Access Point (AP) | Station + Access Point (STA+AP) |
---|---|---|---|
功能描述 | 连接到已有 Wi-Fi 网络 | 创建独立的 Wi-Fi 网络 | 同时连接到外部网络并创建本地网络 |
应用场景 | 数据上传、远程控制 | 设备配置、调试 | 远程和本地交互 |
是否需外部网络 | 是 | 否 | 是 |
资源占用 | 较低 | 中等 | 较高 |
适用场景 | 需要联网的 IoT 设备 | 设备初次配置 | 复杂应用,需兼顾远程和本地通信 |
使用建议
-
Station (STA) 模式:
- 适用于大多数需要连接到外部 Wi-Fi 网络的 IoT 设备。
- 确保在网络配置时提供正确的 SSID 和密码,并处理好断开重连机制。
-
Access Point (AP) 模式:
- 主要用于设备的初次配置或调试阶段,让用户可以直接与设备通信。
- 确保 AP 的 SSID 和密码简单易记,但也要保证一定的安全性。
-
Station + Access Point (STA+AP) 模式:
- 适用于需要同时支持远程和本地交互的复杂应用场景。
- 注意优化资源管理,避免因双模式运行导致的性能问题。
根据具体需求选择合适的 Wi-Fi 模式,可以使你的项目更加高效和稳定。
STA模式实现
#include <stdio.h>
#include <string.h>
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_err.h"
#define MY_SSID "your ssid"
#define MY_PASSWORD "your password"
#define MAX_RETRY_COUNT 5 // 最大重连次数
static int retry_count = 0; // 重连计数器
/*
* @brief 处理 Wi-Fi 断开连接事件的原因,并打印相关日志信息。
*
* 该函数解析 WIFI_EVENT_STA_DISCONNECTED 事件中的断开原因,
* 并根据不同的原因打印详细的错误日志,帮助用户或开发者快速定位问题。
*
* @param event_data 事件数据指针,指向触发事件时传递的数据。
* 对于 WIFI_EVENT_STA_DISCONNECTED 事件,event_data 是一个 wifi_event_sta_disconnected_t 类型的结构体。
*/
void wifi_disconnected_reason(void* event_data)
{
// 将 event_data 转换为 wifi_event_sta_disconnected_t 类型的指针
wifi_event_sta_disconnected_t *disconnected_event = (wifi_event_sta_disconnected_t *)event_data;
// 打印断开连接的原因编号(reason 字段)
ESP_LOGE("sta", "Disconnected from AP. Reason: %d", disconnected_event->reason);
// 判断断开原因是否为认证失败(例如密码错误)
if (disconnected_event->reason == WIFI_REASON_AUTH_FAIL) {
// 认证失败时打印错误日志,提示用户检查 SSID 和密码
ESP_LOGE("sta", "Authentication failed. Check SSID and password.");
}
// 判断断开原因是否为未找到目标接入点(AP)
else if (disconnected_event->reason == WIFI_REASON_NO_AP_FOUND) {
// 未找到 AP 时打印错误日志,提示用户检查 SSID 是否正确
ESP_LOGE("sta", "AP not found. Check SSID.");
}
// 如果断开原因是未知原因,则打印具体的断开原因编号
else {
ESP_LOGE("sta", "Disconnected due to unknown reason: %d", disconnected_event->reason);
}
}
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)
{
switch (event_id)
{
case WIFI_EVENT_STA_START: //WIFI以STA模式启动后触发此事件//启动STA工作模式
retry_count = 0; // 启动时重置重连计数器
esp_wifi_connect(); //启动WIFI连接
break;
case WIFI_EVENT_STA_CONNECTED: //WIFI连上路由器后,触发此事件
retry_count = 0; // 连接上wifi后重置重连计数器
ESP_LOGI("sta", "esp32 connetced to ap!");
break;
case WIFI_EVENT_STA_DISCONNECTED: //WIFI从路由器断开连接后触发此事件
wifi_disconnected_reason(event_data);
if (retry_count < MAX_RETRY_COUNT)
{
retry_count++;
vTaskDelay(pdMS_TO_TICKS(2000)); // 延迟 2 秒后重连
esp_wifi_connect();
ESP_LOGI("sta", "esp32 connect the ap failed! retry %d/%d", retry_count, MAX_RETRY_COUNT);
}
else
{
ESP_LOGE("sta", "Max retry count reached. Connection failed.");
}
break;
default:
break;
}
}
else if(event_base == IP_EVENT) //IP相关事件
{
switch (event_id)
{
case IP_EVENT_STA_GOT_IP: //只有获取到路由器分配的IP,才认为是连上了路由器
ESP_LOGI("sta", "esp32 get ip address");
break;
default:
break;
}
}
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init()); // 初始化 NVS 存储(用于保存 Wi-Fi 配置等数据)
ESP_ERROR_CHECK(esp_netif_init()); //用于初始化tcp/ip协议栈
ESP_ERROR_CHECK(esp_event_loop_create_default()); //创建一个默认系统事件调度循环,之后可以注册回调函数来处理系统的一些事件
esp_netif_create_default_wifi_sta(); //使用默认配置创建STA对象
//初始化WIFI
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); // 使用默认配置初始化 Wi-Fi
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
//注册事件
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handle, NULL)); // 注册 Wi-Fi 事件处理函数
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handle, NULL));// 注册 IP 事件处理函数
//WIFI配置
wifi_config_t wifi_config = {
.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK,//设置加密方式
.sta.pmf_cfg.capable = true, //是否使用保护管理帧
.sta.pmf_cfg.required = false, //是否之和有保护管理帧功能的设备通信
};
/* 不直接在结构体内对ssid和password赋值的原因是:
wifi_config.sta.ssid和wifi_config.sta.password是固定长度的数组类型,而不是指针类型,C 语言不允许直接将字符串赋值给数组*/
memset(wifi_config.sta.ssid, 0, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.ssid, MY_SSID, strlen(MY_SSID));
memset(wifi_config.sta.password, 0, sizeof(wifi_config.sta.password));
memcpy(wifi_config.sta.password, MY_PASSWORD, strlen(MY_PASSWORD));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); //设置工作模式为STA
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); //设置wifi配置
ESP_ERROR_CHECK(esp_wifi_start()); //启动WIFI
ESP_LOGI("sta", "wifi_init_sta finished!");
while(1)
{
vTaskDelay(pdMS_TO_TICKS(500));
}
ESP_LOGI("err", "project faild!");
return;
}