【快速上手ESP32(基于ESP-IDFVSCode)】10-事件循环WiFi

事件循环

本来这篇文章是只写WiFi的,但是写的时候才发现离不开事件循环,因此再多添一点内容在WiFi前面。

事件循环简单来说就是一个(循)环,我们可以在这个环上绑上一些事件,我们也可以监听这个环,当环上发生了事件,那么监听了对应事件的的处理函数就会执行,可以参考FreeRTOS的事件组。

使用事件循环

#include "esp_event.h"

创建&删除事件循环

esp_err_t esp_event_loop_create(const esp_event_loop_args_t *event_loop_args, esp_event_loop_handle_t *event_loop)

参数二是传出参数,把事件循环的句柄传出来,我们主要看看第一个参数的结构体。

事件循环队列的大小,也就是这个事件循环可以绑多少个事件。

事件名字随意。

优先级和栈大小根据实际情况而定。

最后一个ID实际上BaseType_t就是给一个整型。

esp_err_t esp_event_loop_delete_default(void)

删除只需要传入句柄。

注册&注销事件

esp_err_t esp_event_handler_register_with(esp_event_loop_handle_ t event_loop, esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg)

参数一传入事件循环句柄。

参数二是事件基ID,听起来像是给一个整数,但它实际上是个字符串。

剩下的参数就是事件ID,处理函数和给处理函数的参数。

然后处理函数是固定的格式,无返回值和固定的参数类型。每个参数是什么意思看名字应该就都能懂。

void fun(void* handler_arg, esp_event_base_t base, int32_t id, void* event_data){// 事件处理程序逻辑
}

注销事件使用下面的函数。

esp_err_t esp_event_handler_unregister_with( esp_event_loop_handle_t event_loop、 esp_event_base_t event_base、 int32_t event_id、 esp_event_handler_t event_handler)

两个ID都需要对应上之前注册过的事件。

发布事件

esp_err_t esp_event_post_to ( esp_event_loop_handle_t event_loop , esp_event_base_t event_base , int32_t event_id , const void * event_data , size_t event_data_size , TickType_t ticks_to_wait )

参数一传入事件循环句柄。

参数二是字符串的那个ID。

参数三是整数的ID,要两个ID都符合才会触发对应的事件处理函数。

参数四是传递给处理程序的参数,参数五是传递的参数的大小。

最后一个是阻塞时间。

发布事件时候,之前绑定了的对应的事件处理函数就会触发。

测试

#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "nvs_flash.h"void fun(void *handler_arg, esp_event_base_t base, int32_t id, void *event_data){// 事件处理程序逻辑printf("fun is run\r\n");
}void app_main(void){esp_event_loop_args_t eela = {.queue_size = 10,.task_core_id = 1,.task_name = "test",.task_priority = 1,.task_stack_size = 1024};esp_event_loop_handle_t eelh;esp_event_loop_create(&eela, &eelh); // 创建事件循环esp_event_handler_register_with(eelh, "test", 1, fun, NULL); // 绑定事件while (1){esp_event_post_to(eelh, "test", 1, NULL, 1024, 100 / portTICK_PERIOD_MS); // 发送事件vTaskDelay(1000 / portTICK_PERIOD_MS);printf("过了1秒钟\r\n");}
}

可以看到上面的代码使得“test”的1号事件每隔一秒触发了一次,事件循环正常地运行着。

那么除了上面介绍的函数,还有一些其他的函数。

我们上面介绍的是左边一列的函数,而右边一列的其实差不多,函数名字也都很像。

差别就在于默认事件循环为用户提供了一套简单的事件处理机制,适用于大多数常规应用。而用户事件循环则为用户提供了更多的控制权和定制化能力,适用于需要精细管理事件或处理特殊事件的场景。

而我们接下来的WiFI需要用到的是默认事件循环,因为WiFI事件已经放到默认事件循环里了。

ESP32中的WiFi

官方手册里介绍的WiFi,专业名词看不太懂,不过问题不大,我们能用就行。

