使用 Seeed Studio XIAO ESP32-C5 的 WiFi 功能
| Seeed Studio XIAO ESP32-C5 |
|---|
![]() |
Seeed Studio XIAO ESP32-C5 支持双频 2.4 GHz 和 5 GHz Wi-Fi,配备双频 Wi-Fi 6(802.11ax)射频,并向下兼容 802.11a/b/g/n/ac 标准。此外,该开发板支持 U.FL 天线连接,旨在增强 XIAO ESP32-C5 的无线连接性能。在本教程中,我们将介绍如何利用 XIAO ESP32-C5 的 Wi-Fi 功能连接到 Wi-Fi 网络并执行基本的网络任务。
以下教程使用 Arduino IDE 进行编译和烧录。如果你还没有使用 Arduino IDE 的经验,请访问 Getting Started with Seeed Studio XIAO ESP32-C5。
入门指南
天线安装
在 Seeed Studio XIAO ESP32-C5 的包装内,配有一个专用的 Wi-Fi/BT 天线连接器。为了获得最佳的 WiFi/Bluetooth 信号强度,你需要取出包装中附带的天线并将其连接到该连接器上。
WiFi 库的常用接口
- XIAO ESP32-C5 提供了丰富的 Wi-Fi 网络功能。通常,我们可以查看 ESP32 内置包中的 WiFi 库函数,并选择相应的函数来实现所需的功能。接下来,我们将列出一些常用接口并介绍它们的用法。
如果你想直接开始 Wi-Fi 使用教程,可以跳转到 WiFi 使用示例。
通用 WiFi 函数
-
WiFiGenericClass::getHostname()-- 是 ESP32 WiFi 库中的一个函数,用于以字符串形式返回设备的主机名。主机名是在网络中标识设备的唯一名称。该函数会获取之前通过WiFiGenericClass::setHostname()设置的主机名。如果尚未设置主机名,则会返回默认主机名。 -
WiFiGenericClass::persistent(bool persistent)-- 是一个用于启用或禁用 ESP32 WiFi 库持久化模式的方法。当启用持久化模式时,Wi-Fi 配置信息会存储在非易失性存储器(NVM)中,即使断电或复位也会保留。当禁用持久化模式时,配置信息存储在 RAM 中,在断电或复位后会丢失。- 输入参数
- persistent: 如果参数为 true,则启用持久化模式;如果参数为 false,则禁用持久化模式。
- 输入参数
-
WiFiGenericClass::enableLongRange(bool enable)-- 该函数用于启用或禁用 WiFi 模块的 Long Range(LR,长距离)特性。启用后,LR 功能允许模块连接到比平常更远距离的 WiFi 网络,但数据速率会降低。- 输入参数
- enable: 将该参数设置为 true 以启用该特性,设置为 false 以禁用。
- 输入参数
-
WiFiGenericClass::mode(wifi_mode_t m)-- 该函数用于设置设备的 WiFi 模式。- 输入参数
- m: 参数 m 指定要设置的模式,可以是 wifi_mode_t 枚举中定义的以下常量之一:
- WIFI_MODE_NULL: 禁用 WiFi station 和接入点模式。
- WIFI_MODE_STA: 启用 WiFi station 模式,用于连接到现有 WiFi 网络。
- WIFI_MODE_AP: 启用接入点模式,用于创建新的 WiFi 网络。
- WIFI_MODE_APSTA: 同时启用 WiFi station 和接入点模式。
- m: 参数 m 指定要设置的模式,可以是 wifi_mode_t 枚举中定义的以下常量之一:
- 输入参数
-
WiFiGenericClass::setSleep(wifi_ps_type_t sleepType)-- 该函数用于为 WiFi 模块设置省电模式。- 输入参数
- sleepType: sleepType 参数是一个枚举类型,用于指定要使用的省电模式类型。有三种可能的睡眠类型:
- WIFI_PS_NONE: 默认睡眠模式,WiFi 模块不会进入省电模式。
- WIFI_PS_MIN_MODEM: 在此模式下,WiFi 模块会关闭其调制解调器,同时保持与接入点(AP)的连接。
- WIFI_PS_MAX_MODEM: 启用最激进的 Wi-Fi 省电模式。它可以显著增加休眠时间,但可能会带来更高的延迟和更低的吞吐量,并且在某些网络中可能影响连接稳定性。
- sleepType: sleepType 参数是一个枚举类型,用于指定要使用的省电模式类型。有三种可能的睡眠类型:
- 输入参数
STA 函数
-
WiFiSTAClass::status()-- 返回连接状态。- 输出: wl_status_t 中定义的值之一。
- WL_NO_SHIELD: 表示 Wi-Fi 模块不存在。
- WL_IDLE_STATUS: 表示 Wi-Fi 模块当前未执行任何操作。
- WL_NO_SSID_AVAIL: 表示在扫描过程中未找到任何 Wi-Fi 网络。
- WL_SCAN_COMPLETED: 表示 Wi-Fi 扫描已成功完成。
- WL_CONNECTED: 表示 ESP32 已成功连接到某个 Wi-Fi 网络。
- WL_CONNECT_FAILED: 表示连接到 Wi-Fi 网络失败。
- WL_CONNECTION_LOST: 表示与 Wi-Fi 网络的连接已丢失。
- WL_DISCONNECTED: 表示 ESP32 之前连接过某个 Wi-Fi 网络,但当前未连接到任何网络。
- 输出: wl_status_t 中定义的值之一。
-
WiFiSTAClass::begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* ca_pem, const char* client_crt, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect)-- 使用 WPA2 Enterprise AP 启动 Wifi 连接。- 输入参数(可选)
- ssid: 指向 SSID 字符串的指针。
- method: WPA2 的认证方法(WPA2_AUTH_TLS, WPA2_AUTH_PEAP, WPA2_AUTH_TTLS)
- wpa2_identity: 指向实体的指针
- wpa2_username: 指向用户名的指针
- wpa2_password: 指向密码的指针。
- ca_pem: 指向包含 CA 证书的 .pem 文件内容字符串的指针
- client_crt: 指向包含客户端证书的 .crt 文件内容字符串的指针
- client_key: 指向包含客户端密钥的 .key 文件内容字符串的指针
- channel: 可选。AP 的信道
- bssid: 可选。AP 的 BSSID / MAC
- connect: 可选。是否调用连接
- 输入参数(可选)
-
WiFiSTAClass::reconnect()-- 将强制断开连接,然后开始重新连接到 AP。- 输出: True/False。
-
WiFiSTAClass::disconnect(bool wifioff, bool eraseap)-- 从网络断开连接。-
输入参数
- wifioff: wifioff 为
true时关闭 Wi-Fi 射频。 - eraseap: eraseap 为
true时从 NVS 存储器中擦除 AP 配置。
- wifioff: wifioff 为
-
输出: True/False。
-
-
WiFiSTAClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2)-- 更改 IP 配置设置并禁用 DHCP 客户端。- 输入参数
- local_ip: 静态 IP 配置。
- gateway: 静态网关配置。
- subnet: 静态子网掩码。
- dns1: 静态 DNS 服务器 1。
- dns2: 静态 DNS 服务器 2。
- 输入参数
-
WiFiSTAClass::setAutoConnect(bool autoConnect)-- 已弃用。用于设置 ESP32 station 在上电时是否自动连接到已记录的 AP。默认启用自动连接。-
输入参数
- autoConnect: autoConnect 布尔值。
-
输出: False。
-
-
WiFiSTAClass::waitForConnectResult(unsigned long timeoutLength)-- 等待 WiFi 连接得到结果。-
输入参数
- timeoutLength: 该参数指定等待建立连接的最长时间,单位为毫秒。
-
输出: wl_status_t 中定义的值之一。
-
-
WiFiSTAClass::localIP()-- 获取 station 接口的 IP 地址。- 输出: IPAddress station IP。
-
WiFiSTAClass::macAddress(uint8_t* mac)-- 获取 station 接口的 MAC 地址。-
输入参数
- mac(可选): 指向长度为 WL_MAC_ADDR_LENGTH 的 uint8_t 数组的指针。
-
输出: 指向 uint8_t * 的指针。
-
-
WiFiSTAClass::SSID()-- 返回当前与网络关联的 SSID。- 输出: SSID。
-
WiFiSTAClass::RSSI(void)-- 返回当前网络的 RSSI。- 输出: RSSI。
AP 函数
-
WiFiAPClass::softAP(const char* ssid, const char* passphrase, int channel, int ssid_hidden, int max_connection, bool ftm_responder)-- 这是 XIAO ESP32-C5 的 WiFi 库中的一个函数,用于建立 SoftAP(程序接入点),使其他设备可以连接到 XIAO ESP32-C5 并访问其资源。-
输入参数
- ssid: 指向 SSID 的指针(最多 63 个字符)。
-
passphrase: (对于 WPA2,最少 8 个字符;若为开放网络则使用 NULL)。
-
channel: WiFi 信道号,1 - 13。
-
ssid_hidden: 网络隐藏(0 = 广播 SSID,1 = 隐藏 SSID)。
-
max_connection: 最大同时连接的客户端数量,1 - 4。
-
输出: True/False。
-
-
WiFiAPClass::softAPgetStationNum()-- 获取连接到 softAP 接口的 Station / 客户端数量。- 输出: Station 数量。
-
WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dhcp_lease_start)-- 用于配置 SoftAP 的函数。-
输入参数
- local_ip: 接入点 IP。
- gateway: 网关 IP。
- subnet: 子网掩码。
-
输出: True/False。
-
-
WiFiAPClass::softAPIP()-- 获取 softAP 接口的 IP 地址。- 输出: IPAddress softAP IP。
-
WiFiAPClass::softAPmacAddress(uint8_t* mac)-- 获取 softAP 接口的 MAC 地址。-
输入参数
- mac (可选): 指向长度为 WL_MAC_ADDR_LENGTH 的 uint8_t 数组的指针。
-
输出: 指向 uint8_t* 的指针或 String 类型的 mac。
-
WiFi 扫描函数
-
WiFiScanClass::scanNetworks(bool async, bool show_hidden, bool passive, uint32_t max_ms_per_chan, uint8_t channel, const char * ssid, const uint8_t * bssid)-- 开始扫描可用的 WiFi 网络。-
输入参数
- async: 该参数是一个布尔值,用于决定是否以异步方式执行扫描。若设为 true,函数会立即返回,之后可以通过调用
getScanResults()函数获取扫描结果。若设为 false,函数会阻塞直到扫描完成。 - show_hidden: 该参数是一个布尔值,用于决定函数是否在扫描结果中包含隐藏网络。
- passive: 该参数是一个布尔值,用于决定函数是否执行被动扫描。若设为 true,函数在扫描期间不会发送任何数据包,扫描可能耗时更长,但在某些场景下会更有用。
- max_ms_per_chan: 该参数是每个信道上用于扫描的最长时间(毫秒)。
- channel: 该参数是要扫描的 Wi-Fi 信道。如果设为 0,函数将扫描所有可用信道。
- ssid: 该参数是一个指向以空字符结尾的字符串的指针,包含要扫描的网络的 SSID。如果设为 nullptr,函数将扫描所有可用网络。
- bssid: 该参数是一个指向 6 字节数组的指针,包含要扫描的接入点的 MAC 地址。如果设为 nullptr,函数将扫描所有接入点。
- async: 该参数是一个布尔值,用于决定是否以异步方式执行扫描。若设为 true,函数会立即返回,之后可以通过调用
-
输出: 此函数的返回值是一个整数,表示扫描到的网络数量。
-
-
WiFiScanClass::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel)-- 将某个已扫描 WiFi 的所有信息加载到指针参数中。-
输入参数
- i: 该函数用于获取指定索引 i 处的已扫描网络的信息。
- ssid: 参数 ssid 是一个 String 变量的引用,函数会在其中存储网络的 SSID。
- encType: 参数 encType 是一个 uint8_t 变量的引用,函数会在其中存储网络的加密类型(0 = open,1 = WEP,2 = WPA_PSK,3 = WPA2_PSK,4 = WPA_WPA2_PSK)。
- rssi: 参数 rssi 是一个 int32_t 变量的引用,函数会在其中存储网络的接收信号强度指示(RSSI)。
- bssid: 参数 bssid 是一个 uint8_t* 指针的引用,函数会在其中存储网络的 BSSID(MAC 地址)。
- channel: 参数 channel 是一个 int32_t 变量的引用,函数会在其中存储网络的信道号。
-
输出: True/False。
-
-
WiFiScanClass::SSID(uint8_t i)-- 返回在网络扫描过程中发现的 SSID。-
输入参数
- i: 指定要从哪个网络条目获取信息。
-
输出: 已扫描网络列表中指定条目的 SSID 字符串。
-
-
WiFiScanClass::RSSI(uint8_t i)-- 返回在scanNetworks过程中发现的网络的 RSSI。-
输入参数
- i: 指定要从哪个网络条目获取信息。
-
输出: 已扫描网络列表中指定条目的 RSSI 有符号值。
-
WiFi 客户端函数
-
WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout)-- 此函数用于 WiFiClient 库中,以指定的超时时间连接到远程 IP 地址和端口。- 输入参数
- ip: 要连接的服务器 IP 地址。
- port: 要连接的服务器端口号。
- timeout (可选): 建立连接所允许等待的最长时间(毫秒)。如果在该时间内未建立连接,函数将返回错误。如果 timeout 设为 0,函数将无限期等待连接建立。
- 输入参数
-
WiFiClient::stop()-- 该函数用于将客户端与服务器断开连接,并释放客户端使用的套接字/端口。一旦调用该函数,客户端将无法再发送或接收数据。 -
WiFiClient::setTimeout(uint32_t timeout_ms)-- 该函数设置客户端在等待连接建立或接收数据时的最长等待毫秒数。如果连接或数据传输时间超过指定的超时时间,连接将被关闭。- 输入参数
- timeout_ms: 超时时间的毫秒数。
- 输入参数
-
WiFiClient::write(uint8_t data)-- 通过 WiFiClient 实例向已连接的服务器写入单字节数据。或者使用WiFiClient::write(const uint8_t *buf, size_t size)。- 输入参数
- data: 需要通过已建立的网络连接发送的单字节数据。
- 输入参数
-
WiFiClient::read()-- 该函数从已连接的服务器读取一个字节的传入数据。它以整数形式返回读取到的字节。如果没有可用数据,则返回 -1。或者使用read(uint8_t *buf, size_t size)。- 输出: 一个整数值,表示接收到的字节数。如果返回值为 0,表示服务器已关闭连接。
-
WiFiClient::peek()-- 该函数用于在不实际读取数据的情况下,检查服务器是否有可读数据。- 输出: 返回下一个传入数据字节,但不会将其从接收缓冲区中移除。如果没有可用数据,则返回 -1。
-
WiFiClient::available()-- 该函数用于检查服务器端有多少字节数据可供读取。- 输出: 返回一个整数值,表示可读取的字节数。
WiFi 服务器函数
-
WiFiServer::stopAll()-- 该函数是 Arduino WiFi 库中 WiFiServer 类的方法。此方法会停止所有使用 WiFiServer 类创建的服务器实例。当你希望一次性停止所有服务器,而不是对每个实例单独调用stop()方法时,这个函数非常有用。 -
WiFiServer::begin(uint16_t port, int enable)-- 该函数用于在指定端口上启动服务器。服务器将监听传入的客户端连接。- 输入参数
- port: 要监听的端口号。
- enable (可选): 一个标志,用于指示服务器在启动后是否应立即启用。该标志默认设为 true。
- 输入参数
-
WiFiServer::hasClient()-- 该函数用于检查服务器上是否有任何传入的客户端连接可用。可以在循环中使用此函数以持续检查新连接。- 输出: 如果有客户端已连接,则返回一个 WiFiClient 对象;如果没有等待连接的客户端,则返回 NULL 指针。
-
WiFiServer::end()-- 该函数用于停止服务器并释放相关资源。一旦调用,服务器将不再接受新的客户端连接。任何现有的客户端连接将保持打开状态,直到由客户端或服务器一方关闭。WiFiServer::close()和WiFiServer::stop()具有相同的功能。
WiFi 多路连接函数
-
WiFiMulti::addAP(const char* ssid, const char *passphrase)-- 该函数用于向 WiFiMulti 对象将尝试连接的可用接入点(AP)列表中添加一个新的接入点。-
输入参数
- ssid: 指向 SSID 的指针(最多 63 个字符)。
- passphrase: (对于 WPA2,最少 8 个字符;若为开放网络则使用 NULL)。
-
输出: True/False
-
-
WiFiMulti::run(uint32_t connectTimeout)-- 该函数会按顺序尝试连接已保存的接入点之一,直到成功连接为止。-
输入参数
- connectTimeout: 该参数指定等待连接的最长时间(毫秒)。如果 connectTimeout 设为 0,函数将不会超时,并会一直尝试连接。
-
输出: 状态
-
WiFi 使用示例
接下来,我们将使用 XIAO ESP32-C5 演示如何使用一些基本的 Wi-Fi 功能。
扫描网络
XIAO ESP32-C5 支持双频 2.4 GHz 和 5 GHz Wi-Fi,并且可以在扫描模式下扫描周围的 2.4 GHz 和 5 GHz Wi-Fi 网络及其信号强度。
程序
下面是一个示例程序,向你展示 XIAO ESP32-C5 如何扫描周围的 Wi-Fi 网络。
- 参考代码
WiFiScan.ino
/*
* This sketch demonstrates how to scan WiFi networks. For chips that support 5GHz band, separate scans are done for all bands.
* The API is based on the Arduino WiFi Shield library, but has significant changes as newer WiFi functions are supported.
* E.g. the return value of `encryptionType()` different because more modern encryption is supported.
*/
#include "WiFi.h"
void setup() {
Serial.begin(115200);
// Enable Station Interface
WiFi.STA.begin();
Serial.println("Setup done");
}
void ScanWiFi() {
Serial.println("Scan start");
// WiFi.scanNetworks will return the number of networks found.
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) {
// Print SSID and RSSI for each network found
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);
}
}
// Delete the scan result to free memory for code below.
WiFi.scanDelete();
Serial.println("-------------------------------------");
}
void loop() {
Serial.println("-------------------------------------");
Serial.println("Default wifi band mode scan:");
Serial.println("-------------------------------------");
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2)
WiFi.setBandMode(WIFI_BAND_MODE_AUTO);
#endif
ScanWiFi();
#if CONFIG_SOC_WIFI_SUPPORT_5G
// Wait a bit before scanning again.
delay(1000);
Serial.println("-------------------------------------");
Serial.println("2.4 Ghz wifi band mode scan:");
Serial.println("-------------------------------------");
WiFi.setBandMode(WIFI_BAND_MODE_2G_ONLY);
ScanWiFi();
// Wait a bit before scanning again.
delay(1000);
Serial.println("-------------------------------------");
Serial.println("5 Ghz wifi band mode scan:");
Serial.println("-------------------------------------");
WiFi.setBandMode(WIFI_BAND_MODE_5G_ONLY);
ScanWiFi();
#endif
// Wait a bit before scanning again.
delay(10000);
}
效果展示
- 上传程序后,打开 Arduino IDE 的串口监视器,即可输出扫描到的 Wi-Fi 信息。

