Wi-Fi 基础用法
ESP32 系列芯片内置了强大的无线连接功能。多数 ESP32 芯片集成了 Wi-Fi,这使其非常适用于物联网(IoT)项目。(部分型号为满足成本或特定应用场景的需求,未集成 Wi-Fi 功能。各型号具体的支持情况可查阅官方的 ESP32 产品概览 文档。)
ESP32 可以工作在多种 Wi-Fi 模式下:
- STA 模式(Station):ESP32 作为客户端连接到路由器或热点。
- AP 模式(Access Point):ESP32 创建热点,其他设备可以连接到它。
- AP+STA 模式:同时作为客户端连接网络,并为其他设备提供热点。
本教程将通过以下示例介绍 Arduino 环境下 ESP32 的 Wi-Fi 基本用法:
- 示例 1:扫描 WiFi
- 示例 2:连接指定 Wi-Fi(STA 模式)
- 示例 3:管理多个 Wi-Fi(WiFiMulti)
- 示例 4:创建 Wi-Fi 热点 (AP 模式)
- 示例 5:配置静态 IP
1. 示例 1:扫描 WiFi
这个示例展示如何扫描周围的 Wi-Fi 网络并显示其详细信息,包括网络名称、信号强度、信道和加密类型。
1.1 代码
#include "WiFi.h"
void setup() {
Serial.begin(115200);
// 将 Wi-Fi 设置为站点模式,并断开任何已有的连接
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.println("Setup done");
}
void loop() {
Serial.println("Scan start");
// WiFi.scanNetworks() 将返回找到的网络数量。
int n = WiFi.scanNetworks();
Serial.println("Scan done");
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.print(n);
Serial.println(" networks found");
Serial.println("Nr | SSID | RSSI | CH | Encryption");
for (int i = 0; i < n; ++i) {
// 打印找到的每个网络的 SSID 和 RSSI
Serial.printf("%2d", i + 1);
Serial.print(" | ");
Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
Serial.print(" | ");
Serial.printf("%4ld", WiFi.RSSI(i));
Serial.print(" | ");
Serial.printf("%2ld", WiFi.channel(i));
Serial.print(" | ");
switch (WiFi.encryptionType(i)) {
case WIFI_AUTH_OPEN: Serial.print("open"); break;
case WIFI_AUTH_WEP: Serial.print("WEP"); break;
case WIFI_AUTH_WPA_PSK: Serial.print("WPA"); break;
case WIFI_AUTH_WPA2_PSK: Serial.print("WPA2"); break;
case WIFI_AUTH_WPA_WPA2_PSK: Serial.print("WPA+WPA2"); break;
case WIFI_AUTH_WPA2_ENTERPRISE: Serial.print("WPA2-EAP"); break;
case WIFI_AUTH_WPA3_PSK: Serial.print("WPA3"); break;
case WIFI_AUTH_WPA2_WPA3_PSK: Serial.print("WPA2+WPA3"); break;
case WIFI_AUTH_WAPI_PSK: Serial.print("WAPI"); break;
default: Serial.print("unknown");
}
Serial.println();
delay(10);
}
}
Serial.println("");
// 删除扫描结果以释放内存
WiFi.scanDelete();
// 在再次扫描之前等待一下。
delay(5000);
}
1.2 代码解释
WiFi.mode(WIFI_STA);
:设置 ESP32 的 Wi-Fi 工作模式为站点(Station)模式。WiFi.disconnect()
:断开之前可能存在的连接,确保处于未连接状态。WiFi.scanNetworks()
:执行一次同步扫描,探测周围的 Wi-Fi 网络。该函数为阻塞式,扫描完成后会返回发现的网络数量。WiFi.SSID(i)
:获取索引为i
的网络的 SSID(网络名称),返回 String 类型。WiFi.RSSI(i)
:获取索引为i
的网络的 RSSI(接收信号强度指示)。单位为 dBm,该值为负数,越接近 0 表示信号越强。WiFi.channel(i)
:获取索引为i
的网络所在的 Wi-Fi 信道。WiFi.encryptionType(i)
: 获取索引为i
的网络的加密类型。WiFi.scanDelete()
:删除扫描结果以释放内存,是良好的编程习惯。
1.3 运行结果
打开串口监视器,波特率设置为 115200
。串口监视器将显示检测到的可用 Wi-Fi 网络列表,输出类似如下:
2. 示例 2:连接指定 Wi-Fi (STA 模式)
ESP32 连接到指定的 Wi-Fi 网络,获取 IP 地址并保持连接。
2.1 代码
#include <WiFi.h>
// 请替换为你的 Wi-Fi 网络信息
const char *ssid = "yourssid"; // 替换为你的 Wi-Fi 名称
const char *password = "yourpasswd"; // 替换为你的 Wi-Fi 密码
void setup() {
Serial.begin(115200);
delay(10);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
}
2.2 代码解释
WiFi.begin(ssid, password);
:启动连接过程。这是一个异步函数,它会立即返回,而连接在后台进行。WiFi.status()
:返回当前的 Wi-Fi 连接状态。WL_CONNECTED
表示已成功连接。while
循环通过轮询此状态来等待连接完成。常见的 Wi-Fi 状态值:WL_IDLE_STATUS
:Wi-Fi 处于空闲状态WL_NO_SSID_AVAIL
:找不到指定的网络名称WL_CONNECTED
:已成功连接WL_CONNECT_FAILED
:连接失败WL_CONNECTION_LOST
:连接丢失
WiFi.localIP()
:获取 ESP32 在连接成功后由 DHCP 服务器分配到的 IP 地址。类型为 IPAddress。
2.3 运行结果
将代码中的 yourssid
和 yourpassword
修改为你的 Wi-Fi 信息后上传。串口监视器将显示连接过程,成功后打印出获取到的 IP 地址:
3. 示例 3:管理多个 Wi-Fi (WiFiMulti)
预设多个 Wi-Fi 网络信息,ESP32 自动连接到信号最强的可用网络。
3.1 代码
#include <WiFi.h>
#include <WiFiMulti.h>
WiFiMulti wifiMulti;
void setup() {
Serial.begin(115200);
delay(10);
// 添加多个候选 Wi-Fi 网络
wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");
wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
Serial.println("Connecting Wifi...");
if (wifiMulti.run() == WL_CONNECTED) {
Serial.println("");
Serial.println("WiFi connected");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
}
void loop() {
// 检查连接状态,如果断开则尝试重连
if (wifiMulti.run() != WL_CONNECTED) {
Serial.println("WiFi not connected!");
delay(1000);
}
}
3.2 代码解释
WiFiMulti wifiMulti;
:创建一个WiFiMulti
对象实例,用于管理多个 Wi-Fi 网络。wifiMulti.addAP("ssid", "password");
:向WiFiMulti
实例中添加一个候选 Wi-Fi 网络的凭据。可以多次调用以添加多个网络。wifiMulti.run()
:核心函数。它会扫描、选择信号最强的可用网络并尝试连接。返回当前的连接状态,类似WiFi.status()
。在loop
中持续调用可实现断线自动重连。
3.3 运行结果
配置好至少一个可用的 Wi-Fi 信息后上传代码。ESP32 会连接到列表中信号最强的网络,并打印出 IP 地址。如果当前连接断开,它会自动尝试重连到列表中的其他可用网络。
4. 示例 4:创建 Wi-Fi 热点 (AP 模式)
ESP32 创建一个 Wi-Fi 热点,其他设备可以连接到它。设备的连接和断开时,串口监视器显示设备的信息。本示例使用事件回调来监视客户端的连接和断开。
4.1 代码
#include <WiFi.h>
const char *ssid = "ESP32S3-TEST"; // 设置热点名称
const char *password = "12345678"; // 设置热点密码(至少 8 位)
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Configuring access point...");
// 设置 Wi-Fi 事件回调函数
WiFi.onEvent(WiFiStationConnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_AP_STACONNECTED);
WiFi.onEvent(WiFiStationGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED);
WiFi.onEvent(WiFiStationDisconnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_AP_STADISCONNECTED);
// 创建 Wi-Fi 热点
if (!WiFi.softAP(ssid, password)) {
Serial.println("Soft AP creation failed.");
while (1)
;
}
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
}
void loop() {
}
// 设备连接事件
void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("Device connected, MAC: ");
Serial.println(macToString(info.wifi_ap_staconnected.mac));
}
// 设备获取 IP 事件
void WiFiStationGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("Device IP address: ");
Serial.println(IPAddress(info.got_ip.ip_info.ip.addr));
}
// 设备断开连接事件
void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("Device disconnected, MAC: ");
Serial.println(macToString(info.wifi_ap_stadisconnected.mac));
}
// MAC 地址转换为字符串辅助函数
String macToString(const uint8_t *mac) {
char buf[18];
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(buf);
}
4.2 代码解释
WiFi.onEvent(callback, event)
:注册 Wi-Fi 事件回调函数。当指定的事件发生时,系统会自动调用相应的回调函数。这是一种事件驱动的编程模式,无需主动轮询状态。- 事件类型说明:
ARDUINO_EVENT_WIFI_AP_STACONNECTED
:有设备连接到 ESP32 热点时触发ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED
:连接的设备获取到 IP 地址时触发ARDUINO_EVENT_WIFI_AP_STADISCONNECTED
:设备从 ESP32 热点断开时触发- 其他事件,参考 Wi-Fi 事件示例
WiFi.softAP(ssid, password)
:创建一个 Wi-Fi 热点。第一个参数是热点名称,第二个参数是密码(至少 8 位)。返回布尔值表示创建是否成功。WiFi.softAPIP()
:获取 ESP32 作为热点时的 IP 地址,通常默认为 192.168.4.1。WiFiEventInfo_t info
:包含事件相关信息的结构体,不同事件类型包含不同的信息字段。macToString()
:辅助函数,将 6 字节的 MAC 地址数组转换为可读的字符串格式(如 "aa:bb:cc:dd:ee:ff")。
4.3 运行结果
程序运行后,ESP32 会创建一个名为 "ESP32S3-TEST" 的 Wi-Fi 热点。串口监视器会首先打印出 AP 的 IP 地址。当有设备连接或断开此热点时,相应的事件信息会被打印出来:
5. 示例 5:配置静态 IP
在特定应用场景下,为 ESP32 设置一个固定的 IP 地址(而非通过 DHCP 动态获取)是一种常见需求,便于设备被稳定访问。
STA 模式:配置静态 IP
5.1 STA 模式:配置静态 IP
基于示例 2,添加静态 IP 配置:
#include <WiFi.h>
const char *ssid = "Maker"; // Wi-Fi 名称
const char *password = "12345678"; // Wi-Fi 密码
// 设置静态 IP 地址、网关和子网掩码
// 根据你的局域网配置进行修改
IPAddress ip(192, 168, 137, 100); // 设定静态 IP 地址
IPAddress gateway(192, 168, 137, 1); // 设定网关
IPAddress subnet(255, 255, 255, 0); // 设定子网掩码
void setup() {
Serial.begin(115200);
delay(10);
WiFi.mode(WIFI_STA);
// 在连接之前配置静态 IP,必须在 WiFi.begin() 之前调用
WiFi.config(ip, gateway, subnet);
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
}
代码解释
-
IPAddress(a, b, c, d)
:创建一个IPAddress
对象来表示 IP 地址。 -
WiFi.config(local_IP, gateway, subnet)
:在WiFi.begin()
之前调用,用于配置静态 IP。如果配置失败,会返回false
。注意请确保你设置的 IP 地址、网关和子网掩码与你所在的局域网环境相匹配,且该 IP 未被其他设备占用。
5.2 AP 模式:配置静态 IP
基于示例 4,为热点设置自定义 IP 地址:
#include <WiFi.h>
const char *ssid = "ESP32S3-TEST"; // 设置热点名称
const char *password = "12345678"; // 设置热点密码(至少 8 位)
IPAddress ip(192, 168, 5, 1); // 设定静态 IP 地址
IPAddress gateway(192, 168, 5, 1); // 设定网关
IPAddress subnet(255, 255, 255, 0); // 设定子网掩码
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Configuring access point...");
// 设置 Wi-Fi 事件回调函数
WiFi.onEvent(WiFiStationConnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_AP_STACONNECTED);
WiFi.onEvent(WiFiStationGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED);
WiFi.onEvent(WiFiStationDisconnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_AP_STADISCONNECTED);
// 在 WiFi.softAP() 创建热点之前调用
WiFi.softAPConfig(ip, gateway, subnet);
// 创建 Wi-Fi 热点
if (!WiFi.softAP(ssid, password)) {
Serial.println("Soft AP creation failed.");
while (1)
;
}
Serial.print("AP IP address: ");
Serial.println(WiFi.softAPIP());
}
void loop() {
}
// 设备连接事件
void WiFiStationConnected(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("Device connected, MAC: ");
Serial.println(macToString(info.wifi_ap_staconnected.mac));
}
// 设备获取 IP 事件
void WiFiStationGotIP(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("Device IP address: ");
Serial.println(IPAddress(info.got_ip.ip_info.ip.addr));
}
// 设备断开连接事件
void WiFiStationDisconnected(WiFiEvent_t event, WiFiEventInfo_t info) {
Serial.print("Device disconnected, MAC: ");
Serial.println(macToString(info.wifi_ap_stadisconnected.mac));
}
// MAC 地址转换为字符串辅助函数
String macToString(const uint8_t *mac) {
char buf[18];
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(buf);
}
代码解释
WiFi.softAPConfig(local_IP, gateway, subnet)
:在WiFi.softAP()
之前调用,为 ESP32 的 AP 模式设置自定义的 IP 地址、网关和子网掩码。