第四十八章 ESP32S3 扫描 WiFi 实验
ESP32-S3的WiFi库支持配置及监控ESP32-S3的Wi-Fi连网功能。它支持配置基站模式(即STA 模式或 WiFi 客户端模式),此时 ESP32-S3 连接到接入点(AP)。还支持 AP 模式(即SoftAP 模式或接入点模式),此时基站连接到 ESP32-S3。同时,支持 AP-STA 共存模式,此时ESP32-S3 既是接入点,同时又作为 STA。本章节的实验是基于乐鑫官方提供的 WiFi 库来实现的,但遗憾的是乐鑫并没有公开 WiFi 库的源码,所以只能调用 API 函数实现。
本章分为如下几个小节:
48.1 WiFi 模式概述
48.2 硬件设计
48.3 软件设计
48.4 下载验证
48.1 WiFi 模式概述
WiFi 主要有两种模式: STA 和 AP 模式。 AP 模式即无线接入点,是常说的手机热点,被其他设备连接; STA 模式即 Station,是连接热点的设备。另外, ESP32S3 可支持 STA 和 AP两种模式共存,就像手机那样可以开热点,也可以连接其他热点。
WiFi 库支持配置及监控 ESP32S3 Wi-Fi 连网功能。支持配置:
①: Station 模式(即 STA 模式或 WiFi 客户端模式),此时 ESP32 S3 连接到接入点 (AP)。
②: AP 模式(即 Soft-AP 模式或接入点模式),此时基站连接到 ESP32S3 设备。
③: Station/AP 共存模式(ESP32S3 既是接入点,同时又作为基站连接到另外一个接入点)。
④:上述模式的各种安全模式(WPA、 WPA2 及 WEP 等)。
⑤:扫描接入点(包括主动扫描及被动扫描)。
⑥:使用混杂模式监控 IEEE802.11 Wi-Fi 数据包。
下面学习ESP32S3 开启 WiFi 两种模式启动流程,如下:
(1) WiFi-AP 启动流程
WiFi-AP 启动流程如下。

图 48.1.1 AP 启动流程
上图展示了 ESP32 系列芯片以 AP 模式开启 WiFi 的启动流程。首先,系统需要对 lwIP 协议栈进行初始化。接着,创建一个任务,该任务将用于触发相应的事件。然后,配置 WiFi 参数和AP 模式参数。最后,启动 WiFi,从而完成以 AP 模式开启 WiFi 的操作。
(2)WiFi-STA 启动流程

图 48.1.2 STA 模式启动流程
上图展示了 ESP32 系列芯片以 STA 模式开启 WiFi 的启动流程。首先,系统需要创建定时器和事件组,并对 lwIP 协议栈进行初始化。接着,创建一个任务,该任务将用于触发相应的事件。然后,配置 WiFi 参数和 STA 模式参数。最后,启动 WiFi,从而完成以 STA 模式开启 WiFi的操作。
48.2 硬件设计
1. 例程功能
本章实验功能简介:扫描附近的 WIFI 信号,并在 LCD 显示屏右侧显示 12 个 WIFI 名称。
2. 硬件资源
1) LED 灯
LED-IO1
2) XL9555
IIC_INT-IO0(需在 P5 连接 IO0)
IIC_SDA-IO41
IIC_SCL-IO42
3) SPILCD
CS-IO21
SCK-IO12
SDA-IO11
DC-IO40(在 P5 端口,使用跳线帽将 IO_SET 和 LCD_DC 相连)
PWR- IO1_3(XL9555)
RST- IO1_2(XL9555)
4) ESP32-S3内部 WiFi
3. 原理图
本章实验使用的 WiFi 为 ESP32-S3 的片上资源,因此并没有相应的连接原理图。
48.3 软件设计
48.3.1 程序流程图
本实验的程序流程图。