连接WiFi

#include "esp_wifi.h"

通常我们就是连接WiFI也就是STA模式,AP模式是自己开一个热点,不过这个用的比较少,因此我们看看STA的流程。

我们按照顺序来,首先是初始化阶段。

不过在这之前有一个问题在这里没有提到,那就是要先对nvs初始化,否则是使用不了WiFI的。

    nvs_flash_init();

初始化底层TCP/IP堆栈

esp_err_t esp_netif_init(void)

我们就调用一次,不用参数。

创建默认事件循环

esp_err_t esp_event_loop_create_default(void)

虽然上面编程指南中用的是创建用户事件循环,但是我找了不少资料都说创建默认事件循环。

那么我们就使用默认事件循环,也比较省事,没有需要配置的参数。

既然我们创建了事件循环,那么还需要的就是绑定事件了。

我们创建的默认事件循环,那么绑定事件的函数也需要和默认事件循环是配套的,可以参考上面的一个表格。

绑定WiFI事件

esp_err_t esp_event_handler_register ( esp_event_base_t event_base , int32_t event_id , esp_event_handler_t event_handler , void * event_handler_arg ) 

那么我们应该如何绑定WiFI事件呢。

参考我下面的代码。

esp_event_handler_register(WIFI_EVENT,ESP_EVENT_ANY_ID,fun,NULL);

在文章的开始就介绍了事件循环,那么上面这个例子大家应该能懂什么意思,要解释的就是前两个参数了,WIFI_EVENTESP_EVENT_ANY_ID,这两个宏的含义分别是WiFI事件和任意ID。

所以上面例子的意思就是我们绑定了WIFI的所有事件,也就是WiFi有任何风吹草动都会触发我们绑定的处理函数fun(这边名字随意,符合要求即可)。

创建STA

esp_netif_t *esp_netif_create_default_wifi_sta(void)

也是不用参数,但是会返回一个esp_netif_t类型的指针。

初始化WiFI

esp_err_t esp_wifi_init(const wifi_init_config_t *config)

需要传入一个参数,这个结构体相当复杂。

如果一个个去配置的话会相当麻烦,因此我们有一个宏定义可以帮我们都配置一个默认项,那就是WIFI_INIT_CONFIG_DEFAULT()

所以我们只需要像下面这样使用就可以啦。

    wifi_init_config_t wct = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&wct);

接下来我们进入到第二部分,WiFI配置。

设置WiFI模式

esp_err_t esp_wifi_set_mode(wifi_mode_t mode)

可以选择的模式有下面这些。

我们常用的就是AP和SAT以及APSTA,APSTA就是即可以是AP也可以是STA,跟我们手机一样,即可以连接WiFi也可以开热点。

配置STA

esp_err_t esp_wifi_set_config(wifi_interface_t interface, wifi_config_t *conf)

需要两个参数,第一个是WiFI接口,我们可以直接使用宏定义WIFI_IF_STA

第二个参数是union,也就是我们配置AP模式和配置STA模式还不一样。

我们直接看看STA怎么配置。

光看上面的表格我们就知道要怎么配置了,一般情况我们就配置要连接的WiFi名称和密码就够了,其他都用默认的就行。

配置完就可以启动了。

启动WiFi

esp_err_t esp_wifi_start(void)

连接WiFi

esp_err_t esp_wifi_connect(void)

现在有个问题,那就是我们需要把握住连接的时机,因为我们调用一次只会尝试连接WiFI一次,而有可能我们在调用的时候上面启动WiFI的流程还没走完。

因此我们可以在WiFi事件的处理函数里尝试连接。

如果触发事件的是WiFI事件,并且ID号和WIFI_EVENT_STA_START这个宏一致,那么我们就可以尝试连接了,因为这意味着STA已经启动了。

一切准备就绪,我们就可以开始连接了。

仅仅连接WIFI的完整示例代码

