ESP32S3网络编程学习笔记(1)—— Wi-Fi扫描实验

2024-04-08 19:28

本文主要是介绍ESP32S3网络编程学习笔记(1)—— Wi-Fi扫描实验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

(1)如果有嵌入式企业需要招聘湖南区域日常实习生,任何区域的暑假Linux驱动/单片机/RTOS的实习岗位,可C站直接私聊,或者邮件:zhangyixu02@gmail.com,此消息至2025年1月1日前均有效
(2)学习本文之前,建议先学习:ESP32S3网络编程学习笔记(0)—— 计算机网络基础科普

实操

工程目录和CMakeList修改

(1)在main文件夹中创建APP文件夹,并且在APP文件夹中创建wifi.cwifi.h两个文件。

在这里插入图片描述

(2)在main/CMakeLists.txt中修改为如下代码。

idf_component_register(SRC_DIRS "." "./app"INCLUDE_DIRS "." "./app")

在这里插入图片描述

WIFI程序配置

wifi.c

(1)在wifi.c中补充如下代码。

/******************************************************************************************************* @file     led.c* @brief    正点原子ESP32S3开发板的WIFI扫描实验* @author   zhangyixu* @version  1.0.0* @date     2024-04-06* @Copyright (c) 仅供学习,如需商用,请邮件zhangyixu02@gmail.com***************************************************************************************************** @attention* * 个人博客:www.zyxbeyourself.blog.csdn.net* 本人邮件:zhangyixu02@gmail.com***************************************************************************************************** @par Change Logs:* * Date Author Notes* 2024-04-06 zhangyixu 初始版本
*/#include "esp_log.h"
#include "esp_wifi.h"
#include "wifi.h"/* 存储12个WIFI名称 */
#define DEFAULT_SCAN_LIST_SIZE  10static const char *TAG = "WIFI";void wifi_init(void)
{/*-------------- 1、Wi-Fi/LwIP 初始化阶段 --------------*//* 1.1、网卡初始化,LWIP内核初始化 */ESP_ERROR_CHECK(esp_netif_init());/* 1.2、创建新的事件循环 */ESP_ERROR_CHECK(esp_event_loop_create_default());/* 1.3、用户初始化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));/*-------------- 2、Wi-Fi/LwIP 配置阶段 --------------*//* 设置WIFI为STA模式 */ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));/*-------------- 3、Wi-Fi/LwIP 启动阶段 --------------*//* 启动WIFI */ESP_ERROR_CHECK(esp_wifi_start());
}void wifi_scan(void)
{uint16_t number = DEFAULT_SCAN_LIST_SIZE;uint16_t ap_count = 0;wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE] = {0};/* 开始扫描附件的WIFI */esp_wifi_scan_start(NULL, true);/* 获取上次扫描中找到的AP数量 */ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count));ESP_LOGI(TAG, "Total APs scanned = %u", ap_count);/* 获取上次扫描中找到的AP列表 */ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));/* 下面是打印附件的WIFI信息 */for (int i = 0; (i < number) && (i < ap_count); i++){ESP_LOGI(TAG, "NUM \t\t%d", i);ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid);ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi);ESP_LOGI(TAG, "MAC \t\t%02X-%02X-%02X-%02X-%02X-%02X\n", ap_info[i].bssid[0], ap_info[i].bssid[1], ap_info[i].bssid[2], ap_info[i].bssid[3], ap_info[i].bssid[4], ap_info[i].bssid[5]);}
}

wifi.h

(1)在wifi.h中补充如下代码。

/******************************************************************************************************* @file     led.h* @brief    正点原子ESP32S3开发板的WIFI扫描实验* @author   zhangyixu* @version  1.0.0* @date     2024-04-06* @Copyright (c) 仅供学习,如需商用,请邮件zhangyixu02@gmail.com***************************************************************************************************** @attention* * 个人博客:www.zyxbeyourself.blog.csdn.net* 本人邮件:zhangyixu02@gmail.com***************************************************************************************************** @par Change Logs:* Date Author Notes* 2024-04-06 zhangyixu 初始版本
*/#ifndef __WIFI_H__
#define __WIFI_H__#ifdef __cplusplusextern "C" {#endif /* __cplusplus *//*============================ INCLUDES ======================================*//*============================ MACROS ========================================*//*============================ TYPES =========================================*//*============================ GLOBAL VARIABLES ==============================*//*============================ PROTOTYPES ====================================*//*** @brief   将Wi-Fi初始化为sta并设置扫描方法** @param   无** @return  无*/void wifi_init(void);/*** @brief   进行WIFI扫描** @param   无** @return  无*/void wifi_scan(void);#ifdef __cplusplus}#endif /* __cplusplus */#endif /* __WIFI_H__ */

