基于VScode的ESP32开发学习(三):官方例程Station,连接到wifi

代码

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"

/* 
用idf.py menuconfig进入菜单配置
或者修改下述宏定义进而配置wifi ssid、密码
*/
#define EXAMPLE_ESP_WIFI_SSID      "胡警文粉丝团"
#define EXAMPLE_ESP_WIFI_PASS      "hjlhjw@123!"
#define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY             //最大重试数

/*连接成功时,FreeRTOS事件组来传递信号*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
/*
事件组设有多个比特位来标志每个事件,但我们仅关心其中两个
1.连接到了AP且分配到了个ip
2.重连次数超过最大重试数,判定为连接失败
*/
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi station";

static int s_retry_num = 0;                     //记录重连次数

static void 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) {         //如果是wifi事件相关&&事件id==wifi STA模式开始,开始连接WiFi
        esp_wifi_connect();
    } 
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {   //如果是wifi事件相关&&事件id==wifi STA模式连接失败
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {                  //如果重连次数<预设的最大重连次数
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {                                                        
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);      //置位wifi事件组的失败标志位,表示连接失败
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } 
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {       //如果是ip事件相关&&事件id==已取得ip
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));             //串口打印ip
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();                   //初始化wifi事件组

    ESP_ERROR_CHECK(esp_netif_init());                          //检查

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();        //配置wifi
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;           //存id
    esp_event_handler_instance_t instance_got_ip;           //存ip
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,         //注册wifi事件
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,           //注册ip事件
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {               //wifi配置初始化
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
	     .threshold.authmode = WIFI_AUTH_WPA2_PSK,

            .pmf_cfg = {
                .capable = true,
                .required = false
            },
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");


    //等待,直到到连接建立,或者连接失败,事件标志bits被event_handler()置位
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits()在回调发生之前就会返回Bits,所以我们可以用来测试事件是否真的发生了*/
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }

    //事件注销后不会再被处理
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
    vEventGroupDelete(s_wifi_event_group);
}

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    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();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
}

解析

1.事件组定义

/*连接成功时,FreeRTOS事件组来传递信号*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
/*
事件组设有多个比特位来标志每个事件,但我们仅关心其中两个
1.连接到了AP且分配到了个ip
2.重连次数超过最大重试数,判定为连接失败
*/
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

在这里插入图片描述
查看定义到这就可以明白,上述一个事件由多位bit表示是什么意思了,每一个事件标志实际上是一个32/16位的unsigned int型变量。
我们再看看BIT0,BIT1
在这里插入图片描述
确实是32位

2.事件处理函数

static void 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) {         //如果是wifi事件相关&&事件id==wifi STA模式开始,开始连接WiFi
        esp_wifi_connect();
    } 
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {   //如果是wifi事件相关&&事件id==wifi STA模式连接失败
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {                  //如果重连次数<预设的最大重连次数
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {                                                        
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);      //置位wifi事件组的失败标志位,表示连接失败
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } 
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {       //如果是ip事件相关&&事件id==已取得ip
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));             //串口打印ip
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

这个函数的功能简单,根据事件id、类型的不同,执行不同操作。详细请看注释

3.初始化函数

(1) esp_netif_create_default_wifi_sta();
这是官方提供给用户,用于初始化默认STA模式的API
在这里插入图片描述

(2)wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); //配置wifi
在这里插入图片描述
(3)
esp_event_handler_instance_t instance_any_id; esp_event_handler_instance_t instance_got_ip;

在这里插入图片描述
所以这两变量的实际类型是void*
参考:C 语言中 void* 详解及应用

(4)

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();                   //初始化wifi事件组

    ESP_ERROR_CHECK(esp_netif_init());                          //检查

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();        //配置wifi
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;           //存id
    esp_event_handler_instance_t instance_got_ip;           //存ip
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,         //注册wifi事件
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,           //注册ip事件
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {               //wifi配置初始化
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
	     .threshold.authmode = WIFI_AUTH_WPA2_PSK,

            .pmf_cfg = {
                .capable = true,
                .required = false
            },
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");


    //等待,直到到连接建立,或者连接失败,事件标志bits被event_handler()置位
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits()在回调发生之前就会返回Bits,所以我们可以用来测试事件是否真的发生了*/
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }

    //事件注销后不会再被处理
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
    vEventGroupDelete(s_wifi_event_group);
}

注册事件

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,         //注册wifi事件
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,           //注册ip事件
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

在这里插入图片描述
注册一个事件处理实例到默认死循环中
@param[in] :不能为NULL,被注册的 Event_loop 的句柄

  • @param[in] :handle函数要处理的事件的基础id
  • @param[in] :handle函数要处理的事件的id
  • @param[in] :事件触发时,handle函数入口
  • @param[in] :事件触发时,传递给handle函数的参数
  • @param[out] instance :可以为NULL,后面自行看吧

//可以看我的基于VScode的ESP32开发学习(四),对这里做了详细分析

参考:ESP32-IDF Event_Loop库 实战分析

后言

看wifi之前先去看事件注册相关例程,会轻松很多。

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值