#include <stdio.h>
#include <string.h>
#include "esp_event.h"
#include "esp_wifi.h"
#include "nvs_flash.h"void  fun(void* handler_arg,esp_event_base_t event_base,int32_t event_id,void* event_data){printf("%s,%ld\r\n",event_base,event_id);if(event_id==WIFI_EVENT_STA_START){         //如果是STA开启了,那么尝试连接esp_wifi_connect();}
}void app_main(void){nvs_flash_init();                           //初始化nvsesp_netif_init();                           //初始化TCP/IP堆栈esp_event_loop_create_default();            //创建默认事件循环esp_event_handler_register(WIFI_EVENT,ESP_EVENT_ANY_ID,fun,NULL);       //绑定事件处理函数esp_netif_create_default_wifi_sta();        //创建STA,但是返回值没有用上,所以就不管它的返回值了wifi_init_config_t wict = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&wict);                       //初始化WiFIesp_wifi_set_mode(WIFI_MODE_STA);           //设为STA模式wifi_config_t wct = {.sta = {.ssid="zhetu",.password="zhetu123"}};esp_wifi_set_config(WIFI_IF_STA,&wct);      //设置WiFiesp_wifi_start();                           //启动WiFiwhile (1){vTaskDelay(1000 / portTICK_PERIOD_MS);}
}

我手机的热点确实也被连接上了。

我们在上面的截图可以看到,事件处理函数中收到了来自WIFI_EVENT的两个事件,ID分别是2和4,我们可以去看看这分别代表什么含义。

看得出来2就是我们设定的连接条件,也就是STA开启了。

而4是我们连接上了WIFI。

为了使我们的程序更加健全,我们可以根据上面这一堆WIFI事件的事件ID来完善我们的事件处理函数。例如在WiFI断开连接的时候我们再次尝试连接。

连接完之后接下来我们进入下一个阶段。

获取IP

ID号是IP_EVENT_STA_GOT_IP,从名字我们也看得出来,这是IP事件里的,因此我们要获取IP的话需要独立于WiFi事件再单独绑定一个IP事件。

接下来再来一段示例代码,我在上面的连接WiFi的代码里再加一段,主要看我加的代码即可。

#include <stdio.h>
#include <string.h>
#include "esp_event.h"
#include "esp_wifi.h"
#include "nvs_flash.h"void  fun(void* handler_arg,esp_event_base_t event_base,int32_t event_id,void* event_data){printf("%s,%ld\r\n",event_base,event_id);if(event_id==WIFI_EVENT_STA_START){         //如果是STA开启了,那么尝试连接esp_wifi_connect();}
}//加了下面这段代码
void  fun1(void* handler_arg,esp_event_base_t event_base,int32_t event_id,void* event_data){printf("%s,%ld\r\n",event_base,event_id);if(event_id==IP_EVENT_STA_GOT_IP){       ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;printf("ip is %ld",event->ip_info.ip.addr);}
}
//加了上面这段代码void app_main(void){nvs_flash_init();                           //初始化nvsesp_netif_init();                           //初始化TCP/IP堆栈esp_event_loop_create_default();            //创建默认事件循环esp_event_handler_register(WIFI_EVENT,ESP_EVENT_ANY_ID,fun,NULL);       //绑定事件处理函数//加了下面这段代码esp_event_handler_register(IP_EVENT,IP_EVENT_STA_GOT_IP,fun1,NULL);//加了上面这段代码esp_netif_create_default_wifi_sta();        wifi_init_config_t wict = WIFI_INIT_CONFIG_DEFAULT();esp_wifi_init(&wict);                       //初始化WiFIesp_wifi_set_mode(WIFI_MODE_STA);           //设为STA模式wifi_config_t wct = {.sta = {.ssid="zhetu",.password="zhetu123"}};esp_wifi_set_config(WIFI_IF_STA,&wct);      //设置WiFiesp_wifi_start();                           //启动WiFiwhile (1){vTaskDelay(1000 / portTICK_PERIOD_MS);}
}

