arduino-esp32 WiFiScanTime 示例精讲:用自定义驻留时间精确控制 ESP32 的 Wi-Fi 扫描行为
arduino-esp32 WiFiScanTime 示例精讲用自定义驻留时间精确控制 ESP32 的 Wi-Fi 扫描行为【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32本篇围绕libraries/WiFi/examples/WiFiScanTime示例展开讲解如何为 ESP32 系列芯片的 Wi-Fi 扫描设置每信道最小/最大驻留时间从而在扫描速度与网络发现率之间取得平衡。读完后你将掌握WiFi.scanNetworks()的完整参数语义、setScanActiveMinTime()的作用机制以及扫描结果SSID、RSSI、信道、加密类型的读取与内存释放方法并能从源码层面理解 Arduino 封装之下 ESP-IDF 扫描流程的真实实现。示例定位与适用目标WiFiScanTime是libraries/WiFi库内置的一组 Wi-Fi 扫描示例之一用于演示使用自定义扫描时序custom scan timing扫描可用 Wi-Fi 网络并打印结果。同目录下还有几个相关示例可作对照WiFiScan基础同步扫描、WiFiScanAsync异步扫描、WiFiScanDualAntenna双天线扫描本示例的独特点在于显式控制每个信道的驻留时间。根据 README该示例支持的目标芯片如下支持的目标ESP32ESP32-S2ESP32-C3ESP32-S3ESP32-C6从源码结构看这一限制与构建配置直接对应。示例的 ci.yml 声明了requires_any条件CONFIG_SOC_WIFI_SUPPORTEDy或CONFIG_ESP_HOSTED_ENABLEDy即只有 SoC 原生支持 Wi-Fi、或启用了 ESP Hosted通过另一颗协处理芯片提供 Wi-Fi的构建才会编译运行该示例。库源码 WiFiScan.h 中同样以#if SOC_WIFI_SUPPORTED || CONFIG_ESP_HOSTED_ENABLED包裹整个类定义二者是一致的。核心概念扫描驻留时间min / max语义示例文件 WiFiScanTime.ino 开头的注释给出了这套 API 最关键的行为约定——活跃扫描active scan下min_time与max_time四种组合的语义min 取值max 取值行为min0, max0—每个信道驻留固定的 120 ms底层默认值min0, max0—每个信道驻留固定的 120 msmin0, max0—每个信道驻留maxmsmin0, max0—每个信道至少驻留minms若这段时间内未发现任何 AP立即跳到下一信道若发现了 AP则驻留延长至maxms 以收集更多结果这套规则正是 ESP-IDFwifi_scan_config_t.scan_time.active.min/max字段的语义。它解决的是一个实际工程问题全信道扫描 13 个2.4 GHz 频段信道时若每个信道都驻留较长时间扫描总时长会成倍增加阻塞主循环而驻留时间太短又会漏掉响应慢、信号弱的 AP。min保证没有收获就快速跳过max保证有收获就多收集。示例代码逐段解析示例的完整逻辑可以拆为三步设置每信道最小驻留时间、发起带最大驻留时间的同步扫描、格式化打印并释放结果。1. 准备射频进入 Station 模式// Set WiFi to station mode and disconnect from an AP if it was previously connected. WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100);扫描前必须让 Wi-Fi 处于 Station 模式并断开已有连接。从 WiFiScan.cpp 的实现看scanNetworks()内部会调用WiFi.enableSTA(true)即底层已保证 STA 射频使能但显式调用WiFi.mode(WIFI_STA)WiFi.disconnect()可以确保从 SoftAP 或 STAAP 模式干净地切出避免 AP 广播与扫描相互干扰。2. 设置最小驻留时间并发起扫描void wifiScan(uint16_t min_time, uint16_t max_time) { Serial.println(Scan start); // Set the minimum time per channel for active scanning. WiFi.setScanActiveMinTime(min_time); // Capture the start time of the scan. uint32_t start millis(); // WiFi.scanNetworks will return the number of networks found. // Scan networks with those options: Synchrone mode, show hidden networks, // active scan, max scan time per channel. int n WiFi.scanNetworks(false, true, false, max_time); Serial.printf(Scan done, elapsed time: % PRIu32 ms\n, millis() - start); ... }注意min和max走的是两条不同的 API 通道这是本示例最容易忽视的细节min通过WiFi.setScanActiveMinTime(min_time)单独设置写入 WiFiScan.cpp 中的静态成员_scanActiveMinTime默认值为 100 ms见 第 49 行在后续每次scanNetworks()构建配置时生效max则作为scanNetworks()的第 4 个位置参数max_ms_per_chan直接传入。scanNetworks()的完整原型见 WiFiScan.h及默认值如下int16_t scanNetworks( bool async false, // 是否异步扫描true 时立即返回 bool show_hidden false, // 是否包含隐藏 SSID 的网络 bool passive false, // true被动扫描只监听 beaconsfalse主动扫描发送 probe uint32_t max_ms_per_chan 300, // 每信道最大驻留时间被动模式下为监听时长 uint8_t channel 0, // 0 表示扫描全部信道非 0 只扫指定信道 const char *ssid nullptr, // 非空则只匹配指定 SSID const uint8_t *bssid nullptr // 非空则只匹配指定 AP 的 MAC );示例调用WiFi.scanNetworks(false, true, false, max_time)的含义是同步模式、显示隐藏网络、主动扫描、每信道最大驻留max_timems。返回值语义为成功时返回发现的 AP 数量异步模式下扫描进行中返回WIFI_SCAN_RUNNING扫描超时或底层启动失败返回WIFI_SCAN_FAILED详见 WiFiScan.cpp 第 67–107 行。3. 格式化打印扫描结果示例按固定列宽打印序号、SSID最长 32 字符截断、RSSI、信道与加密类型for (int i 0; i n; i) { Serial.printf(%2d, i 1); Serial.print( | ); Serial.printf(%-32.32s, WiFi.SSID(i).c_str()); Serial.print( | ); Serial.printf(%4 PRIi32, WiFi.RSSI(i)); Serial.print( | ); Serial.printf(%2 PRIi32, 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(WPAWPA2); 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(WPA2WPA3); break; case WIFI_AUTH_WAPI_PSK: Serial.print(WAPI); break; default: Serial.print(unknown); } Serial.println(); delay(10); }这些取值函数最终都落在 WiFiScan.cpp 的SSID()、RSSI()、channel()、encryptionType()等方法上它们按索引取出wifi_ap_record_t记录并返回对应字段ssid、rssi、primary、authmode。示例的注释也特别提醒encryptionType()的返回值与老版 Arduino WiFi Shield 库不同因为新增了 WPA3、WPA2WPA3 等现代加密模式的枚举值。除SSID(i)外库还提供BSSID(i)/BSSIDstr(i)获取 AP 的 MAC 地址WiFiScan.cpp 第 255–284 行以及一次性取出全部字段的getNetworkInfo()第 197–208 行。4. 释放结果并循环演示// Delete the scan result to free memory for code below. WiFi.scanDelete(); // Wait a bit before scanning again delay(2000);WiFi.scanDelete()会释放上一次扫描结果的堆内存_scanResult缓冲、清零_scanCount并清除扫描状态位WiFiScan.cpp 第 177–185 行。在 RAM 有限的设备上读完结果后及时调用它是良好习惯。5. setup() 中的三组对照扫描void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); // 每信道最小 100 ms / 最大 300 ms默认值组合 wifiScan(100, 300); // 最小 100 ms / 最大 1500 ms有 AP 时驻留更久发现更全耗时更长 wifiScan(100, 1500); // 最小 0 ms / 最大 1500 ms无 AP 时快速跳信道有 AP 时最长驻留 1500 ms wifiScan(0, 1500); }loop()为空示例只在setup()中完成三轮扫描正好覆盖默认组合、拉大 max、min 归零三种典型配置方便对比不同参数下打印的elapsed time与网络数量的差异。底层实现Arduino 封装到 ESP-IDF 的调用链从源码结构看scanNetworks()WiFiScan.cpp 第 67–107 行的完整流程是防重入若状态位WIFI_SCANNING_BIT已置位说明已有扫描在进行直接返回WIFI_SCAN_RUNNING清理旧结果调用scanDelete()释放上一次结果构建wifi_scan_config_t填入ssid、bssid、channel、show_hidden按passive标志选择WIFI_SCAN_TYPE_PASSIVE此时max_ms_per_chan写入scan_time.passive或WIFI_SCAN_TYPE_ACTIVEmin取静态成员_scanActiveMinTimemax取参数max_ms_per_chan——这正是上文 min/max 四种组合语义的落点启动扫描调用 ESP-IDF 的esp_wifi_scan_start(config, false)同步阻塞模式成功后记录_scanStarted millis()并等待WIFI_SCAN_DONE_BIT状态位最长等待_scanTimeout默认 60000 ms见 第 47 行可用WiFi.setScanTimeout()修改结果回调扫描完成事件触发_scanDone()第 115–137 行它通过esp_wifi_scan_get_ap_num()取得 AP 数量再calloc分配wifi_ap_record_t数组并用esp_wifi_scan_get_ap_records()填充最后置位WIFI_SCAN_DONE_BIT唤醒等待方。如果改用异步模式scanNetworks(true, ...)函数会立即返回WIFI_SCAN_RUNNING此时需要轮询WiFi.scanComplete()未完成返回WIFI_SCAN_RUNNING完成返回网络数量超过_scanTimeout超时则清位并返回WIFI_SCAN_FAILED第 157–172 行。这正是同目录下WiFiScanAsync示例采用的模式适合需要扫描期间保持 CPU 响应性的场景。期望的串口输出按 README 给出的样例烧录后串口115200 波特率示例中Serial.begin(115200)输出形如Setup done Scan start Scan done, elapsed time: 4960 ms 17 networks found Nr | SSID | RSSI | CH | Encryption 1 | IoTNetwork | -62 | 1 | WPA2 2 | WiFiSSID | -62 | 1 | WPA2-EAP 3 | B3A7992 | -63 | 6 | WPAWPA2 4 | WiFi | -63 | 6 | WPA3 5 | IoTNetwork2 | -64 | 11 | WPA2WPA3 ...其中Scan done, elapsed time一行即示例中millis() - start的实测值它随max参数增大、以及环境中 AP 密度变化而变化是判断参数调优效果的直接依据。使用方法与排错README 中给出的操作步骤在 Arduino IDE 中编译/验证前通过Tools - Board选择正确的板卡再通过Tools - Port: xxx选择已识别的 COM 口然后编译烧录libraries/WiFi/examples/WiFiScanTime/WiFiScanTime.ino即可。README 的 Troubleshooting 一节同样值得保留在实操清单里首要前提使用质量可靠的 USB 数据线并确保供电充足编程失败Programming Fail尝试降低串口连接速度COM 口未被识别检查 USB 线连接与 USB 转串口驱动安装情况。结合源码还可以补充一点排错视角若扫描完成但返回 0 个网络可检查是否误用了passivetrue且驻留时间过短被动扫描依赖 AP 主动发 beacon响应慢的 AP 容易漏检若长时间阻塞后返回失败值则受setScanTimeout()的超时上限默认 60 s约束。小结WiFiScanTime示例用不到百行代码覆盖了 ESP32 Wi-Fi 扫描时序控制的全部关键点setScanActiveMinTime()管理每信道最小驻留静态状态、默认 100 msscanNetworks()的第 4 个参数管理最大驻留默认 300 ms两者共同决定每个信道快跳还是久留结果通过SSID/RSSI/channel/encryptionType/BSSIDstr等索引接口读取用scanDelete()释放底层则是wifi_scan_config_t→esp_wifi_scan_start()→_scanDone()回调这条清晰的 ESP-IDF 调用链。对于需要在扫描延迟与AP 发现完整度之间做取舍的应用如自动选网、信号测量、Mesh 选父节点这组参数是最直接的调优入口。【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考