ESP32 (WIFI)-AP、STA模式(13)

提示:本博客作为学习笔记,有错误的地方希望指正

文章目录

  • 一、ESP32 WIFI模式概述
  • 二、ESP32 WIFI-AP初始化流程
  • 三、WIFI-AP示例
  • 四、ESP32 WIFI-STA初始化流程
  • 五、WIFI-STA示例

一、ESP32 WIFI模式概述

  参考资料:ESP IDF编程手册V4.4
  WIFI主要有两种模式 STA、AP两种模式,AP的全程是:Access Point,即无线接入点,就是我们常说的热点,热点被其他设备连接,那么连接热点的设备我们叫啥呢,连接热点的设备叫STA,STA的全程是:Station,STA站点就是每一个连接到无线网络中的终端(如笔记本电脑、PDA及其它可以联网的用户设备)都可称为一个站点。
  Wi-Fi 库支持配置及监控 ESP32 Wi-Fi 连网功能。支持配置:

  • station 模式(即 STA 模式或 Wi-Fi 客户端模式),此时 ESP32 连接到接入点 (AP)。
  • AP 模式(即 Soft-AP 模式或接入点模式),此时基站连接到 ESP32。
  • station/AP 共存模式(ESP32 既是接入点,同时又作为基站连接到另外一个接入点)。
  • 上述模式的各种安全模式(WPA、WPA2 及 WEP 等)。
  • 扫描接入点(包括主动扫描及被动扫描)。
  • 使用混杂模式监控 IEEE802.11 Wi-Fi 数据包。

二、ESP32 WIFI-AP初始化流程

  WIFIAP配置流程:
ESP32 (WIFI)-AP、STA模式(13)_第1张图片

三、WIFI-AP示例

  在WIFI示例中我们可以看到有默认的event loop,event loop 我的理解就是任务事件,就是当我们注册回调函数之后,在执行wifi初始化之后,就会执行wifi任务,然后wifi任务有事件产生之后就会有一个类似于中断事件在回调事件中产生。其中注册函数如下:

ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));

  WIFI_EVENT是一个字符串,就是我们event loop基础事件,后续event loop发送到那个组件都是根据这个参数确定的,ESP_EVENT_ANY_ID是指在发送event loop 事件的时候,只要是WIFI_EVENT这个基础事件的数据都会调用我们的回调函数,当我们使用ESP_EVENT_ANY_BASE的时候这个时候就是发送除了WIFI_EVENT这个基础事件之外的其他任何基础事件都会调用这个我们注册的回调函数,当我们使用指定ID的时候,这个时候就只会当有这个ID事件触发的时候才会调用我们注册的回调函数,例如我们注册ID为WIFI_EVENT_AP_STACONNECTED的时候,这个时候只要有WIFI_EVENT_AP_STACONNECTED的事件触发的时候才会触发执行我们的回调函数wifi_event_handler,其他的WIFI_EVENT_AP_STADISCONNECTED、WIFI_EVENT_AP_START事件产生的时候不会调用我们注册的回调函数。
  WIFI的认证模式有以下几种,我们默认基本上都是WIFI_AUTH_WPA_WPA2_PSK。

typedef enum {
    WIFI_AUTH_OPEN = 0,         /**< authenticate mode : open */
    WIFI_AUTH_WEP,              /**< authenticate mode : WEP */
    WIFI_AUTH_WPA_PSK,          /**< authenticate mode : WPA_PSK */
    WIFI_AUTH_WPA2_PSK,         /**< authenticate mode : WPA2_PSK */
    WIFI_AUTH_WPA_WPA2_PSK,     /**< authenticate mode : WPA_WPA2_PSK */
    WIFI_AUTH_WPA2_ENTERPRISE,  /**< authenticate mode : WPA2_ENTERPRISE */
    WIFI_AUTH_WPA3_PSK,         /**< authenticate mode : WPA3_PSK */
    WIFI_AUTH_WPA2_WPA3_PSK,    /**< authenticate mode : WPA2_WPA3_PSK */
    WIFI_AUTH_WAPI_PSK,         /**< authenticate mode : WAPI_PSK */
    WIFI_AUTH_MAX
} wifi_auth_mode_t;

  当我们设置热点的密码长度为0的时候,我们就需要设置加密方式为WIFI_AUTH_OPEN 开放。