由于打印的时候是按照长整型的打印的,换算之后是上面的这段16进制数,我们再按照每两个16进制转换为10进制,那就变成了102.168.168.192 ,再反过来192.168.168.102,这个就是我们的IP地址了。

剩下的阶段我们合一起,介绍一下函数就不演示了,因为也比较简单。

esp_err_t esp_wifi_disconnect(void)

esp_err_t esp_wifi_stop(void)

esp_err_t esp_wifi_deinit(void)

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

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

相关文章

JavaScript进阶(十五):JS 垃圾回收机制_vue gc

内存&#xff1a;由可读写单元组成&#xff0c;表示一片可操作空间&#xff1b;管理&#xff1a;人为的去操作一片空间的申请、使用和释放&#xff1b;内存管理&#xff1a;开发者主动申请空间、使用空间、释放空间&#xff1b;管理流程&#xff1a;申请-使用-释放&#xff1b;…

oracle sql monitor简单使用说明

一 sql monitor介绍 二 用命令行方式生成sql monitor报告 set long 1000000 set longchunksize 100000 set linesize 1000 set pagesize 0 set trim on set trimspool on set echo off set feedback off spool report_sql_monitor.html select dbms_sqltune.report_s…

线性代数-行列式-p1 矩阵的秩

目录 1.定义 2. 计算矩阵的秩 3. 矩阵的秩性质 1.定义 2. 计算矩阵的秩 3. 矩阵的秩性质

美国言语听力学会(ASHA)关于非处方 (OTC) 助听器的媒体声明(翻译稿)

美国国会于 2021 年 4 月 13 日批准美国听力学会积极提供建议&#xff0c;并一直积极参与制定FDA关于非处方助听器销售的拟议法规。根据2017年通过的立法授权。学院积极参与帮助塑造授权立法&#xff0c;并就即将出台的条例分享了建议。 根据美国卫生与公众服务部NIH / NIDCD的…

用Python绘制了几张有趣的可视化图表

流程图存在于我们生活的方方面面&#xff0c;对于我们追踪项目的进展&#xff0c;做出各种事情的决策都有着巨大的帮助&#xff0c;而对于的Python而言呢&#xff0c;绘制流程图也是十分轻松的&#xff0c;今天小编就来为大家介绍两个用于绘制流程图的模块&#xff0c;我们先来…

12 JavaScript学习: 字符串

JavaScript 字符串 JavaScript 字符串是一种用于存储和操作文本数据的数据类型。字符串可以包含字母、数字、符号和空格等字符。在 JavaScript 中&#xff0c;字符串可以使用单引号&#xff08;&#xff09;或双引号&#xff08;"&#xff09;来定义。 例如&#xff1a;…

链表与模拟LinkedList的实现

1. ArrayList的缺陷 ArrayList底层使用数组来存储元素 由于其底层是一段连续空间&#xff0c;当在ArrayList任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后 搬移&#xff0c;时间复杂度为O(n)&#xff0c;效率比较低。因此ArrayList不适合做任意位…

机械臂过程

rosdep install --from-paths src --ignore-src --rosdistro melodic0、安装机械手臂 官方教程&#xff1a; 前人教程&#xff1a;UR5机械臂仿真实例 rosdep update 出错&#xff0c;使用小鱼的大佬的 一键配置 wget http://fishros.com/install -O fishros && . fish…

Rest微服务案例

Rest 父工程构建microservicecloud-api公共子模块Modulemicroservicecloud-provider-dept-8001部门微服务提供者Modulemicroservicecloud-consumer-dept-80部门微服务消费者Module 以Dept部门模块做一个微服务通用案例 Consumer消费者&#xff08;Client&#xff09;通过REST调…

ssm082基于java斗车交易系统设计与实现+vue

斗车交易系统 摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&…

第三篇:Python编程基础:掌握核心语法与开发技巧