连接到 Wi-Fi 网络
在 Wi-Fi 覆盖范围内,如果你知道目标 Wi-Fi 网络的 SSID 和 PASSWORD,就可以通过 XIAO ESP32-C5 支持的 STA 模式连接到指定的 Wi-Fi 网络。
程序
接下来提供一个示例程序,向你展示 XIAO ESP32-C5 如何连接到指定的 Wi-Fi 网络。
XIAO ESP32-C5 支持双频 Wi-Fi(2.4 GHz 和 5 GHz),允许你根据家庭网络情况选择连接方式。
- 参考代码
#include <WiFi.h>
// Replace with your network credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
void setup() {
Serial.begin(115200);
// Explicitly set mode to Station
WiFi.mode(WIFI_STA);
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nCONNECTED!");
// Print connection details
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Subnet Mask: ");
Serial.println(WiFi.subnetMask());
Serial.print("Gateway IP: ");
Serial.println(WiFi.gatewayIP());
Serial.print("DNS IP: ");
Serial.println(WiFi.dnsIP());
// C5 Specific: Check which band and channel we are on
Serial.print("Channel: ");
Serial.println(WiFi.channel());
Serial.print("RSSI (Signal Strength): ");
Serial.println(WiFi.RSSI());
}
void loop() {
// Check if WiFi is still connected
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi lost. Reconnecting...");
WiFi.disconnect();
WiFi.reconnect();
}
delay(5000);
}
效果展示
- 上传程序后,打开 Arduino IDE 的串口监视器,即可输出已连接 Wi-Fi 网络的 IP 地址等信息。
- 在我的环境中,我连接的是 5 GHz 网络。