main.c

(1)在main.c中补充如下代码。

/******************************************************************************************************* @file     led.c* @brief    正点原子ESP32S3开发板的WIFI扫描实验* @author   zhangyixu* @version  1.0.0* @date     2024-04-06* @Copyright (c) 仅供学习,如需商用,请邮件zhangyixu02@gmail.com***************************************************************************************************** @attention* * 个人博客:www.zyxbeyourself.blog.csdn.net* 本人邮件:zhangyixu02@gmail.com***************************************************************************************************** @par Change Logs:* * Date Author Notes* 2024-04-06 zhangyixu 初始版本
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"#include "led.h"
#include "nvs_flash.h"
#include "wifi.h"void app_main(void)
{esp_err_t ret;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());ret = nvs_flash_init();}led_init();             /* 初始化LED */wifi_init();wifi_scan();while(1){led_toggle();vTaskDelay(pdMS_TO_TICKS(1000));   /* 延时1s */}
}

运行结果

(1)烧录运行之后,能够一共扫描到多少个Wi-Fi,并且显示扫描到的前10个Wi-Fi名字,信号强度,MAC地址。

在这里插入图片描述

解析

为什么需要初始化NVS

(1)在esp_wifi_init()函数中,将会要使用到NVS相关内容,如果不先将NVS初始化,将无法成功读取到对应的内容,因此会导致初始化失败。
(2)如果我们不想使用NVS,可以打开menuconfig,按照下图关闭下图这个选项。

在这里插入图片描述

Wi-Fi配置初始化流程介绍

(1)在前面的计算机网络科普一文中我解释了APSTA的区别,因为本次实验是Wi-Fi扫描实验,因此我们需要将ESP32S3配置为STA模式。现在我们看看乐鑫科技官方给出来的STA模式配置流程。
(2)下图为截取部分,我们只需要看红框里面的内容即可。这个时候有人会问了,为什么只要看前三步呢?原因很简单,因为我们这里只会进行WIFI扫描,并不会进行连接操作,因此只需要看前三步骤。

在这里插入图片描述

1.初始化阶段

(1)上图,先看1.1步,我们知道需要初始化LwIPLwIP 是一个开源的 TCP/IP 协议栈,专门设计用于嵌入式系统。我们直接调用esp_netif_init()函数就可以将网卡LwIP内核进行初始化。

/* 1.1、网卡初始化,LWIP内核初始化 */
ESP_ERROR_CHECK(esp_netif_init());

(2)创建事件循环有两个函数esp_event_loop_create_default()esp_event_loop_create()函数。esp_event_loop_create_default()其实就是对esp_event_loop_create()进行了一层封装,没有特殊需求,一般调用esp_event_loop_create_default()
这个函数的调用是必要的,因为WIFI扫描实验需要在扫描过程中处理一些事件,例如扫描开始事件,扫描完成事件。如果没有创建事件循环,这些事件将无法被正确处理,导致Wi-Fi扫描实验无法正常进行。

/* 1.2、创建新的事件循环 */
ESP_ERROR_CHECK(esp_event_loop_create_default());

(3.1)前面说了,Wi-Fi扫描实验需要在扫描过程中处理一些事件。而这些事件由esp_netif_create_default_wifi_sta()函数创建。这个事件能够初始化Wi-FiSTA模式,官方的解释是创建有 TCP/IP 堆栈的默认网络接口实例绑定 station

/* 1.3、创建有 TCP/IP 堆栈的默认网络接口实例绑定 station */
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);

(3.2)这一步和上一步同属于1.3步骤,这里是 创建 Wi-Fi 驱动程序任务,并初始化 Wi-Fi 驱动程序。

/* 1.3、创建 Wi-Fi 驱动程序任务,并初始化 Wi-Fi 驱动程序 */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));

(4)这个时候肯定就有同学有疑问了,怎么没有1.4创建应用程序任务呢?原因很简单,我们这里只是进行 Wi-Fi 扫描,并不会进行连接,因此这一步进行省略。

1.2配置阶段

(1)这句话就是将 Wi-Fi配置为STA模式。如果不是在中国,可能还需要调用esp_wifi_set_xxx ()进行更多的配置,例如:协议模式、国家代码、带宽等。

/* 2、设置 Wi-Fi为STA模式 */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

1.3启动阶段