/**
 * @file 1_WIFI_AP.c
 * @author WSP
 * @brief  WIFI AP模式的实验
 * @version 0.1
 * @date 2022-10-30
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include "MY_WIFI_Include.h"

#define EXAMPLE_ESP_WIFI_SSID       "ESP32AP"
#define EXAMPLE_ESP_WIFI_PASSWORD   "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL    1
#define EXAMPLE_MAX_STA_CONNECT     4

const static char * TAG = "WIFI_AP";

static void wifi_event_handler(void * arg, esp_event_base_t event_base, int32_t event_id, void * event_data)
{
    if (event_id == WIFI_EVENT_AP_STACONNECTED) {           // WIFI 连接事件
        wifi_event_ap_staconnected_t * event = (wifi_event_ap_staconnected_t *)event_data;
        ESP_LOGI(TAG,"station "MACSTR" join, AID=%d",MAC2STR(event->mac),event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { // WIFI断开连接事件
        wifi_event_ap_stadisconnected_t * event = (wifi_event_ap_stadisconnected_t *)event_data;
        // #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
        ESP_LOGI(TAG,"station "MACSTR" leave,AID=%d",MAC2STR(event->mac),event->aid);
    } else if (event_id == WIFI_EVENT_AP_START){
        ESP_LOGI(TAG,"WIFI_EVENT_AP_START");
    }
}

void wifi_init_softap(void)
{
    ESP_ERROR_CHECK(esp_netif_init());                  // 初始化lwip协议
    ESP_ERROR_CHECK(esp_event_loop_create_default());   // 创建event loop
    // API创建esp_netif对象与默认的WiFi接入点配置,将netif附加到wifi并注册默认的wifi处理程序。
    esp_netif_create_default_wifi_ap();              
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();// 获取WIFI默认初始化配置
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));               // 初始化wifi
    // 创建WIFI事件的event loop回调函数
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));
    wifi_config_t wifi_config = {
        .ap = {
            .ssid           = EXAMPLE_ESP_WIFI_SSID,        // 设置WIFI SSID
            .ssid_len       = strlen(EXAMPLE_ESP_WIFI_SSID),// 设置WIFI SSID长度
            .channel        = EXAMPLE_ESP_WIFI_CHANNEL,     // 设置通道
            .password       = EXAMPLE_ESP_WIFI_PASSWORD,    // 设置密码 设置密码长度必须大于等于8或者0
            .max_connection = EXAMPLE_MAX_STA_CONNECT,      // 设置STA最大连接数
            .authmode       = WIFI_AUTH_WPA_WPA2_PSK        // 设置设置加密方式
        },
    }; 
    if (strlen(EXAMPLE_ESP_WIFI_PASSWORD) == 0) {           // 密码长度0的话加密方式为 open 不加密
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;   
    }  
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));       // 初始化 WIFI 模式 
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP,&wifi_config)); // 设置AP模式下的一些配置参数
    ESP_ERROR_CHECK(esp_wifi_start());                      // 启动WIFI
    ESP_LOGI(TAG,"wifi_init_softap finished. SSID:%s password:%s channel:%d",
                EXAMPLE_ESP_WIFI_SSID,
                EXAMPLE_ESP_WIFI_PASSWORD,
                EXAMPLE_ESP_WIFI_CHANNEL);                                  
}

void WIFI_AP_Init(void)
{
    // 初始化flash
    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_AP");
    wifi_init_softap();
}

四、ESP32 WIFI-STA初始化流程

ESP32 (WIFI)-AP、STA模式(13)_第2张图片

五、WIFI-STA示例

  在WIFI STA中我们需要配置下我们要连接热点名称以及密码,其次我们这里开启一个定时器来检测我们是否连接上WIFI,这里我们创建两个event loop 事件,最后我们等待事件组,等待我们WiFi连接之后才会去继续执行后面的逻辑代码。

/**
 * @file 2_WIFI_STA.c
 * @author WSP
 * @brief  WIFI STA的实验,加上一个软件定时器 10S内没有连接上就连接失败
 * @version 0.1
 * @date 2022-10-30
 * @copyright Copyright (c) 2022
 */
#include "MY_WIFI_Include.h"

#define WIFI_CONNECTED_BIT  BIT0
#define WIFI_FAIL_BIT       BIT1