AP 模式
XIAO ESP32-C5 可以作为热点供其他设备连接。换句话说,你可以使用支持 Wi-Fi 的设备连接到 XIAO ESP32-C5,而无需连接到你的路由器。
简单来说,当你将 XIAO ESP32-C5 配置为接入点时,就创建了它自己的独立 Wi-Fi 网络,附近的 Wi-Fi 设备(站点)可以连接到该网络(例如你的智能手机或电脑)。
程序
接下来提供一个示例程序,向你展示 XIAO ESP32-C5 如何创建热点并允许其他设备连接到它。
- 参考代码
#include <WiFi.h>
const char* ap_ssid = "XIAO ESP32-C5";
const char* ap_password = "password1234";
int previous_station_count = 0;
void setup() {
Serial.begin(115200);
// Initialize built-in LED pin
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW); // Initial state: LED off
// Set mode to Access Point
WiFi.mode(WIFI_AP);
// Configure AP
// Arguments: SSID, Password, Channel (1-13 for 2.4G), Hidden (0/1), Max Connections
// Note: Forcing 5GHz AP usually requires lower-level IDF calls in current Arduino Core,
// so this will likely default to 2.4GHz.
bool result = WiFi.softAP(ap_ssid, ap_password, 1, 0, 4);
if (result) {
Serial.println("AP Started Successfully");
} else {
Serial.println("AP Start Failed");
}
// Print IP Address of the AP (Default is usually 192.168.4.1)
Serial.print("AP IP Address: ");
Serial.println(WiFi.softAPIP());
}
void loop() {
// Get current number of connected stations
int current_station_count = WiFi.softAPgetStationNum();
Serial.printf("Stations connected: %d\n", current_station_count);
// Check if any device has connected or disconnected
if (current_station_count > 0 && previous_station_count == 0) {
// New device connected, turn on LED
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("Device connected - LED ON");
} else if (current_station_count == 0 && previous_station_count > 0) {
// All devices disconnected, turn off LED
digitalWrite(LED_BUILTIN, LOW);
Serial.println("All devices disconnected - LED OFF");
}
previous_station_count = current_station_count;
delay(2000);
}
效果展示
- 编译并上传程序后,你可以通过 WLAN 功能发现该 AP 热点。

