ESP-IDF+vscode开发ESP32 联网篇第一讲——WIFI扫描

📅 2026/7/27 5:50:48
ESP-IDF+vscode开发ESP32 联网篇第一讲——WIFI扫描
目录前言一、WIFI的相关术语1.1 基础术语1.2 标准与协议1.3 安全相关1.4 信号与性能1.5 组网与拓扑1.6 网络功能1.7 实用场景二、工程实现2.1 项目结构全览2.2 WIFI 组件深度解析2.2.1 模块架构2.2.2 初始化管线2.2.3 事件处理流程2.2.4 关键函数详解2.3 系统构建2.4 WIFI组件代码展览CMakeLists.txtscan.cscan.h三、输出展示注意前言ESP32 作为面向物联网应用的芯片具备较强的无线联网能力。为便于系统介绍其联网功能本文单独开设联网篇首先讲解 Wi‑Fi 扫描的实现方法。本文使用微雪 ESP32-C6-DEV-KIT-N16 开发板开发环境为 ESP-IDF 6.0.1。工程模板与前文 ESP32-P4 示例模板基本一致相关代码可从我的 Gitee 仓库获取。《https://gitee.com/pai-schoolmate/esp32_project.git》一、WIFI的相关术语关于WIFI相信同学们已经很熟悉了但是关于WIFI的一些专业知识肯定有一些薄弱那么这里来进行一个复习。1.1 基础术语APAccess Point接入点无线接入点发出 WiFi 信号的设备。家用无线路由器本身就集成了 AP 功能。STAStation站点连接到无线网络的终端设备也就是你的手机、笔记本电脑、智能电视、智能音箱等。AP 和 STA 是 WiFi 中最核心的一对角色关系AP 发信号STA 连上来。SSIDService Set IdentifierWiFi 网络的名字。你在设备上看到的 WiFi 列表里的每一个名称就是一个 SSID。BSSIDBasic Service Set IdentifierAP 的 MAC 地址是物理层面唯一标识。同一个 SSID 下可能有多个 BSSID比如 Mesh 网络的多个节点。频段BandWiFi 使用的无线电频率范围目前主要有三个2.4GHz穿墙能力强、覆盖远但干扰多蓝牙、微波炉、无线鼠标都用这个频段速度相对慢5GHz速度快、干扰少但穿墙能力弱、覆盖距离短6GHzWiFi 6E 和 WiFi 7 新增的频段更宽的频道、更高的速度、更少的干扰1.2 标准与协议WiFi 4 / 5 / 6 / 7IEEE 802.11 协议族的商业命名商业名技术标准推出年份主要提升WiFi 4802.11n2009引入 MIMO速度突破百兆WiFi 5802.11ac2014主攻 5GHz速度达 Gbps 级别WiFi 6802.11ax2019高密场景优化更低延迟更省电WiFi 7802.11be2024320MHz 频宽速度可达 30GbpsMIMOMultiple-Input Multiple-Output多入多出技术。路由器用多根天线同时收发数据就像多条车道同时跑车。常见标注如 2x2 MIMO、4x4 MIMO。MU-MIMOMulti-User MIMO多用户 MIMO允许路由器同时和多个 STA 通信。WiFi 5 只支持下行 MU-MIMOWiFi 6 支持上下行都支持。OFDMAOrthogonal Frequency Division Multiple Access正交频分多址WiFi 6 引入的技术。把一个信道分成更小的子信道可以在同一时刻给多个设备发送小数据包大幅降低延迟、提升多设备场景下的效率。1.3 安全相关WEP最早的加密协议极其脆弱几分钟就能破解早已被淘汰。WPA / WPA2 / WPA3WPAWEP 的替代品现在也已不安全WPA2目前最广泛使用的标准采用 AES 加密对普通家庭足够安全WPA3最新标准引入 SAE 握手替代 WPA2 的 PSK防暴力破解即使密码弱也不易被离线破解WPSWiFi Protected Setup通过按路由器上的按钮或输入 PIN 码快速连接 WiFi。但 PIN 方式存在严重安全漏洞建议在路由器后台关闭 WPS。MAC 地址过滤路由器设置只允许特定 MAC 地址的设备连接。看起来能增强安全但实际上 MAC 地址可以伪造防御能力有限。1.4 信号与性能dBm分贝毫瓦信号强度的单位通常为负值越接近 0 越强-30 dBm极强紧贴路由器-50 dBm良好-67 dBm可靠高清视频流的最低要求-80 dBm弱可能不稳定-90 dBm几乎不可用RSSIReceived Signal Strength Indicator接收信号强度指示与 dBm 类似用来衡量 STA 收到的 AP 信号强弱。经常直接用dBm做单位。信道ChannelWiFi 工作的具体频率划分。2.4GHz 国内有 13 个信道1-13其中 1、6、11 互不重叠。5GHz 信道更多且支持更宽的频宽20/40/80/160MHz。信道干扰Co-Channel Interference / Adjacent-Channel Interference邻居的 WiFi 用相同或相邻信道时产生的互相干扰是导致网速变慢甚至不稳定的常见原因。频宽Channel Bandwidth信道的宽度越宽速度越快但越容易被干扰。常见的20MHz、40MHz、80MHz、160MHz。1.5 组网与拓扑Mesh网状网络多个 AP 节点组成一个统一的 WiFi 网络设备在不同节点间自动切换全屋只有一个 SSID实现无缝覆盖。三频 Mesh 会用单独一个 5GHz 频段做节点间回传性能更好。漫游RoamingSTA 从一个 AP 的覆盖范围移动到另一个 AP 时自动切换连接的过程。802.11k / 802.11v / 802.11r快速漫游协议802.11k让 STA 提前知道附近有哪些 AP 可选802.11v让 AP 主动建议 STA 切换到哪个 AP802.11r简化重认证流程切换更快这三者合称快速漫游对视频通话、在线游戏等实时业务体验提升明显。WDSWireless Distribution System无线分布式系统允许 AP 之间通过无线方式互联扩展覆盖范围。相比 Mesh 配置复杂性能也差一些。中继Repeater / Extender接收主路由的信号再转发出去会损失一半带宽半双工而且会增加延迟。Mesh 在很大程度上已经取代了传统的中继模式。1.6 网络功能DHCPDynamic Host Configuration Protocol自动给接入的设备分配 IP 地址。路由器默认会开启 DHCP 服务你连上 WiFi 时自动获取 IP 就是它在工作。NATNetwork Address Translation网络地址转换把局域网内多个设备的私有 IP 映射到一个公网 IP 上网。这是家用路由器最核心的功能之一。LAN / WAN 端口WAN 口接光猫或入户宽带LAN 口接家里的有线设备VLANVirtual Local Area Network虚拟局域网把一个物理网络划分成多个逻辑隔离的网络。常用于区分访客网络和家庭网络或者 IPTV 和普通上网走不同的 VLAN。QoSQuality of Service服务质量路由器可以优先处理某些流量。比如设置游戏和视频通话的优先级高于下载保证关键业务不卡顿。端口转发Port Forwarding把从外网访问特定端口的流量转发到内网某台设备。搭建 NAS、远程访问摄像头、自建网站等场景常用。UPnPUniversal Plug and Play设备自动在路由器上开端口简化配置。虽然方便但有安全隐患建议在不必要时关闭。1.7 实用场景双频 / 三频双频同时支持 2.4GHz 和 5GHz三频一个 2.4GHz 两个 5GHz多见于高端 Mesh 路由器其中一个 5GHz 专门用于节点间回传天线增益dBi天线具有将信号集中方向的能力。增益越高信号传得越远但覆盖角度越小。家用路由器通常用 3-5dBi 的天线。PoEPower over Ethernet通过网线同时传输数据和电力。企业级 AP 常用 PoE 供电只需要一根网线既上网又取电。双频合一路由器把 2.4GHz 和 5GHz 使用同一个 SSID让设备自己选择连哪个频段。但有些设备会固执地连在 2.4GHz 上不切回 5GHz所以很多人会分开设置两个 SSID。Beamforming波束成形路由器将信号定向发射到特定设备的方向而不是全向广播可以提升特定设备的信号质量和速度。WAN 聚合 / LAN 聚合把两个网口绑定成一个实现双倍带宽。适合 NAS 等需要大带宽的场景。这份算是比较完整的常用 WiFi 术语清单了。涉及到的专业名词较多但都进行了非常通俗的解释结合现实实例还是比较好理解的。二、工程实现2.1 项目结构全览本工程采用ESP-IDF 组件化架构模式 A。顶层CMakeLists.txt通过EXTRA_COMPONENT_DIRS引入了 IDF 自带的 console 示例组件cmd_system、cmd_nvs、cmd_wifi免去手写系统命令的重复劳动。2.2 WIFI 组件深度解析2.2.1 模块架构文件components/WIFI/scan.c300 行——这是本工程代码量最大、逻辑最密集的模块完成从 WiFi 子系统初始化到扫描结果解析输出的全部工作。模块架构如下公开 APIwifi_scan_init()—— 唯一的对外接口由app_main()调用事件回调wifi_event_handler()—— 注册到 ESP-IDF 事件循环处理WIFI_EVENT_SCAN_DONE控制台命令scan_cmd_handler()register_scan_cmd()—— 让用户在 REPL 中手动触发重新扫描工具函数cipher_type_to_str()—— 将枚举转为可读字符串静态缓冲区ap_records[100]—— 文件作用域避免每次扫描动态分配内存2.2.2 初始化管线⚠ 顺序不可打乱ESP-IDF WiFi 初始化有严格的前置依赖。例如若先调用esp_wifi_init()再初始化 NVS驱动会因读不到 RF 校准数据而打印 warning 并使用默认射频参数。事件循环若未创建就注册回调esp_event_handler_instance_register()会返回ESP_ERR_INVALID_STATE。2.2.3 事件处理流程事件回调在扫描完成后由事件循环任务调用非 ISR 上下文因此可以安全地调用日志输出和内存操作。回调末尾的esp_wifi_clear_ap_list()是关键——不调用它扫描结果会一直占用 WiFi 驱动的内部缓冲区导致下一次扫描无法获取新结果。2.2.4 关键函数详解⚡ 初始化wifi_scan_init(void)完成 WiFi 子系统从零到可扫描的全部初始化并注册控制台命令。是 WIFI 组件唯一的公开 API。返回值无内部通过ESP_ERROR_CHECK断言失败直接 abort。注意NVS 初始化包含「损坏恢复」逻辑——若检测到ESP_ERR_NVS_NO_FREE_PAGES或ESP_ERR_NVS_NEW_VERSION_FOUND会自动擦除 NVS 分区后重试。这意味着首次烧录或 OTA 升级后不会因 NVS 格式变化而卡死。⚡ 初始化esp_event_loop_create_default(void)创建系统默认事件循环。ESP-IDF 的 WiFi、IP、蓝牙等子系统都通过该事件循环分发事件到用户注册的回调。返回值ESP_OK成功ESP_ERR_INVALID_STATE已存在重复调用安全ESP_ERR_NO_MEM内存不足。注意必须在esp_event_handler_instance_register()之前调用否则注册回调会返回ESP_ERR_INVALID_STATE。默认事件循环会创建一个独立的 FreeRTOS 任务栈大小由CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE决定默认 3584 字节。⚡ 初始化esp_wifi_init(const wifi_init_config_t *config)初始化 WiFi 驱动程序分配内部缓冲区、加载射频校准数据、初始化硬件寄存器。config指向wifi_init_config_t结构体的指针。通常使用WIFI_INIT_CONFIG_DEFAULT()宏生成默认配置包含 TX/RX 缓冲区数量、AMSDU 阈值等参数。返回值ESP_OK成功ESP_ERR_NO_MEM内存不足ESP_ERR_INVALID_ARG参数非法。注意依赖 NVS 已初始化射频校准数据从 NVS 读取和esp_netif_init()已完成。该函数只能调用一次重复调用返回ESP_ERR_INVALID_STATE。 事件注册esp_event_handler_instance_register(base, id, cb, arg, instance)向事件循环注册一个事件处理回调。当指定类型的事件被 post 到事件循环时回调函数将在事件循环任务上下文中被调用。event_base事件基类型如WIFI_EVENT、IP_EVENT。event_id具体事件 IDESP_EVENT_ANY_ID表示订阅该 base 下的所有事件。event_handler回调函数指针签名为void (*)(void*, esp_event_base_t, int32_t, void*)。event_handler_arg传递给回调的自定义参数透传本工程传 NULL。instance输出参数返回注册实例句柄可用于后续注销。本工程传 NULL 表示不保存。返回值ESP_OK成功ESP_ERR_INVALID_ARG参数非法ESP_ERR_NO_MEM内存不足。注意回调不在 ISR 中执行而是在事件循环任务中串行执行因此回调内可以调用日志、内存分配等非实时安全函数。但回调执行时间不宜过长否则会阻塞后续事件的处理。 配置esp_wifi_set_mode(wifi_mode_t mode)设置 WiFi 工作模式。必须在esp_wifi_start()之前调用。mode可选值WIFI_MODE_STA站点模式用于扫描/连接 AP、WIFI_MODE_AP软 AP 模式、WIFI_MODE_APSTA混合模式、WIFI_MODE_NULL关闭射频。返回值ESP_OK成功ESP_ERR_INVALID_ARG模式值非法ESP_ERR_WIFI_NOT_INITWiFi 未初始化。注意本工程使用WIFI_MODE_STA——扫描功能要求 STA 模式。若设为WIFI_MODE_NULL射频关闭扫描将返回错误。模式切换会触发WIFI_EVENT_STA_STOP/WIFI_EVENT_STA_START等事件。 控制esp_wifi_start(void)启动 WiFi 硬件开启射频并根据当前模式触发对应事件STA 模式触发WIFI_EVENT_STA_START。返回值ESP_OK成功ESP_ERR_WIFI_NOT_INIT未初始化ESP_ERR_WIFI_IF内部错误。注意必须在esp_wifi_set_mode()之后调用。启动后 WiFi 驱动开始占用 CPU 和内存资源。只有 start 之后才能调用esp_wifi_scan_start()、esp_wifi_connect()等操作函数。对应的停止函数为esp_wifi_stop()。 扫描esp_wifi_scan_start(const wifi_scan_config_t *config, bool block)触发一次 WiFi 扫描。扫描完成后产生WIFI_EVENT_SCAN_DONE事件结果通过esp_wifi_scan_get_ap_records()获取。config扫描配置指针。NULL表示使用默认配置全信道、全 SSID、主动扫描。可指定特定 SSID、信道列表、扫描类型主动/被动、各信道停留时间等。blocktrue 阻塞直到扫描完成再返回false 立即返回结果通过事件异步通知。本工程使用false以避免阻塞主任务。返回值ESP_OK成功ESP_ERR_WIFI_NOT_INIT未初始化ESP_ERR_WIFI_NOT_STARTED未 startESP_ERR_WIFI_IF正在扫描中或内部错误。注意全信道主动扫描在 2.4 GHz 下约耗时 1.5~2 秒13 个信道 × 120 ms/信道。扫描期间 STA 无法收发数据。若上一次扫描结果未通过esp_wifi_clear_ap_list()清除可能导致新扫描结果获取异常。2.3 系统构建顶层 CMakeLists.txtcmake_minimum_required(VERSION 3.22) set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ESP32C6_v6_temaplat)关键点EXTRA_COMPONENT_DIRS将 IDF 示例中的cmd_system、cmd_nvs、cmd_wifi组件引入本工程避免重复实现。组件依赖关系组件REQUIRESmain隐式依赖 basic、WIFIWIFIbasic · esp_event · esp_netif · esp_wifibasicconsole · cmd_system · cmd_nvs · cmd_wifi · nvs_flash · esp_partition2.4 WIFI组件代码展览CMakeLists.txtidf_component_register(SRCS scan.c INCLUDE_DIRS include REQUIRES basic esp_event esp_netif esp_wifi)scan.c/* * WiFi 扫描模块 — 实现文件 * * 功能 * 1. 初始化 NVS、TCP/IP 协议栈、事件循环、WiFi 子系统 * 2. 将 WiFi 设为 STA 模式并触发主动扫描 * 3. 在 SCAN_DONE 事件中打印前若干 AP 的详细信息 * * 依赖 * - ESP-IDF: nvs_flash, esp_netif, esp_wifi, esp_event, esp_log * - 本组件: scan.h函数声明、basic 组件 * */ /* ---------- 头文件 ---------- */ #include stdio.h /* 标准 I/O */ #include inttypes.h /* PRI 格式化宏如 PRIu16 */ #include scan.h /* 本模块接口声明 */ #include esp_log.h /* ESP 日志系统 */ #include nvs_flash.h /* 非易失性存储NVS */ #include esp_netif.h /* TCP/IP 网络栈初始化 */ #include esp_event.h /* 事件循环框架 */ #include esp_wifi.h /* WiFi 驱动 API */ /* ---------- 宏定义 ---------- */ /** 模块日志标签用于 ESP_LOGx 宏 */ static const char *TAG wifi_scan; /** 单次扫描最多缓存的 AP 数量 */ #define MAX_AP_NUM 100 /** * 打印 AP 详情的个数上限。 * * 注意这里设为 5 仅用于演示实际扫描到的 AP 可能远超这个数量。 * 如需全部输出请将 DISPLAY_AP_COUNT 改为 ap_num。 */ #define DISPLAY_AP_COUNT 5 /* ---------- 模块级文件作用域变量 ---------- */ /** 存储扫描结果的全局缓冲区文件内 static外部不可见 */ static wifi_ap_record_t ap_records[MAX_AP_NUM]; /* * 内部辅助函数 * */ /** * brief 将 wifi_cipher_type_t 枚举转为可读字符串 * * 覆盖 ESP-IDF 定义的全部 13 种密码类型wifi_cipher_type_t。 * 未知值返回 未知(?) 并附带原始数值便于调试。 */ static const char *cipher_type_to_str(wifi_cipher_type_t type) { switch (type) { case WIFI_CIPHER_TYPE_NONE: return 无; case WIFI_CIPHER_TYPE_WEP40: return WEP-40; case WIFI_CIPHER_TYPE_WEP104: return WEP-104; case WIFI_CIPHER_TYPE_TKIP: return TKIP; case WIFI_CIPHER_TYPE_CCMP: return CCMP (AES); case WIFI_CIPHER_TYPE_TKIP_CCMP: return TKIPCCMP; case WIFI_CIPHER_TYPE_AES_CMAC128: return AES-CMAC-128; case WIFI_CIPHER_TYPE_SMS4: return SMS4 (WAPI); case WIFI_CIPHER_TYPE_GCMP: return GCMP; case WIFI_CIPHER_TYPE_GCMP256: return GCMP-256; case WIFI_CIPHER_TYPE_AES_GMAC128: return AES-GMAC-128; case WIFI_CIPHER_TYPE_AES_GMAC256: return AES-GMAC-256; case WIFI_CIPHER_TYPE_UNKNOWN: return 未知; default: return 未知(?); } } /* * 内部函数 * */ /** * brief WiFi 事件处理回调 * * 当前仅处理 WIFI_EVENT_SCAN_DONE 事件 * - 获取扫描到的 AP 数量 * - 读取前 DISPLAY_AP_COUNT 个 AP 记录 * - 逐条打印 AP 的 MAC、RSSI、信道、SSID 等信息 * * note 扫描结果存储在文件级静态数组 ap_records 中。 */ static void wifi_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { /* 仅处理扫描完成事件 */ if (event_base WIFI_EVENT event_id WIFI_EVENT_SCAN_DONE) { /* ---- 1. 获取扫描到的 AP 总数 ---- */ uint16_t ap_num 0; ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(ap_num)); ESP_LOGI(TAG, 扫描完成共发现 % PRIu16 个 WiFi 网络, ap_num); /* ---- 2. 边界保护防止数组越界 ---- */ if (ap_num MAX_AP_NUM) { ap_num MAX_AP_NUM; } /* ---- 3. 读取 AP 记录到缓冲区 ---- */ ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(ap_num, ap_records)); /* ---- 4. 打印前 DISPLAY_AP_COUNT 个 AP 的详细信息 ---- */ ESP_LOGI(TAG, 扫描结果前 %d 个 , (ap_num DISPLAY_AP_COUNT) ? ap_num : DISPLAY_AP_COUNT); for (int i 0; (i DISPLAY_AP_COUNT) (i ap_num); i) { const wifi_ap_record_t *ap ap_records[i]; /* 4.1 基本信息MAC、RSSI、信道、SSID */ ESP_LOGI(TAG, [%d] MAC: %02x:%02x:%02x:%02x:%02x:%02x RSSI: %d dBm 信道: %d SSID: %s, i 1, ap-bssid[0], ap-bssid[1], ap-bssid[2], ap-bssid[3], ap-bssid[4], ap-bssid[5], ap-rssi, ap-primary, ap-ssid); /* 4.2 安全信息认证模式、加密类型 */ ESP_LOGI(TAG, 认证模式: %s 配对密码: %s 组密码: %s, ap-authmode WIFI_AUTH_OPEN ? Open : ap-authmode WIFI_AUTH_WEP ? WEP : ap-authmode WIFI_AUTH_WPA_PSK ? WPA-PSK : ap-authmode WIFI_AUTH_WPA2_PSK ? WPA2-PSK : ap-authmode WIFI_AUTH_WPA3_PSK ? WPA3-PSK : 其他, cipher_type_to_str(ap-pairwise_cipher), cipher_type_to_str(ap-group_cipher)); /* 4.3 频段与功能特性 * 优先用 PHY 标志位判断无法确定时用 primary 信道号兜底 * 802.11b/g → 2.4 GHz确定 802.11a/ac → 5 GHz确定 * 802.11n/ax → 多频段需结合其他标志或信道号 */ const char *band_str 未知; int has_24g ap-phy_11b || ap-phy_11g; /* b/g 是 2.4G 独有 */ int has_5g ap-phy_11a || ap-phy_11ac; /* a/ac 是 5G 独有 */ if (has_24g has_5g) { band_str 2.4 / 5 GHz (双频); } else if (has_24g) { band_str 2.4 GHz; } else if (has_5g) { band_str 5 GHz; } else if (ap-phy_11ax) { /* 仅 11ax 标志Wi-Fi 6/6E具体频段依赖信道号 */ if (ap-primary 1 ap-primary 14) { band_str 2.4 GHz (Wi-Fi 6); } else if (ap-primary 36 ap-primary 177) { band_str 5 GHz (Wi-Fi 6); } else { band_str 6 GHz (Wi-Fi 6E); } } else if (ap-phy_11n) { /* 仅 11n 标志大概率 2.4G用信道号确认 */ if (ap-primary 36 ap-primary 177) { band_str 5 GHz (802.11n); } else { band_str 2.4 GHz (802.11n); } } else { /* PHY 标志均无完全依赖信道号兜底 */ if (ap-primary 1 ap-primary 14) { band_str 2.4 GHz; } else if (ap-primary 36 ap-primary 177) { band_str 5 GHz; } } ESP_LOGI(TAG, 频段: %s WPS: %s FTM: %s, band_str, ap-wps ? 支持 : 不支持, ap-ftm_responder ? 支持 : 不支持); /* 4.4 带宽与中心频率 */ const char *bw_str 未知; switch (ap-bandwidth) { case 1: bw_str 20 MHz; break; case 2: bw_str 40 MHz; break; case 3: bw_str 80 MHz; break; case 4: bw_str 160 MHz; break; default: bw_str 未知; break; } /* 从主信道号计算中心频率MHz */ uint16_t center_freq 0; if (ap-primary 1 ap-primary 14) { center_freq 2407 ap-primary * 5; /* 2.4 GHz */ } else if (ap-primary 36 ap-primary 177) { center_freq 5000 ap-primary * 5; /* 5 GHz */ } /* 4.5 GHz VHT 宽信道使用 AP 上报的 VHT 频率 */ if (ap-bandwidth 2 ap-vht_ch_freq1 ! 0) { center_freq ap-vht_ch_freq1; } ESP_LOGI(TAG, 带宽: %s 中心频率: %d MHz, bw_str, center_freq); } ESP_LOGI(TAG, ); esp_wifi_clear_ap_list(); /* 清空扫描结果释放内存 */ } } /* * 控制台命令 * */ /** scan 命令的回调转发到 wifi_scan_trigger() */ static int scan_cmd_handler(int argc, char **argv) { ESP_LOGI(TAG, 触发重新扫描...); esp_err_t ret esp_wifi_scan_start(NULL, false); if (ret ! ESP_OK) { ESP_LOGE(TAG, 扫描启动失败: %s, esp_err_to_name(ret)); } return 0; } /** 注册 scan 控制台命令 */ void register_scan_cmd(void) { const esp_console_cmd_t cmd { .command scan, .help 触发一次 WiFi 全信道扫描结果通过日志输出, .hint NULL, .func scan_cmd_handler, }; ESP_ERROR_CHECK(esp_console_cmd_register(cmd)); } /* * 公开 API * */ /** * brief 初始化 WiFi 并触发一次全信道扫描 * * 本函数完成以下步骤 * 1. 初始化 NVSWiFi 校准数据存储依赖 * 2. 初始化 TCP/IP 协议栈esp_netif * 3. 创建默认事件循环 * 4. 初始化 WiFi 子系统默认配置 * 5. 注册 WIFI_EVENT 回调 * 6. 设置 WiFi 为 STA 模式并启动 * 7. 发起主动全信道扫描阻塞时间极短结果通过事件异步返回 */ void wifi_scan_init(void) { /* ---- 1. 初始化 NVS ---- */ esp_err_t ret nvs_flash_init(); if (ret ESP_ERR_NVS_NO_FREE_PAGES || ret ESP_ERR_NVS_NEW_VERSION_FOUND) { /* NVS 分区损坏或版本不兼容擦除后重新初始化 */ ESP_ERROR_CHECK(nvs_flash_erase()); ret nvs_flash_init(); } ESP_ERROR_CHECK(ret); /* ---- 2. 初始化 TCP/IP 协议栈 ---- */ ESP_ERROR_CHECK(esp_netif_init()); /* ---- 3. 创建默认事件循环 ---- */ ESP_ERROR_CHECK(esp_event_loop_create_default()); /* ---- 4. 初始化 WiFi 子系统默认配置 ---- */ wifi_init_config_t cfg WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(cfg)); /* ---- 5. 注册 WiFi 事件回调 ---- */ ESP_ERROR_CHECK( esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL, /* arg: 未使用 */ NULL)); /* instance: 未保存句柄 */ /* ---- 6. 设置为 STA 模式并启动 WiFi ---- */ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); /* ---- 7. 发起主动全信道扫描 ---- */ ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false)); ESP_LOGI(TAG, WiFi 初始化完成开始扫描 WiFi 网络...); register_scan_cmd(); // 注册scan控制台命令 }scan.h#ifndef SCAN_H #define SCAN_H #include string.h /* C 标准库字符串处理 */ #include esp_console.h /* ESP-IDF控制台框架 */ #include linenoise/linenoise.h /* ESP-IDF行编辑库 */ #include nvs_flash.h /* ESP-IDF非易失性存储NVS */ #include esp_partition.h /* ESP-IDF分区表查询 */ #include esp_log.h /* ESP-IDF日志系统 */ #include FreeRTOS/FreeRTOS.h /* FreeRTOS内核 */ #include FreeRTOS/task.h /* FreeRTOS任务管理 */ #include FreeRTOS/semphr.h /* FreeRTOS信号量管理 */ /** * brief 初始化 WiFi 扫描功能 * * 初始化 WiFi 扫描相关的数据结构和资源并执行首次扫描。 */ void wifi_scan_init(void); #endif /* SCAN_H */三、输出展示配对密码Pairwise Cipher单播加密— AP 与单个客户端之间通信使用的加密算法。当你的设备连接到 WiFi 后你和 AP 之间的数据包就是用这个算法加密的每个客户端拥有一把独立的密钥。组密码Group Cipher广播/组播加密— AP 向所有已连接客户端广播数据时使用的加密算法。AP 有时需要向所有客户端发送同样的信息如 ARP 广播这时用的就是组密码。所有连接到同一个 AP 的设备共享同一把组密钥。取值与配对密码相同同一个枚举。为什么需要两种单播密钥每人一把 → 更安全互不窃听组播密钥大家共用 → AP 只需加密一次所有客户端都能解密效率更高中心频率Center FrequencyWiFi 信道不是单一频率而是一段频率范围。中心频率就是这个范围的正中间位置。ESP32-C6 的 WiFi 射频模块仅支持 2.4 GHz 频段不支持 5 GHz。注意乐鑫官网明确说明ESP32-C6 的 WiFi 射频模块仅支持 2.4 GHz 频段不支持 5 GHz。ESP32-C6 的射频硬件根本无法接收5 GHz频率的信号所以无论怎么扫都扫不到。总结本文基于 ESP32-C6 与 ESP-IDF 6.0.1系统梳理了 WiFi 基础术语、协议标准、安全机制、信号与组网等概念并结合组件化工程示例完整实现并解析了一个可通过控制台命令触发的全信道 WiFi 扫描功能包含初始化流程、事件回调、AP 信息解析与日志输出等关键细节为后续拓展更多联网功能提供了可复用的基础框架和实践参考。