本文章 来自原创专栏《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类型为:bool;表示是否要阻塞。为true表示此函数将阻塞直到扫描完成。为false表示此函数将要立即返回(扫描结束通过事件循环来传递结果)

函数名 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两种模式相关推荐

  1. Wifi WDS的两种模式

    一.什么是WDS WDS是Wireless Distribution System,即无线网络部署延展系统的简称,是指用多个无线网络相互联结的方式构成一个整体的无线网络.简单地说,WDS就是利用两个( ...

  2. 关于Wifi WDS的两种模式浅谈

    转自:微点阅读  https://www.weidianyuedu.com 一.什么是WDS WDS是Wireless Distribution System,即无线网络部署延展系统的简称,是指用多个 ...

  3. 浅谈 Wifi WDS的两种模式

    转载自品略图书馆 http://www.pinlue.com/article/2018/09/1721/187259292010.html 一.什么是WDS WDS是Wireless Distribu ...

  4. ESP32-C3入门教程 WiFi篇③——WiFi SoftAP 模式开启AP热点

    文章目录 一.前言 二.WiFi模式 三.快速运行 四.运行效果 五.程序流程 5.1 主程序 5.2 注册事件回调函数 六.关键函数 6.1 将事件回调函数注册到特定循环 6.2 设置 ESP32 ...

  5. 5 FPGA时序约束理论篇之两种时序例外

    两种时序例外 多周期路径   上面我们讲的是时钟周期约束,默认按照单周期关系来分析数据路径,即数据的发起沿和捕获沿是最邻近的一对时钟沿.如下图所示.   默认情况下,保持时间的检查是以建立时间的检查为 ...

  6. 查看 WiFi 密码的两种方法

    查看 WiFi 密码的两种方法 1. 概述 2. 在控制面板中查看 WiFi 密码 3. 使用 CMD 查看 WiFi 密码 结束语 1. 概述 突然忘记 WiFi 密码怎么办? 想连上某个使用过的 ...

  7. 计算机辅助教学常用的教学模式,计算机辅助教学的“两种模式”

    计算机辅助教学的"两种模式" 计算机辅助教学是在计算机辅助下进行的各种教学活动,以对话方式与学生讨论教学内容.安排教学进程.进行教学训练的方法与技术.以下是小编帮大家整理的计算机辅 ...

  8. ESP32-C3入门教程 WiFi篇⑤——WiFi Smart Config 智能配网(基于AirKiss)

    文章目录 一.前言 二.代码修改 三.运行效果 一.前言 本文基于VS Code IDE进行编程.编译.下载.运行等操作 基础入门章节请查阅:ESP32-C3入门教程 基础篇①--基于VS Code构 ...

  9. javaweb学习总结(二十一):JavaWeb的两种开发模式

    SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...

  10. 【转】Win10系统创建WiFi热点的两种方法

    现在电脑和wifi已经成为很多人生活中不可缺少的一部分,上网过程只有连接WiFi才可以上网.使用windows10系统开启WiFi热点都是提示没有找到支持的无线网卡.不管你是驱动更新,重装,还是怎么操 ...

最新文章

  1. idea java cpu100_intellij idea cpu占用率太大太满 运行速度太慢 使了五个解决方法最终成功...
  2. ASP.NET Core SameSite 设置引起 Cookie 在 QQ 浏览器中不起作用
  3. 关于.net的垃圾回收和大对象处理_标记
  4. java 字典 引用_java中数据字典的使用
  5. 项目管理学习总结(14)——优秀技术Leader应该具备什么哪些方面的能力
  6. 让 ASP.NET JS验证和服务端的 双验证 更简单
  7. poj 2318 TOYS amp; poj 2398 Toy Storage (叉积)
  8. WebSocket+HTML5实现在线聊天室
  9. rtmp中flv和flv文件的区别
  10. python3.7安装Numpy库
  11. 双人五子棋(C++游戏)游戏代码在最底下
  12. 毕业设计源码——旅游打卡小程序
  13. 知道PDF密码,想要移除如何操作?
  14. python绘图画猫咪_使用Python的turtle画小猫咪
  15. 计算机查看正在运行的程序,win7系统查看当前正在运行程序状态的方法
  16. 如何正确跟踪广告转化数据,优化广告投放效果?
  17. 电子书 UNIX环境高级编程(第3版).pdf
  18. 腾讯词向量下载链接(Tencent_AILab_ChineseEmbedding.txt)
  19. 计算机休眠唤醒后分辨率变小了,WIN10休眠唤醒后,所有的窗口都跑到了左上角,如何解决?...
  20. “北上广曹”商标被抢注,商标过期后企业可以抢注吗?

热门文章

  1. 利用.bat批处理命令进行文件复制粘贴备份
  2. 公式编辑器MathType中矩阵模板的使用技巧
  3. 联想拯救者Y7000P的一些功能键
  4. 联想Y7000安装双系统(Windows10与Ubuntu16.04)
  5. 计算机科学论文生成器,数学论文生成器:从此一天一篇不再愁
  6. html字体加载太慢,字体加载CSS @font-face性能优化的常用策略
  7. zepto部分报错及解决方案
  8. IAR FOR STM8 简单使用教程
  9. SAP 标准TCODE ME2L ME2N VL31等设置清单范围默认值(ME2L默认ALV显示)
  10. funcode拍飞虫C语言报告,【逻辑游戏面试题】面试问题:funcode… - 看准网