跳到主要内容

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. 示例 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 网络列表,输出类似如下:

示例 1:扫描 WiFi 运行结果

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 运行结果

将代码中的 yourssidyourpassword 修改为你的 Wi-Fi 信息后上传。串口监视器将显示连接过程,成功后打印出获取到的 IP 地址:

示例 2:扫描 WiFi 运行结果

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 地址。如果当前连接断开,它会自动尝试重连到列表中的其他可用网络。

示例 3:管理多个 Wi-Fi 运行结果

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 地址。当有设备连接或断开此热点时,相应的事件信息会被打印出来:

示例 4:扫描 WiFi 运行结果

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 地址、网关和子网掩码。

6. 相关链接