Python编程基础&#xff1a;掌握核心语法与开发技巧 1 引言 在这个信息化迅速蔓延的世界中&#xff0c;Python语言如同钥匙一般开启了通往各种可能性的大门。无论你是数据科学家、网络工程师、机器学习专家&#xff0c;还是仅仅对自动化办公感兴趣的办公室人员&#xff0c;Pyt…

环境配置——Windows平台配置VScode运行环境为远程服务器或虚拟机

1. 远程机需要先安装SSH服务&#xff0c;命令如下 sudo apt install openssh-server 2. 安装好后需要开启SSH服务&#xff1a; sudo service sshd start 3. 查看SSH服务是否有被开启&#xff1a; sudo systemctl status sshd.service 4. 本地Windows需要生成密钥将公钥放…

CTFshow-PWN-栈溢出(pwn36)

存在后门函数&#xff0c;如何利用&#xff1f; 好好好&#xff0c;终于到了这种有后门函数的了 checksec 检查一下&#xff1a; 32 位程序&#xff0c;RELRO 保护部分开启 RWX: Has RWX segments 存在可读可写可执行的段 使用 ida32 看 main 函数 跟进 ctfshow 函数…

go语言并发实战——日志收集系统(十) 重构tailfile模块实现同时监控多个日志文件

前言 在上一篇文章中&#xff0c;我们实现了通过etcd来同时指定多个不同的有关分区与日志文件的路径&#xff0c;但是锁着一次读取配置的增多&#xff0c;不可避免的出现了一个问题&#xff1a;我们如何来监控多个日志文件&#xff0c;这样原来的tailFile模块相对于当下场景就…

Golang | Leetcode Golang题解之第46题全排列

题目&#xff1a; 题解&#xff1a; func permute(nums []int) [][]int {var (n len(nums)dfs func(vals []int) // 已选择数 排列为vals 后续回溯继续选择 直至选完ans [][]int)dfs func(vals []int) {//边界if len(vals) n {ans append(ans, vals)}//转移 枚举选哪个f…

嵌入式系统中的实时操作系统(RTOS)深入应用与优化

引言 实时操作系统&#xff08;RTOS&#xff09;在嵌入式系统中扮演着至关重要的角色&#xff0c;特别是在需要快速响应和高度可靠性的应用中。 我将探讨如何在STM32单片机上实现RTOS&#xff0c;包括任务管理、内存管理以及中断处理&#xff0c;以提高系统的效率和响应速度。…

github+PicGo+obsidian来作为你的免费高效可靠图床吧

前提 一直以来 博客的图床问题都是个大问题 ,如何找到一个 可靠并且 方便的搭建方式 非常重要 今天介绍一种 githubpicGoobsidian的搭建方式 准备github库 生成个人github token 找到个人 设置 生成一个新token 或者已经有的直接用 新生成的token 需要记录下来 这可能是你最后…

vue3.2+vite+unocss原子化配置

1、安装unocss&#xff1a;npm install unocss 2、vite.config.ts中配置&#xff1a; 3、创建unocss自己的ts文件&#xff1a;uno.config.ts 根路径下创建&#xff0c; 4、在创建好的uno.config.ts文件中编写如下代码&#xff1a; // uno.config.ts import {defineConfig,prese…

关于MySQL Command Line Client 运行闪退问题解决,my.ini文件内容

MySQL Command Line Client 运行闪退问题解决&#xff0c;缺少my.ini文件_通过下载msi安装mysql,双击打开mysql 8.2 command line client --CSDN博客 打开mysql Command Line Client 发现直接闪退&#xff0c;一直不明所以&#xff08;这里是没输密码&#xff0c;直接一闪而过…

python学习笔记----python基础语法(二)

一、字面量 在 Python 中&#xff0c;字面量 是一种直接在代码中表示其自身值的数据。字面量用于创建值&#xff0c;并且可以直接被 Python 的解释器识别和处理。不同类型的数据有不同的字面量形式。下面是一些常见的字面量类型&#xff1a; 二、注释 注释&#xff1a;在程序…