(1)因为我们不需要连接Wi-Fi,因此无需关心 WIFI_EVENT_STA_CONNECTED 事件。只需要调用如下代码即可。

/* 3.1、启动 Wi-Fi 驱动程序 */
ESP_ERROR_CHECK(esp_wifi_start());

关键API介绍

esp_wifi_scan_start()

(1)这个函数表示开始扫描附近的Wi-Fi设备,我们先讲解一下esp_wifi_scan_start()第一个参数的作用。
<1>如果ssid不为NULL,则只扫描SSID与该值相同的AP。否则扫描所有SSIDAP
注:ssid就是Wi-Fi的名字。AP表示热点或者说是Wi-Fi。
<2>如果bssid不为NULL,则只扫描MAC地址与该值相同的AP
注:不了解MAC地址是什么意思的,请看上一篇计算机网络科普。
<3>如果channel为0,则进行全信道扫描。否则只扫描指定的信道。
<4>show_hidden如果为true则扫描时会包括隐藏SSIDAP。否则会忽略隐藏SSIDAP
<5>scan_type如果为WIFI_SCAN_TYPE_ACTIVE,则进行主动扫描。如果是WIFI_SCAN_TYPE_PASSIVE,则进行被动扫描。如下为主动扫描和被动扫描的区别。通常情况下,移动设备会优先使用主动扫描,而固定设备则更倾向于使用被动扫描

  • 主动扫描:客户端主动发送Probe Request帧,询问周围是否有APAP收到Probe Request后,会立即回复Probe Response帧,告知自己的信息。主动扫描速度更快,但会增加网络流量和功耗。
  • 被动扫描:客户端被动地监听AP周期性发送的Beacon帧。AP会定期广播Beacon帧,包含自身的SSID、安全性等信息。被动扫描速度较慢,但不会增加网络流量和功耗。
  • 区别:主动扫描可以发现隐藏SSIDAP,被动扫描无法发现。主动扫描可以更快地发现AP,但会增加功耗。被动扫描不会主动打扰AP,但可能会漏掉某些AP

<6>scan_time用于控制每个信道的扫描时间。对于被动描,scan_time.passive字段指定每个信道的扫描时间。对于主动扫描,每个信道的扫描时间由scan_time.active.minscan_time.active.max决定。
<7>home_chan_dwell_time用于控制在主信道上停留的时间。当进行快速扫描时,会优先在主信道上停留较长时间,以提高扫描效率。
(2)第二个参数就比较容易理解,如果是true那么需要等待Wi-Fi扫描完成之后才会进行esp_wifi_scan_start()下面的函数。如果是false,那么无需等待Wi-Fi扫描完成就会马上执行下面的任务。
(3)如果没有特殊需求,esp_wifi_scan_start()函数第一个参数一般填写NULL默认为主动扫描扫描所有通道扫描所有Wi-Fi忽略隐藏Wi-Fi主动扫描时间为0~120ms主信道上停留的时间为360ms

/*** @brief   扫描所有可用的 AP** @param    config    扫描的配置设置,如果设置为 NULL 将使用默认设置,默认值为 show_hidden:false、scan_type:active、scan_time.active.min:0、scan_time.active.max:120 毫秒、scan_time.passive :360 毫秒*          -block     如果true,此API将阻止调用者直到扫描完成,否则将立即返回** @return   ESP_OK                    配置成功*         - ESP_ERR_WIFI_NOT_INIT     WiFi未由esp_wifi_init初始化*         - ESP_ERR_WIFI_NOT_STARTED  esp_wifi_start未启动WiFi*         - ESP_ERR_WIFI_TIMEOUT      阻塞扫描超时*         - ESP_ERR_WIFI_STATE        调用esp_wifi_scan_start时wifi仍在连接*/
esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *config, bool block);/** @brief 每个通道的活动扫描时间范围 */
typedef struct {uint32_t min;  /**< 每个通道的最小活动扫描时间,单位:毫秒 */uint32_t max;  /**< 每个通道的最大活动扫描时间,单位:毫秒,超过1500ms可能导致工作站与AP断开连接,不建议使用。  */
} wifi_active_scan_time_t;/** @brief 每个通道的主动和被动扫描时间的总和 */
typedef struct {wifi_active_scan_time_t active;  /**< 每个通道的主动扫描时间,单位:毫秒 */uint32_t passive;                /**< 每通道被动扫描时间,单位:毫秒,超过1500ms可能导致工作站与AP断开连接,不建议使用 */
} wifi_scan_time_t;/** @brief SSID扫描参数 */
typedef struct {uint8_t *ssid;               /**< SSID of AP */uint8_t *bssid;              /**< MAC address of AP */uint8_t channel;             /**< 通道,扫描特定的通道 */bool show_hidden;            /**< 使能扫描SSID隐藏的AP */wifi_scan_type_t scan_type;  /**< 扫描类型,主动或被动 */wifi_scan_time_t scan_time;  /**< 每通道扫描时间 */uint8_t home_chan_dwell_time;/**< 在扫描连续通道之间花费的时间*/
} wifi_scan_config_t;