- 连接成功后,串口监视器会打印 IP 地址,同时板载 USER LED 会点亮。

WiFi 与 MQTT 的使用
MQTT 协议在物联网设备中被广泛使用,而 XIAO ESP32-C5 支持该协议——这意味着你可以使用 XIAO ESP32-C5 开发许多有趣的物联网项目。
程序
接下来将提供一个参考程序,向你展示如何在 XIAO ESP32-C5 上使用 MQTT 协议。
- 安装
PubSubClient库

- 参考代码
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
// Using a public MQTT broker for demonstration
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
WiFiClient espClient;
PubSubClient client(espClient);
// Callback function: Executed when a message is received
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
String clientId = "ESP32C5Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, subscribe to a topic
client.subscribe("esp32c5/test/topic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Connected");
// Configure MQTT Server
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Publish a message every 2 seconds
static unsigned long lastMsg = 0;
unsigned long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
Serial.println("Publishing message...");
client.publish("esp32c5/test/topic", "Hello from XIAO ESP32-C5");
}
}
效果展示
-
下载任意支持 MQTTX broker 客户端的软件,这里使用 MQTTX MQTTx
-
打开 MQTTX 并添加客户端信息。此处使用默认客户端地址,因此你只需添加客户端 ID
ESP32C5Client并设置测试客户端名称,其余配置保持默认即可。

