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】开发板文档教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/598351.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS 应用内网络请求设置代理

主要通过URLSessionConfiguration 的connectionProxyDictionary 属性 为了方便其他同学使用&#xff0c;我们可以通过界面来进行设定&#xff08;是否开启代理、服务端、端口&#xff09;&#xff0c;从而达到类似系统上的设定 具体链接参考&#xff1a;为 iOS 网络请求设置代理…

5. 4 二重循环将二维数组的某列、某矩形转大写

5. 4 二重循环将二维数组的某列、某矩形转大写 1. 把每一行的b都变成大写 assume cs:codesg,ds:data,ss:stack data segmeNTstr db aaaaabbbbbcccccdb aaaaabbbbbcccccdb aaaaabbbbbcccccdb aaaaabbbbbccccc,$ data endsstack segmentdb 10 dup(0) stack endscodesg SEgments…

Scaling Law 又一次性感了吗?

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 事件&#xff1a; Sora 的出现被认为是 Scaling Law 的又一次成功&#xff0c;这也引起了社区…

【C语言】函数递归编程题

目录 题目一&#xff1a; 题目二&#xff1a; 题目三&#xff1a; 题目四&#xff1a; 总结 题目一&#xff1a; 题目&#xff1a;接受一个整型值&#xff08;无符号&#xff09;&#xff0c;按照顺序打印它的每一位。&#xff08;递归完成&#xff09; 列如&#xff1a; …

uniapp:聊天消息列表(好友列表+私人单聊)支持App、H5、小程序

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 文章简介&#xff08;效果图展示&#xff…

linux安全加固

1.登录账号加固 /etc/login.defs 创建⽤户的默认设置⽂件 grep -Ev "^#|^$" /etc/login.defs /etc/login.defs ⽂件⽤于在创建⽤户时&#xff0c;对⽤户的⼀些基本属性做默认设置&#xff0c;例如指定⽤户 UID 和 GID 的范围&#xff0c;⽤户的过期时间&#xff0…

豆瓣9.7,这部Java神作第3版重磅上市!

Java 程序员们开年就有重磅好消息&#xff0c;《Effective Java 中文版&#xff08;原书第 3 版&#xff09;》要上市啦&#xff01; 该书的第1版出版于 2001 年&#xff0c;当时就在业界流传开来&#xff0c;受到广泛赞誉。时至今日&#xff0c;已热销近20年&#xff0c;本书…

如何搭建APP分发平台分发平台搭建教程

搭建一个APP分发平台可以帮助开发者更好地分发和管理他们的应用程序。下面是一个简要的教程&#xff0c;介绍如何搭建一个APP分发平台。 1.确定需求和功能&#xff1a;首先&#xff0c;确定你的APP分发平台的需求和功能。考虑以下几个方面&#xff1a; 用户注册和登录&#xff…

【图论】有向无环图中一个节点的所有祖先 - 邻接表(DFS)

文章目录 题目&#xff1a;有向无环图中一个节点的所有祖先题目描述代码与解题思路 题目&#xff1a;有向无环图中一个节点的所有祖先 2192. 有向无环图中一个节点的所有祖先 题目描述 代码与解题思路 func getAncestors(n int, edges [][]int) [][]int {g : make([][]int, …

题目:【序列中删除指定数字】【变种水仙花数】【数组串联】【交换奇偶位】【offsetof宏的实现】

题目一:序列中删除指定数字 #include <stdio.h>int main(){int a0;int arr[50]{0};int c0;scanf("%d",&a);for(int i0;i<a;i){scanf("%d",&arr[i]);//输入a个值}scanf("%d",&c);//输入要删除的数据int i0;int j0;for(i0;i&…

【Entity Framework】EF配置文件设置详解

【Entity Framework】EF配置文件设置详解 文章目录 【Entity Framework】EF配置文件设置详解一、概述二、实体框架配置部分三、连接字符串四、EF数据库提供程序五、EF侦听器六、将数据库操作记录到文件中七、Code First默认连接工厂八、数据库初始值设定项 一、概述 EF实体框架…

力扣热题100_链表_138_随机链表的复制

文章目录 题目链接解题思路解题代码 题目链接 138. 随机链表的复制 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&a…