esp_wifi_scan_get_ap_num()

(1)当我们使用esp_wifi_scan_start()函数扫描完Wi-Fi之后,我们可以利用这个函数获取道扫描道的Wi-Fi数量。

/*** @brief   获取上次扫描中找到的Wi-Fi数量** @param    number  存储上次扫描中找到的Wi-Fi数量** @return   ESP_OK                    获取成功*         - ESP_ERR_WIFI_NOT_INIT     Wi-Fi未由esp_wifi_init初始化*         - ESP_ERR_WIFI_NOT_STARTED  esp_wifi_start未启动Wi-Fi*         - ESP_ERR_INVALID_ARG       无效参数*/
esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number);

esp_wifi_scan_get_ap_records()

(1)当我们调用esp_wifi_scan_start()函数

/*** @brief   获取上次扫描中找到的Wi-Fi列表** @param    number      设置ap_records可以容纳的最大Wi-Fi数量,如果number为10,但是扫描到的Wi-Fi只有4个,此时number会变成4。*         - ap_records  保存找到的Wi-Fi** @return   ESP_OK                    获取成功*         - ESP_ERR_WIFI_NOT_INIT     Wi-Fi未由esp_wifi_init初始化*         - ESP_ERR_WIFI_NOT_STARTED  esp_wifi_start未启动Wi-Fi*         - ESP_ERR_INVALID_ARG       无效参数*         - ESP_ERR_NO_MEM            内存不足*/
esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records);

Wi-Fi扫描流程介绍

(1)进行Wi-Fi扫描实验的前提是将ESP32设置为了STA模式,并且成功启动了Wi-Fi,否则无法进行Wi-Fi扫描实验。
(2)我们初始化完ESP32的Wi-Fi之后,就能够直接调用esp_wifi_scan_get_ap_num()函数进行扫描Wi-Fi了,需要注意的是,esp_wifi_scan_get_ap_num()的第二个参数需要配置为true,我们需要扫描完Wi-Fi之后再进行下一步操作。
(3)扫描到的Wi-Fi信息存储在wifi_ap_record_t结构体类型的数组里面,这个对于新手而言只需要关心三个参数:

  • ssid:Wi-Fi名字
  • rssi:一般来说,它是一个负数。RSSI值越大,表示信号强度越强,接近0RSSI值表示非常好的信号强度,而接近于-100RSSI值表示非常弱的信号强度。在某些情况下,如果使用的是其他类型的无线技术或者有特殊配置,RSSI可能会是正数。但对于大多数情况下,尤其是WiFi蓝牙等常见的无线通信,RSSI通常是负数。
  • bssid:Wi-FiMAC地址

参考

(1)乐鑫官方文档:ESP32-S3 Wi-Fi station 一般情况
(2)B站:WIFI扫描 - 乐鑫 ESP32 物联网开发框架 ESP-IDF 开发入门 - 孤独的二进制出品
(3)飞书:【立创·实战派ESP32-C3】开发板文档教程

这篇关于ESP32S3网络编程学习笔记(1)—— Wi-Fi扫描实验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/886319

相关文章

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

SpringBoot使用OkHttp完成高效网络请求详解

《SpringBoot使用OkHttp完成高效网络请求详解》OkHttp是一个高效的HTTP客户端,支持同步和异步请求,且具备自动处理cookie、缓存和连接池等高级功能,下面我们来看看SpringB... 目录一、OkHttp 简介二、在 Spring Boot 中集成 OkHttp三、封装 OkHttp

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

定价129元!支持双频 Wi-Fi 5的华为AX1路由器发布

《定价129元!支持双频Wi-Fi5的华为AX1路由器发布》华为上周推出了其最新的入门级Wi-Fi5路由器——华为路由AX1,建议零售价129元,这款路由器配置如何?详细请看下文介... 华为 Wi-Fi 5 路由 AX1 已正式开售,新品支持双频 1200 兆、配有四个千兆网口、提供可视化智能诊断功能,建