ESP32 之 ESP-IDF 教学(十一)WiFi篇—— WiFi两种模式
本文章 来自原创专栏《ESP32教学专栏 (基于ESP-IDF)》,讲解如何使用 ESP-IDF 构建 ESP32 程序,发布文章并会持续为已发布文章添加新内容! 每篇文章都经过了精打细磨!
↓↓↓通过下方对话框进入专栏目录页↓↓↓
CSDN 请求进入目录 _ O x
是否进入ESP32教学导航(基于ESP-IDF)?
确定
文章目录
- 一、ESP32 WIFI介绍
- 二、WiFi 的启动(STA 及 AP 模式)
- 1. WiFi STA 模式(连接到其他设备的热点)
- (1) 步骤及API简介
- (2) 分步讲解
- (3) 完整代码示例
- 2. WiFi AP 模式(ESP32作为热点供其他设备链接)
- 三、STA模式下扫描外部WiFi
- 1. 步骤
- 2. 代码示例
一、ESP32 WIFI介绍
Wi-Fi 库支持配置及监控 ESP32 Wi-Fi 连网功能。
支持配置:
基站模式(即 STA 模式或 Wi-Fi 客户端模式),此时 ESP32 连接到接入点 (AP)。
AP 模式(即 Soft-AP 模式或接入点模式),此时基站连接到 ESP32。
AP-STA 共存模式(ESP32 既是接入点,同时又作为基站连接到另外一个接入点)。
上述模式的各种安全模式(WPA、WPA2 及 WEP 等)。
扫描接入点(包括主动扫描及被动扫描)。
使用混杂模式监控 IEEE802.11 Wi-Fi 数据包。
二、WiFi 的启动(STA 及 AP 模式)
1. WiFi STA 模式(连接到其他设备的热点)
(1) 步骤及API简介
① 初始化nvs_flash
② 初始化esp_netif
③ 创建事件循环event_loop
—— event_loop
是esp32库的一种事件处理模式,中文曰“事件循环”
④ 初始化、配置WiFi并启动
⑤ 事件处理(使用第③步创建的事件循环)
(2) 分步讲解
① 初始化nvs_flash
#include <nvs_flash.h>/*** @brief 用于初始化nvs*/
void init_nvs() {/*尝试初始化一次nvs_flash*/esp_err_t err = nvs_flash_init();if(err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND){/*第一次初始化失败, 检查错误, 处理错误, 重新初始化*/nvs_flash_erase();err = nvs_flash_init();}ESP_ERROR_CHECK(err);
}
② 初始化event_loop
#include "esp_event.h"esp_event_loop_create_default();esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,想要用于处理事件的函数, NULL, &wifi_handler);
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,想要用于处理时间的函数, NULL, &ip_handler));
代码解析:
- ①
esp_event_loop_create_default();
函数用于创建一个默认的事件循环(同一个esp32程序中可以有多个event_loop
,这里使用默认的事件循环) - ②
esp_event_handler_instance_register()
函数解析见下:
函数名 |
esp_event_handler_instance_register()
|
---|---|
函数原型 | esp_err_t esp_event_handler_instance_register(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg, esp_event_handler_instance_t *instance) |
含义 | 将事件处理程序的实例注册到默认循环。 |
返回值 | esp_err_t |
参数 |
event_base类型为:esp_event_base_t ;表示 事件基,代表事件的大类(如WiFi事件,IP事件等)event_id类型为: int32_t ;表示事件ID,即事件基下的一个具体事件(如WiFi连接丢失,IP成功获取)event_handler类型为: esp_event_handler_t ;表示一个handler函数(模板请见第⑤步)*event_handler_arg类型为: void ;表示需要传递给handler函数的参数*instance类型为: esp_event_handler_instance_t 指针;**[输出]**表示此函数注册的事件实例对象,用于生命周期管理(如删除unrigister 这个事件handler)
|
③ 初始化esp_netif
#include "esp_netif.h"esp_netif_t *pEsp_wifi_netif;esp_netif_init();/*创建wifi sta模式的默认netif, 返回一个指针*/
pEsp_wifi_netif = esp_netif_create_default_wifi_sta();/* (非必须) 这行代码是修改ESP32的主机名, 即WiFi设备名, 连接其他WiFi时显示的名称 */
esp_netif_set_hostname(esp_wifi_netif, "Augtons");// 不建议使用汉字
上述代码第 6 行函数esp_netif_create_default_wifi_sta()
是必要的,只不过函数返回值可以在不需要的时候忽略(本文我们借助这个创建得到的esp_netif
对象来修改了主机名为Augtons
,因此保留了这个返回值)
④ 初始化、配置WiFi并启动
注意:下文的代码实例只展示了最简单的wifi连接代码,实际上第4行配置的结构体下的sta还有很多成员,这里不再细讲
#include "driver/wifi.h"
/* 第一步, WiFi初始化 */
/*这个宏 WIFI_INIT_CONFIG_DEFAULT() 可以初始化一 个wifi_init_config(wifi初始化配置)结构体为默认值
*/
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&wifi_init_config);/* 第二步, WiFi配置 */
wifi_config_t wifi_config = {.sta = {.ssid = "WiFi_SSID", // wifi名(ssid).password = "password",// wifi密码}
};
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_wifi_set_mode(WIFI_MODE_STA); // 设置工作模式/* 第三步, 启动WiFi */
esp_wifi_start();
⑤ 事件处理(使用第③步创建的事件循环)
这里这个函数就是第 ③ 步注册的事件循环handler函数。
handler函数模板如下:
void xxx(void *arg, esp_event_base_t eventBase, int32_t eventID, void *eventData) {/*函数参数一:arg。表示传递给handler函数的参数,在第三步register函数里声明函数参数二,eventBase,表示事件基,详见第三步函数esp_event_handler_instance_register()解析函数参数三:eventID,表示事件ID,详见第三步函数esp_event_handler_instance_register()解析函数参数四,表示传递给这个事件的数据。例如:例如事件基 IP_EVENT 下的 IP_EVENT_STA_GOT_IP 事件会把获取到的IP地址传递过来,见下方示例。
*/
}
下面为WiFi事件处理的一个简单的handler
函数。
处理的事件:
事件基 | 事件 | 含义 |
---|---|---|
WiFi_EVENT | WIFI_EVENT_STA_START | WiFi启动成功 |
WiFi_EVENT | WIFI_EVENT_STA_DISCONNECTED | WiFi连接断开/连接失败 |
IP_EVENT | IP_EVENT_STA_GOT_IP | WiFi连接成功并获取到IP地址 |
下面给出一个示例及其代码:
当WIFI_EVENT_STA_START
发生即WiFi启动成功之后,我们就连接WiFi。
当WIFI_EVENT_STA_DISCONNECT
发生即WiFi断开连接/连接失败后,我们就尝试重新连接
当 IP_EVENT_STA_GOT_IP
发生即WiFi连接成功并获取到IP地址之后,我们就在屏幕上打印出获取到的IP地址
printf("connected, got ip: "IPSTR"\n", IP2STR(&ip->ip_info.ip));
然后做其他的事情
代码:
void wifi_event_handler(void *arg, esp_event_base_t eventBase, int32_t eventID, void *eventData){ip_event_got_ip_t *ip = eventData;if(eventBase == WIFI_EVENT){switch (eventID) {default: break;case WIFI_EVENT_STA_START:printf("WIFI_STARTED!\n");esp_wifi_connect(); break;case WIFI_EVENT_STA_DISCONNECTED:ESP_LOGI("user", "Connect failed\n"); esp_wifi_connect(); break;}}else if(eventBase == IP_EVENT){if(eventID == IP_EVENT_STA_GOT_IP){printf("connected, got ip: "IPSTR"\n", IP2STR(&ip->ip_info.ip));//dosomething//例如:使用任务通知xTaskNotifyGive(任务句柄);来唤醒一个任务等}}
}
(3) 完整代码示例
#include <nvs_flash.h>
#include <esp_event.h>
#include <esp_wifi.h>
#include <esp_log.h>
#include <esp_netif.h>
#include <esp_netif_ip_addr.h>/*** @brief 用于初始化nvs*/
void init_nvs() {esp_err_t err = nvs_flash_init();if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());err = nvs_flash_init();}ESP_ERROR_CHECK(err);
}/*** @brief WiFi 的事件循环Handler* @param arg * @param event_base * @param event_id * @param event_data */
void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();}if(event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;ESP_LOGI("TEST_ESP32", "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));}
}void app_main(void)
{init_nvs();esp_netif_init();esp_event_loop_create_default();esp_netif_create_default_wifi_sta();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&cfg);// 注:下方的cfg_sta也可以写成这样// wifi_config_t wifi_config = {// .sta = {// .ssid = "SSID",// .password = "密码",// }// };wifi_sta_config_t cfg_sta = {.ssid = "改成你WiFi ssid",.password = "改成WiFi密码",};// 而直接将wifi_sta_config_t(或指针)转为wifi_config_t(或指针)是GCC的拓展语法,如下esp_wifi_set_config(WIFI_IF_STA, (wifi_config_t *) &cfg_sta);esp_wifi_set_mode(WIFI_MODE_STA);esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL, NULL);esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL, NULL);esp_wifi_start();}
2. WiFi AP 模式(ESP32作为热点供其他设备链接)
AP模式的WiFi与STA模式极其类似:
不同的是,在进行WiFi配置时wifi_config_t
结构体用法会改变。
wifi_config_t wifi_config = {.ap = {.ssid = "your_ssid",.ssid_len = strlen("your_ssid"),.channel = EXAMPLE_ESP_WIFI_CHANNEL,.password = "password",.max_connection = EXAMPLE_MAX_STA_CONN,.authmode = WIFI_AUTH_WPA_WPA2_PSK},
};
剩余的代码,读者可以参考 ESP-IDF
的官方示例
三、STA模式下扫描外部WiFi
1. 步骤
在上一步WiFi启动之后,我们就能进行扫描附近的WiFi了
这里需要了解 3 个相关的API函数
esp_wifi_scan_start()
esp_wifi_scan_get_ap_num()
esp_wifi_scan_get_ap_records()
函数名 |
esp_wifi_scan_start()
|
---|---|
函数原型 | esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *config, bool block) |
含义 | 开始扫描WiFi,扫描附近所有可用的AP。 |
返回值 | esp_err_t |
参数 |
*config类型为:const wifi_scan_config_t 指针;表示一个用于配置扫描参数的结构体的指针【此参数可为NULL】NULL表示扫描全部WiFi block类型为: |
函数名 |
esp_wifi_scan_get_ap_num()
|
---|---|
函数原型 | esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number) |
含义 | 获取扫描到的AP个数 |
返回值 | esp_err_t |
参数 |
*number类型为:uint16_t 指针;表示用于储存扫描个数的变量的指针
|
函数名 |
esp_wifi_scan_get_ap_records()
|
---|---|
函数原型 | esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records) |
含义 | 获取扫描到的AP |
返回值 | esp_err_t |
参数 |
*number类型为:uint16_t ;【既可输入又可输出】输入读取扫描记录的期望数量,例如预先分配的数组长度。输出实际扫描到的AP个数*ap_records类型为: wifi_ap_record_t 指针;表示存放扫描结果的数组
|
2. 代码示例
// 【注意】:wifi_scan_handle变量是一个Task的句柄,
// 可通过xTaskCreate在创建任务时获得
// 也可通过xTaskGetCurrentTaskHandle()等FreeRTOS API获取
TaskHandle_t wifi_scan_handle;
// 上边的这个变量储存了创建的wifi扫描任务句柄
// 对应下边示例的函数 task_wifi_scan(void *arg)void wifi_event_handler(void *arg, esp_event_base_t eventBase, int32_t eventID, void *eventData){...if(eventBase == WIFI_EVENT){if(eventID == WIFI_EVENT_STA_START){// printf("WiFi 已启动");// 向WiFi扫描任务发送任务通知,通知WiFi启动成功,可以开始扫描了 (这里的任务通知相当于一个二值信号量)xTaskNotifyGive(wifi_scan_handle); }}
}void task_wifi_scan(void *arg){// 等待来自event_handler发来的任务通知,在等到通知之前,此任务进入阻塞状态。知道接收到WiFi启动成功的通知之后才开始往下执行。ulTaskNotifyTake(pdTRUE, portMAX_DELAY);uint16_t num;wifi_ap_record_t records[8];esp_wifi_scan_start(NULL, true);esp_wifi_scan_get_ap_num(&num);if(num > 8){num = 8; // if 的目的是如果扫描到了8个以上的WiFi,则只保留前8个}esp_wifi_scan_get_ap_records(&num, records);if(num > 8){num = 8; // if 的目的同上}// 这个for循环是用来将RSSI信号强度,转换成信号等级。// 如 rssi_level == 5 时,表示WiFi满格for(int i = 0; i < num; i++){uint8_t rssi_level = 0;switch (records[i].rssi) {case -100 ... -88:rssi_level = 1; break;case -87 ... -77:rssi_level = 2; break;case -76 ... -66:rssi_level = 3; break;case -65 ... -55:rssi_level = 4; break;default:if(records[i].rssi < -100){rssi_level = 0;}else{rssi_level = 5;}break;}// 逐条打印扫描到的WiFiprintf("—————【第 %2d 个WiFi】———————\n", i+1);printf("WiFi名称: %s\n", records[i].ssid);printf("信号强度: %d格\n", rssi_level);printf("WiFi: 安全类型: %d\n\n", records[i].authmode);}vTaskDelete(NULL);
}
运行结果图:
ESP32 之 ESP-IDF 教学(十一)WiFi篇—— WiFi两种模式相关推荐
- Wifi WDS的两种模式
一.什么是WDS WDS是Wireless Distribution System,即无线网络部署延展系统的简称,是指用多个无线网络相互联结的方式构成一个整体的无线网络.简单地说,WDS就是利用两个( ...
- 关于Wifi WDS的两种模式浅谈
转自:微点阅读 https://www.weidianyuedu.com 一.什么是WDS WDS是Wireless Distribution System,即无线网络部署延展系统的简称,是指用多个 ...
- 浅谈 Wifi WDS的两种模式
转载自品略图书馆 http://www.pinlue.com/article/2018/09/1721/187259292010.html 一.什么是WDS WDS是Wireless Distribu ...
- ESP32-C3入门教程 WiFi篇③——WiFi SoftAP 模式开启AP热点
文章目录 一.前言 二.WiFi模式 三.快速运行 四.运行效果 五.程序流程 5.1 主程序 5.2 注册事件回调函数 六.关键函数 6.1 将事件回调函数注册到特定循环 6.2 设置 ESP32 ...
- 5 FPGA时序约束理论篇之两种时序例外
两种时序例外 多周期路径 上面我们讲的是时钟周期约束,默认按照单周期关系来分析数据路径,即数据的发起沿和捕获沿是最邻近的一对时钟沿.如下图所示. 默认情况下,保持时间的检查是以建立时间的检查为 ...
- 查看 WiFi 密码的两种方法
查看 WiFi 密码的两种方法 1. 概述 2. 在控制面板中查看 WiFi 密码 3. 使用 CMD 查看 WiFi 密码 结束语 1. 概述 突然忘记 WiFi 密码怎么办? 想连上某个使用过的 ...
- 计算机辅助教学常用的教学模式,计算机辅助教学的“两种模式”
计算机辅助教学的"两种模式" 计算机辅助教学是在计算机辅助下进行的各种教学活动,以对话方式与学生讨论教学内容.安排教学进程.进行教学训练的方法与技术.以下是小编帮大家整理的计算机辅 ...
- ESP32-C3入门教程 WiFi篇⑤——WiFi Smart Config 智能配网(基于AirKiss)
文章目录 一.前言 二.代码修改 三.运行效果 一.前言 本文基于VS Code IDE进行编程.编译.下载.运行等操作 基础入门章节请查阅:ESP32-C3入门教程 基础篇①--基于VS Code构 ...
- javaweb学习总结(二十一):JavaWeb的两种开发模式
SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...
- 【转】Win10系统创建WiFi热点的两种方法
现在电脑和wifi已经成为很多人生活中不可缺少的一部分,上网过程只有连接WiFi才可以上网.使用windows10系统开启WiFi热点都是提示没有找到支持的无线网卡.不管你是驱动更新,重装,还是怎么操 ...
最新文章
- idea java cpu100_intellij idea cpu占用率太大太满 运行速度太慢 使了五个解决方法最终成功...
- ASP.NET Core SameSite 设置引起 Cookie 在 QQ 浏览器中不起作用
- 关于.net的垃圾回收和大对象处理_标记
- java 字典 引用_java中数据字典的使用
- 项目管理学习总结(14)——优秀技术Leader应该具备什么哪些方面的能力
- 让 ASP.NET JS验证和服务端的 双验证 更简单
- poj 2318 TOYS amp; poj 2398 Toy Storage (叉积)
- WebSocket+HTML5实现在线聊天室
- rtmp中flv和flv文件的区别
- python3.7安装Numpy库
- 双人五子棋(C++游戏)游戏代码在最底下
- 毕业设计源码——旅游打卡小程序
- 知道PDF密码,想要移除如何操作?
- python绘图画猫咪_使用Python的turtle画小猫咪
- 计算机查看正在运行的程序,win7系统查看当前正在运行程序状态的方法
- 如何正确跟踪广告转化数据,优化广告投放效果?
- 电子书 UNIX环境高级编程(第3版).pdf
- 腾讯词向量下载链接(Tencent_AILab_ChineseEmbedding.txt)
- 计算机休眠唤醒后分辨率变小了,WIN10休眠唤醒后,所有的窗口都跑到了左上角,如何解决?...
- “北上广曹”商标被抢注,商标过期后企业可以抢注吗?
热门文章
- 利用.bat批处理命令进行文件复制粘贴备份
- 公式编辑器MathType中矩阵模板的使用技巧
- 联想拯救者Y7000P的一些功能键
- 联想Y7000安装双系统(Windows10与Ubuntu16.04)
- 计算机科学论文生成器,数学论文生成器:从此一天一篇不再愁
- html字体加载太慢,字体加载CSS @font-face性能优化的常用策略
- zepto部分报错及解决方案
- IAR FOR STM8 简单使用教程
- SAP 标准TCODE ME2L ME2N VL31等设置清单范围默认值(ME2L默认ALV显示)
- funcode拍飞虫C语言报告,【逻辑游戏面试题】面试问题:funcode… - 看准网