- 上传代码并使用 MQTTX 进行连接。连接成功后,点击左侧的
New Subscription来添加订阅。

- 配置订阅信息:输入
esp32c5/test/topic并为 QoS 选择 0 或 1。

- 配置成功后,你可以看到 XIAO ESP32-C5(作为客户端)每 2 秒发布的消息。你也可以在选择主题后向客户端发送消息,客户端在接收到消息后会将其发布。

broker.emqx.io 是一个所有用户共享的公共 broker。任何订阅相同主题的人都可以查看你的消息。它仅用于测试目的,不适合传输敏感数据。
WiFi & HTTP /HTTPS
-
你可以参考我们为 XIAO ESP32C3 编写的访问 ChatGPT 的示例,其中详细介绍了如何使用 WiFiClient 和 HTTPClient:Learn to use WiFiClient and HTTPClient on XIAO ESP32C3 - XIAO ESP32C3 & ChatGPT in action
-
如果你只想了解 HTTP 的简单用法,也可以按照下面的步骤进行测试和验证。
程序
- 安装
HTTPClient库

- 参考代码
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h> // Required for HTTPS
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
// HTTPS Endpoint
const char* serverUrl = "https://jsonplaceholder.typicode.com/todos/1";
// Root CA Certificate (Optional for simple testing if setInsecure is used)
// To be secure, you should use the actual root CA of the website.
// For this example, we will use setInsecure().
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected");
}
void loop() {
if ((WiFi.status() == WL_CONNECTED)) {
// 1. Create WiFiClientSecure object
WiFiClientSecure client;
// IGNORE SSL certificate validation (Good for testing, NOT for production)
client.setInsecure();
// 2. Create HTTPClient object
HTTPClient http;
Serial.print("[HTTPS] begin...\n");
// 3. Initialize connection
if (http.begin(client, serverUrl)) {
Serial.print("[HTTPS] GET...\n");
// 4. Send GET request
int httpCode = http.GET();
// 5. Check return code
if (httpCode > 0) {
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
if (httpCode == HTTP_CODE_OK || httpCode == 301 || httpCode == 302) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
// 6. Close connection
http.end();
} else {
Serial.printf("[HTTPS] Unable to connect\n");
}
}
delay(10000);
}
效果展示
https://jsonplaceholder.typicode.com 是一个免费的模拟 REST API 测试服务,专为开发和测试目的而设计。它不支持对真实数据进行永久修改或持久化。
- 上传代码,然后你可以打开
https://jsonplaceholder.typicode.com/todos/1和 Arduino IDE 中的串口监视器工具,检查信息是否一致。

WiFi-Mesh
以下是乐鑫官方对 ESP-WIFI-MESH 的介绍:
ESP-WIFI-MESH 是一种无线通信网络,其节点在乐鑫 SoC 上利用 AP-STA 同时工作特性,以 Mesh 拓扑结构进行组织。它提供了自组网和自愈能力,易于部署。ESP-WIFI-MESH 的网络拓扑可以在大范围内扩展到多达 1000 个节点,而无需任何特定的 Wi-Fi 基础设施支持。ESP-WIFI-MESH 还可用于在家庭部署场景中覆盖 Wi-Fi 盲区,即 Wi-Fi 信号无法覆盖的区域。
如需了解更详细的信息,请参考乐鑫官方链接:
接下来,我将向你展示一个 ESP-Mesh 的示例,对于该示例,你需要至少准备两块 ESP32 设备。
程序
- 安装
Alteriom PainlessMesh库

- 安装
AsyncTCP库

- 参考代码
#include "painlessMesh.h"
#define MESH_PREFIX "ESP32_C5_MESH"
#define MESH_PASSWORD "mesh_password123"
#define MESH_PORT 5555
painlessMesh mesh;
Scheduler userScheduler; // to control your personal task
void sendMessage(); // Prototype
// Define a task to send messages every 1 second
Task taskSendMessage(1000, TASK_FOREVER, &sendMessage);
void sendMessage() {
String msg = "Hello from node ";
msg += mesh.getNodeId();
mesh.sendBroadcast(msg);
Serial.printf("Sent broadcast: %s\n", msg.c_str());
}
// Callback: When a message is received
void receivedCallback( uint32_t from, String &msg ) {
Serial.printf("Received from %u msg=%s\n", from, msg.c_str());
}
// Callback: When a new connection is established
void newConnectionCallback(uint32_t nodeId) {
Serial.printf("New Connection, nodeId = %u\n", nodeId);
}
// Callback: When connection changes
void changedConnectionCallback() {
Serial.printf("Changed connections\n");
}
// Callback: Time adjustment
void nodeTimeAdjustedCallback(int32_t offset) {
Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
}
void setup() {
Serial.begin(115200);
// Debug messages
mesh.setDebugMsgTypes( ERROR | STARTUP );
// Initialize Mesh
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
// Register Callbacks
mesh.onReceive(&receivedCallback);
mesh.onNewConnection(&newConnectionCallback);
mesh.onChangedConnections(&changedConnectionCallback);
mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);
// Add task to scheduler
userScheduler.addTask( taskSendMessage );
taskSendMessage.enable();
}
void loop() {
// Keep the mesh network running
mesh.update();
}
效果展示
- 将代码上传到两块 XIAO ESP32-C5 设备上,并打开任意串口工具查看结果。
XIAO ESP32-C5 设备 1 开始组网并发送消息。