图 48.3.1 程序流程图
48.3.2 程序解析
48.3.2.1 本次实验用到了库函数说明
(1)网络接口初始化函数
|
函数名 |
功能 |
参数 |
返回值 |
说明 |
|---|---|---|---|---|
|
|
初始化TCP/IP网络栈 |
无 |
|
使用任何网络功能前必须调用的基础初始化函数 |
|
|
创建默认的事件循环 |
无 |
|
用于处理WiFi、IP等系统事件的事件循环 |
|
|
创建默认的Station模式网络接口 |
无 |
|
创建并配置默认的STA模式网络接口,返回指向网络接口对象的指针 |
表 48.3.2.1 网络接口初始化函数说明
(2)WiFi驱动控制函数
|
函数名 |
功能 |
参数 |
返回值 |
说明 |
|---|---|---|---|---|
|
|
初始化WiFi驱动 |
|
|
使用 |
|
|
设置WiFi工作模式 |
|
|
必须在 |
|
|
启动WiFi |
无 |
|
根据之前设置的模式启动WiFi功能 |
表 48.3.2.2 WiFi驱动控制函数
|
结构体名称 |
说明 |
重要字段 |
|---|---|---|
|
|
WiFi初始化配置结构体 |
使用 |
常用WiFi模式wifi_mode_t枚举值:
|
枚举值 |
说明 |
|---|---|
|
|
WiFi未初始化 |
|
|
Station模式(连接其他热点) |
|
|
Access Point模式(创建热点) |
|
|
同时启用STA和AP模式 |
表 48.3.2.3 WiFi模式wifi_mode_t枚举值
(3)WiFi扫描相关函数
|
函数名 |
功能 |
参数 |
返回值 |
说明 |
|---|---|---|---|---|
|
|
开始WiFi扫描 |
|
|
默认配置会扫描所有信道,不指定特定SSID,显示隐藏网络 |
|
|
获取扫描到的AP数量 |
|
|
必须在扫描完成后调用 |
|
|
获取扫描到的AP详细信息 |
|
|
|
表 48.3.2.4 WiFi扫描相关函数
结构体wifi_ap_record_t字段说明:
|
字段名 |
类型 |
说明 |
取值范围/示例 |
|---|---|---|---|
|
|
|
接入点的 SSID(网络名称) |
最大32字符,以null结尾的字符串 |
|
|
|
接入点的 MAC 地址(BSSID) |
6字节的MAC地址,如 |
|
|
|
主信道 |
1-14(取决于地区法规) |
|
|
|
次要信道(用于HT40模式) |
0:无次要信道 |
|
|
|
接收信号强度指示 |
-127 到 0(负值) |
|
|
|
认证模式 |
见下方认证模式表格 |
|
|
|
单播加密算法 |
见下方加密算法表格 |
|
|
|
组播加密算法 |
见下方加密算法表格 |
|
|
|
天线编号 |
|
|
|
|
支持802.11b |
0:不支持 |
|
|
|
支持802.11g |
0:不支持 |
|
|
|
支持802.11n(HT) |
0:不支持 |
|
|
|
支持Long Range模式 |
0:不支持 |
|
|
|
支持WPS(WiFi Protected Setup) |
0:不支持 |
|
|
|
支持FTM(Fine Timing Measurement)响应 |
0:不支持 |
|
|
|
支持FTM发起 |
0:不支持 |
|
|
|
保留字段,供未来使用 |
- |
表 48.3.2.5 结构体wifi_ap_record_t字段说明
认证模式详细说明 (wifi_auth_mode_t):
|
枚举值 |
说明 |
安全级别 |
|---|---|---|
|
|
开放网络,无需认证 |
无安全 |
|
|
WEP认证 |
低安全 |
|
|
WPA-PSK认证 |
中等安全 |
|
|
WPA2-PSK认证 |
高安全 |
|
|
WPA/WPA2混合认证 |
高安全 |
|
|
WPA2企业级认证 |
企业级安全 |
|
|
WPA3-PSK认证 |
极高安全 |
|
|
WPA2/WPA3混合认证 |
极高安全 |
|
|
WAPI-PSK认证 |
中国标准 |
|
|
OWE(Opportunistic Wireless Encryption) |
增强开放安全 |
|
|
认证模式最大值 |
- |
表 48.3.2.6 结构体认证模式详细说明
加密算法详细说明 (wifi_cipher_type_t):
|
枚举值 |
说明 |
常用场景 |
|---|---|---|
|
|
无加密 |
开放网络 |
|
|
WEP加密,40位密钥 |
WEP网络 |
|
|
WEP加密,104位密钥 |
WEP网络 |
|
|
TKIP加密 |
WPA网络 |
|
|
CCMP加密(AES) |
WPA2/WPA3网络 |
|
|
TKIP/CCMP混合加密 |
兼容模式 |
|
|
AES-CMAC-128加密 |
WAPI网络 |
|
|
SMS4加密 |
WAPI网络 |
|
|
GCMP加密 |
未来标准 |
|
|
GCMP-256加密 |
未来标准 |
|
|
未知加密类型 |
- |
(4)未包含在代码中但重要的相关函数
|
函数名 |
功能 |
参数 |
返回值 |
说明 |
|---|---|---|---|---|
|
|
停止WiFi |
无 |
|
停止WiFi功能,释放资源 |
|
|
反初始化WiFi驱动 |
无 |
|
清理WiFi驱动占用的资源 |
|
|
连接到AP |
无 |
|
连接到之前配置的AP |
|
|
断开当前连接 |
无 |
|
断开与当前AP的连接 |
|
|
设置WiFi配置 |
|
|
设置STA或AP模式的配置参数 |
表 48.3.2.7 未包含在代码中但重要的相关函数说明
注意事项:
- 资源管理:WiFi 功能会消耗较多内存和电源,不使用时应及时停止和反初始化;
- 事件处理:对于非阻塞扫描,需要通过事件循环处理 WIFI_EVENT_SCAN_DONE事件;
- 配置选项:可以通过 wifi_scan_config_t结构体自定义扫描参数,如:指定扫描特定 SSID、设置主动/被动扫描、限制扫描信道、设置扫描时间。
48.3.2.2 main函数解析
在本章节实验中,我们只关心 main.c 文件内容即可,该文件内容如下:
完整工作流程初始化阶段 ->配置阶段->扫描阶段->清理阶段(代码中有缺失,本次实验补充上),上述源码按这个流程实现,从 wifi_scan 函数开始,该函数首先创建了 event loop 事件回调,即任务事件处理机制。接着,配置 WiFi为 STA模式(设备连接热点模式)并设置相应的参数,然后启动 WiFi。最后,程序会扫描附近的 12 个热点,并在 LCD 上显示热点的名称。此外,读者还可以通过串口查看热点的安全模式等身份认证信息。
/* 存储12个WIFI名称 */
#define DEFAULT_SCAN_LIST_SIZE 12
static const char *TAG = "scan";
/**
* @brief 身份认证模式
* @param authmode :身份验证模式
* @retval 无
*/
static void print_auth_mode(int authmode)
{
switch (authmode) {
case WIFI_AUTH_OPEN:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN");
break;
case WIFI_AUTH_OWE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OWE");
break;
case WIFI_AUTH_WEP:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP");
break;
case WIFI_AUTH_WPA_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_PSK");
break;
case WIFI_AUTH_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_PSK");
break;
case WIFI_AUTH_WPA_WPA2_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_WPA2_PSK");
break;
case WIFI_AUTH_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_ENTERPRISE");
break;
case WIFI_AUTH_WPA3_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_PSK");
break;
case WIFI_AUTH_WPA2_WPA3_PSK:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_PSK");
break;
case WIFI_AUTH_WPA3_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_ENTERPRISE");
break;
case WIFI_AUTH_WPA2_WPA3_ENTERPRISE:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_ENTERPRISE");
break;
case WIFI_AUTH_WPA3_ENT_192:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_ENT_192");
break;
default:
ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN");
break;
}
}
/**
* @brief 打印WIFI密码类型
* @param pairwise_cipher :密码类型
* @param group_cipher :群密码类型
* @retval 无
*/
static void print_cipher_type(int pairwise_cipher, int group_cipher)
{
switch (pairwise_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
case WIFI_CIPHER_TYPE_AES_CMAC128:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_AES_CMAC128");
break;
case WIFI_CIPHER_TYPE_SMS4:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_SMS4");
break;
case WIFI_CIPHER_TYPE_GCMP:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_GCMP");
break;
case WIFI_CIPHER_TYPE_GCMP256:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_GCMP256");
break;
default:
ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
switch (group_cipher) {
case WIFI_CIPHER_TYPE_NONE:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_NONE");
break;
case WIFI_CIPHER_TYPE_WEP40:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP40");
break;
case WIFI_CIPHER_TYPE_WEP104:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP104");
break;
case WIFI_CIPHER_TYPE_TKIP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP");
break;
case WIFI_CIPHER_TYPE_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_CCMP");
break;
case WIFI_CIPHER_TYPE_TKIP_CCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP");
break;
case WIFI_CIPHER_TYPE_SMS4:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_SMS4");
break;
case WIFI_CIPHER_TYPE_GCMP:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_GCMP");
break;
case WIFI_CIPHER_TYPE_GCMP256:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_GCMP256");
break;
default:
ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_UNKNOWN");
break;
}
}
/**
* @brief 将Wi-Fi初始化为sta并设置扫描方法
* @param 无
* @retval 无
*/
void wifi_scan(void)
{
char lcd_buff[100] = {0};
/* 网卡初始化 */
ESP_ERROR_CHECK(esp_netif_init());
/* 创建新的事件循环 */
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* 用户初始化STA模式 */
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
/* wifi配置初始化 */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
uint16_t number = DEFAULT_SCAN_LIST_SIZE;
wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE];
uint16_t ap_count = 0;
memset(ap_info, 0, sizeof(ap_info));
/* 设置WIFI为STA模式 */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
/* 启动WIFI */
ESP_ERROR_CHECK(esp_wifi_start());
/* 开始扫描附件的WIFI */
esp_wifi_scan_start(NULL, true);
/* 获取上次扫描中找到的AP数量 */
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));
/* 获取上次扫描中找到的AP列表 */
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
//停止 WiFi
esp_wifi_stop();
//释放 WiFi 子系统占用的所有资源
esp_wifi_deinit();
ESP_LOGI(TAG, "Total APs scanned = %u", ap_count);
/* 下面是打印附件的WIFI信息 */
for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++)
{
sprintf(lcd_buff, "%s",ap_info[i].ssid);
spilcd_show_string(200, 20 * i, 240, 16, 16, lcd_buff, BLUE);
ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);
ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi);
print_auth_mode(ap_info[i].authmode);
if (ap_info[i].authmode != WIFI_AUTH_WEP)
{
print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher);
}
ESP_LOGI(TAG, "Channel \t\t%d\n", ap_info[i].primary);
}
}
/**
* @brief 程序入口
* @param 无
* @retval 无
*/
void app_main(void)
{
esp_err_t ret;
uint8_t x = 0;
ret = nvs_flash_init(); /* 初始化NVS */
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ESP_ERROR_CHECK(nvs_flash_init());
}
led_init(); /* LED初始化 */
my_spi_init(); /* SPI初始化 */
myiic_init(); /* IIC初始化 */
xl9555_init(); /* 初始化按键 */
spilcd_init(); /* LCD屏初始化 */
spilcd_show_string(10, 80, 240, 32, 32, "ESP32-S3", RED);
spilcd_show_string(10, 120, 240, 24, 24, "WiFi SCAN Test", RED);
spilcd_show_string(10, 150, 240, 16, 16, "ATOM@ALIENTEK", RED);
spilcd_draw_line(190,0,190,239,DARKBLUE);
wifi_scan();
while (1)
{
LED0_TOGGLE();
vTaskDelay(pdMS_TO_TICKS(500));
}
}
48.4 下载验证
程序下载成功后,可以看到 LCD 显示附近热点名称,如下图所示:

图 48.4.1 附近热点名称信息
更多推荐


所有评论(0)