#define EXAMPLE_ESP_WIFI_SSID       "CMCC-CM2T"
#define EXAMPLE_ESP_WIFI_PASSWORD   "kqkmaunt"
#define EXAMPLE_ESP_MAXIMUM_RETRY   10

// WIFI_AUTH_WEP
// WIFI_AUTH_WPA_PSK
// WIFI_AUTH_WPA2_PSK
// WIFI_AUTH_WPA_WPA2_PSK
// WIFI_AUTH_WPA3_PSK
// WIFI_AUTH_WPA2_WPA3_PSK
// WIFI_AUTH_WAPI_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK

static EventGroupHandle_t s_wifi_event_group;
const static char * TAG = "wifi station";
static int s_retry_num = 0;
static TimerHandle_t WIFI_Timer = NULL;     // 创建定时器句柄

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) {
        esp_wifi_connect();                         // 连接热点
        assert(WIFI_Timer);
        xTimerReset(WIFI_Timer, pdMS_TO_TICKS(10)); // 复位定时器
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            ESP_LOGI(TAG, "retry to connected to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
            ESP_LOGI(TAG, "connected to the AP fail wait time:%d",s_retry_num);
        }
    } else 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(TAG, "got ip:" IPSTR,IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}
/**
 * @brief WIFI 连接超时定时器
 * @param xTimer 定时器句柄
 */
void WIFI_Time_Counter_Callback(TimerHandle_t xTimer)
{
    s_retry_num++;
}
void wifi_init_sta(void)
{
    // 创建定时器
    WIFI_Timer = xTimerCreate("Connected_WIFI_Time",
                 pdMS_TO_TICKS(1000),
                 pdTRUE,
                 (void *)NULL,
                 WIFI_Time_Counter_Callback);

    s_wifi_event_group = xEventGroupCreate();           // 创建事件组
    ESP_ERROR_CHECK(esp_netif_init());                  // 初始化lwip 协议栈
    ESP_ERROR_CHECK(esp_event_loop_create_default());   // 创建event loop
    // 这个API注销wifi处理程序,并从wifi中分离创建的对象。(如果esp_netif为NULL,则此函数为空操作)
    esp_netif_create_default_wifi_sta();        
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();// 获取WIFI默认配置
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));               // 初始化WIFI

    esp_event_handler_instance_t instance_any_id;       // 创建事件句柄变量
    esp_event_handler_instance_t instance_got_ip;       // 创建事件句柄变量
    // 注册WIFI事件
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    // 注册IP事件
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));
    wifi_config_t wifi_config = {
        .sta = {
            .ssid       = EXAMPLE_ESP_WIFI_SSID,                    // 配置STA热点连接的热点名
            .password   = EXAMPLE_ESP_WIFI_PASSWORD,                // 配置要连接的热点密码
            .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,// 在快速扫描模式下接受的最弱authmode
            .pmf_cfg = {
            // 配置管理框配置。将广播在RSN的能力在RSN IE。
            .capable = true,  // 弃用变量。如果其他设备也通告了PMF能力,则设备将始终以PMF模式连接
            .required = false // 声明需要受保护的管理框架。设备将不关联到非pmf能力的设备。
            },
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));              // 设置WIFI的模式
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA,&wifi_config)); // 配置WIFI的参数
    ESP_ERROR_CHECK(esp_wifi_start());                              // 开启WIFI

    ESP_LOGI(TAG,"wifi_init_sta finished");    
    // 创建事件组
    EventBits_t bit = xEventGroupWaitBits( s_wifi_event_group,
                                           WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
                                           pdFALSE,
                                           pdFALSE,
                                           portMAX_DELAY);
    // 连接事件组                                        
    if (bit & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG,"connected to ap SSID :%s passdord:%s",
                EXAMPLE_ESP_WIFI_SSID,
                EXAMPLE_ESP_WIFI_PASSWORD);
    } else if (bit & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG,"Failed to connected to SSID:%s password:%s",
                EXAMPLE_ESP_WIFI_SSID,
                EXAMPLE_ESP_WIFI_PASSWORD);
    } else {
        ESP_LOGE(TAG,"UNEXPECTED EVENT");
    }                                     
}

void WIFI_STA_Init(void)
{
    // 初始化flash
    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();
}

你可能感兴趣的:(ESP32成长笔记,单片机,学习,c,ESP32,WIFI)