XIAO ESP32-C5 设备 2 加入网络并接收来自设备 1 发送的消息。

示例:IoT 智能家居中控
通过以上 Wi-Fi 示例,你一定已经掌握了如何在 XIAO ESP32-C5 上使用 Wi-Fi。接下来将通过一个示例向你展示如何使用 Wi-Fi AP 模式和 HTTP 网络服务实现智能家居控制中枢——具体来说,就是如何使用 XIAO ESP32-C5 作为智能家居控制中枢来监控你家中的状态。
- 安装
ESPAsyncWebServer库

- 上传代码并连接到
XIAO ESP32-C5热点。
参考代码
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <DNSServer.h>
const char* ssid = "XIAO ESP32-C5"; // Hotspot name
const char* password = "12345678"; // Hotspot password (empty for no password, configurable)
DNSServer dnsServer;
AsyncWebServer server(80);
// HTML content for temporary website (You can modify the content here, e.g., add redirect to external website)
// const char index_html[] PROGMEM = R"rawliteral(
// <!DOCTYPE html>
// <html>
// <head>
// <title>Temporary Website</title>
// <meta charset="UTF-8">
// <!-- Optional: Add automatic redirect to external website -->
// <!-- <meta http-equiv="refresh" content="5;url=https://example.com"> -->
// </head>
// <body>
// <h1>Welcome to XIAO ESP32-C5 Temporary Website!</h1>
// <p>You have connected to XIAO-ESP32-C5 hotspot. This is custom content.</p>
// <form action="/" method="POST">
// <input type="submit" value="Continue">
// </form>
// </body>
// </html>
// )rawliteral";
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>XIAO ESP32-C5 Control Center</title>
<style>
:root {
--bg-color: #121212;
--card-bg: #1e1e1e;
--text-main: #e0e0e0;
--text-sub: #a0a0a0;
--accent: #00e5ff; /* Neon Blue */
--active: #00ff9d; /* Active Green */
--danger: #ff4081; /* Warning Red */
}
body {
font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
background-color: var(--bg-color);
color: var(--text-main);
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
h1 {
font-weight: 300;
letter-spacing: 1.5px;
margin-bottom: 10px;
text-align: center;
}
p.subtitle {
color: var(--text-sub);
font-size: 0.9rem;
margin-top: 0;
margin-bottom: 30px;
text-align: center;
}
/* Container Layout */
.container {
width: 100%;
max-width: 400px; /* Suitable width for mobile devices */
display: flex;
flex-direction: column;
gap: 20px;
}
/* Status Panel */
.status-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.card {
background-color: var(--card-bg);
border-radius: 12px;
padding: 15px;
text-align: center;
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
border: 1px solid #333;
transition: transform 0.2s;
}
.card:active {
transform: scale(0.98);
}
.card-icon {
font-size: 24px;
margin-bottom: 5px;
display: block;
}
.card-value {
font-size: 1.2rem;
font-weight: bold;
color: var(--accent);
}
.card-label {
font-size: 0.8rem;
color: var(--text-sub);
}
/* Control Button Area */
.control-group {
background-color: var(--card-bg);
border-radius: 16px;
padding: 20px;
border: 1px solid #333;
}
.control-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid #333;
}
.control-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
/* Switch Style */
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 26px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #333;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: var(--accent);
box-shadow: 0 0 10px var(--accent);
}
input:checked + .slider:before {
transform: translateX(24px);
}
/* Main Button */
.main-btn {
width: 100%;
padding: 15px;
background: linear-gradient(45deg, var(--accent), #00b8d4);
border: none;
border-radius: 30px;
color: #000;
font-weight: bold;
font-size: 1rem;
cursor: pointer;
margin-top: 20px;
text-transform: uppercase;
letter-spacing: 1px;
}
.main-btn:active {
opacity: 0.9;
transform: scale(0.98);
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>XIAO ESP32-C5</h1>
<p class="subtitle">IoT Smart Home Hub</p>
</header>
<div class="status-grid">
<div class="card">
<span class="card-icon">📡</span>
<div class="card-value">Online</div>
<div class="card-label">System Status</div>
</div>
<div class="card">
<span class="card-icon">🌡️</span>
<div class="card-value" id="temp-val">26.5°C</div>
<div class="card-label">Indoor Temperature</div>
</div>
<div class="card">
<span class="card-icon">💧</span>
<div class="card-value">58%</div>
<div class="card-label">Air Humidity</div>
</div>
<div class="card">
<span class="card-icon">⏱️</span>
<div class="card-value">12ms</div>
<div class="card-label">Latency</div>
</div>
</div>
<div class="control-group">
<div class="control-item">
<span>Living Room Main Light</span>
<label class="switch">
<input type="checkbox" id="btn-light" onchange="toggleDevice('light', this)">
<span class="slider"></span>
</label>
</div>
<div class="control-item">
<span>Air Purifier</span>
<label class="switch">
<input type="checkbox" id="btn-fan" onchange="toggleDevice('fan', this)">
<span class="slider"></span>
</label>
</div>
<div class="control-item">
<span>Auto Mode</span>
<label class="switch">
<input type="checkbox" checked onchange="toggleDevice('auto', this)">
<span class="slider"></span>
</label>
</div>
</div>
<form action="/" method="POST">
<button type="submit" class="main-btn">Enter Advanced Settings</button>
</form>
</div>
<script>
// Simple JavaScript for demo interaction
function toggleDevice(device, element) {
var state = element.checked ? "ON" : "OFF";
console.log(device + " is now " + state);
// You can add fetch request to send to ESP32 here
// fetch('/toggle?device=' + device + '&state=' + state);
}
// Simulate dynamic data fluctuation effect
setInterval(() => {
const temp = 26 + (Math.random() * 0.5);
document.getElementById('temp-val').innerText = temp.toFixed(1) + "°C";
}, 3000);
</script>
</body>
</html>
)rawliteral";
// Handle all requests and redirect to temporary page
class CaptiveRequestHandler : public AsyncWebHandler {
public:
CaptiveRequestHandler() {}
virtual ~CaptiveRequestHandler() {}
bool canHandle(AsyncWebServerRequest *request) {
return true; // Handle all requests
}
void handleRequest(AsyncWebServerRequest *request) {
request->send_P(200, "text/html", index_html); // Return HTML content
}
};
void setup() {
Serial.begin(115200);
delay(10);
// Set to AP (Access Point) mode
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("Hotspot created: " + String(ssid));
Serial.print("IP Address: ");
Serial.println(WiFi.softAPIP());
// Start DNS server, redirect all domains to local IP
dnsServer.start(53, "*", WiFi.softAPIP());
// Configure Web Server: redirect all not found requests to temporary page
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER); // Only in AP mode
server.onNotFound([](AsyncWebServerRequest *request) {
request->send_P(200, "text/html", index_html);
});
server.begin();
Serial.println("Web Server started");
server.on("/toggle", HTTP_GET, [](AsyncWebServerRequest *request){
String device = request->getParam("device")->value();
String state = request->getParam("state")->value();
Serial.print("Device: ");
Serial.print(device);
Serial.print(" State: ");
Serial.println(state);
if(device == "light" && state == "ON") {
digitalWrite(LED_BUILTIN, LOW); // Assume LOW level turns on the LED
} else {
digitalWrite(LED_BUILTIN, HIGH);
}
request->send(200, "text/plain", "OK");
});
}
void loop() {
dnsServer.processNextRequest(); // Process DNS requests
delay(10);
}

- 输入 IP 地址以跳转到网页。

网页上显示的控件和传感器是可自定义的。您可以根据自己的具体需求添加新的控件,并修改生成的网页。参考:ESPAsyncWebServer
XIAO ESP32-C5 生成的 AP 热点默认无法连接互联网。如果需要连接互联网,可以采用以下两种方法之一:
方法一:将 XIAO ESP32-C5 连接到 Home Assistant。参考:Connecting XIAO ESP32-C5 to Home Assistant
方法二:使用 MQTT 服务将数据上传到云服务器。请注意,此方法可能需要购买一定数量的服务点数。参考:Goole Cloud
技术支持与产品讨论
感谢您选择我们的产品!我们将为您提供多种支持,确保您在使用我们产品的过程中尽可能顺利。我们提供多种沟通渠道,以满足不同的偏好和需求。
