ESP-C3入门8. 连接WiFi并打印信息

Posted 编程圈子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ESP-C3入门8. 连接WiFi并打印信息相关的知识,希望对你有一定的参考价值。

ESP-C3入门8. 连接WiFi并打印信息

本文示例代码主要来自官方开源仓库:
https://gitee.com/EspressifSystems/book-esp32c3-iot-projects

一、ESP32 连接WiFi的基本操作流程

1. 初始化nvs存储

nvs_flash_init();
tcpip_adapter_init();

2. 配置WiFi工作模式

wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&wifi_init_config);
esp_wifi_set_storage(WIFI_STORAGE_RAM);
esp_wifi_set_mode(WIFI_MODE_STA);

3. 设置WiFi登陆信息

wifi_config_t wifi_config = 
    .sta = 
        .ssid = "your_SSID",
        .password = "your_password",
    ,
;
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);

4. 启动WiFi

esp_wifi_start();

5. 开启连接

esp_wifi_connect();

6. 判断是否成功

wifi_ap_record_t ap_info;
esp_wifi_sta_get_ap_info(&ap_info);
if (ap_info.authmode != WIFI_AUTH_OPEN) 
    // 连接成功
 else 
    // 连接失败


二、事件处理函数

在 ESP-IDF 中,一些关键的系统任务(比如,Wi-Fi连接、网络传输等)通常都是在事件驱动的模式下实现的,
系统会生成一些事件,然后由事件处理机制来进行处理。事件处理机制是用于接收并处理系统事件的主要机制,通过它,可以实现自定义的动作(比如,记录日志、进行状态更新等)。

在ESP-IDF中使用事件处理函数有以下步骤:

1. 定义事件处理函数

定义一个函数,用于处理特定的事件,如:

void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)

    // your code here


2. 创建事件组

使用 xEventGroupCreate 函数创建事件组。

3. 在事件处理函数中设置事件组位

在事件处理函数内部,使用 xEventGroupSetBits 函数设置事件组位,以标识事件已经发生。

4. 在其他任务中等待事件组位

使用 xEventGroupWaitBits 函数在其他任务中等待事件组位,以确认事件已经发生。

5. 注册事件处理函数

使用函数(如 esp_event_loop_init)注册事件处理函数,使其生效。

esp_event_handler_register(event_base, event_id, event_handler, arg);

其中:

  • event_base 是事件的基础,通常是一个枚举,它表示事件类别,比如 WIFI_EVENT。
  • event_id 是事件的 ID,通常也是一个枚举,它表示事件类型,比如 WIFI_EVENT_STA_DISCONNECTED。
  • event_handler 是事件处理函数,用来处理事件,从中读取事件数据。
  • arg 是一个用户指定的参数,在事件处理函数中可以读取。

6. 如果有必要取消注册

esp_event_handler_unregister(event_base, event_id, event_handler);

三、事件组的使用

ESP-IDF中的事件组是一种线程间同步机制,允许多个任务同时等待特定的事件发生。
在ESP-IDF中使用事件组的步骤是:

1. 创建事件组

EventGroupHandle_t s_event_group = xEventGroupCreate();

2. 向事件组中设置事件

xEventGroupSetBits(s_event_group, BIT0);

3. 在其它任务中等待事件

EventBits_t bits = xEventGroupWaitBits(s_event_group, BIT0, pdFALSE, pdFALSE, portMAX_DELAY);

四、实现过程

1. WiFi初始化函数做以下事情

  • 创建一个事件组,用来管理Wi-Fi连接事件。
  • 实始化协议栈
  • 创建默认事件循环
  • WiFi设置为sta模式
  • 注册事件处理器
static void wifi_initialize(void)

    // 创建一个事件组,用于管理Wi-Fi连接事件。
    s_wifi_event_group = xEventGroupCreate();

    // 初始化 TCP/IP 协议栈。
    ESP_ERROR_CHECK(esp_netif_init());

    // 创建默认事件循环。
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    // 创建默认的Wi-Fi网络接口。
    esp_netif_create_default_wifi_sta();
    // 设置 Wi-Fi 初始化配置为默认配置
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    // 注册事件处理器,以处理 Wi-Fi 和 IP 相关事件
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));

其中事件组的定义是:

static EventGroupHandle_t s_wifi_event_group = NULL;

2. WiFi Station模式初始化

  • 配置WiFi信息
  • WiFi工作模式设置为STA
  • 启动WiFi
  • 等待事件
static void wifi_station_initialize(void)

    // 配置WiFi的配置信息
    wifi_config_t wifi_config = 
            .sta = 
                    .ssid = LIGHT_ESP_WIFI_SSID,
                    .password = LIGHT_ESP_WIFI_PASS,
                    // 启用WPA2模式,常用的WiFi连接方式
                    .threshold.authmode = WIFI_AUTH_WPA2_PSK,

                    .pmf_cfg = 
                            .capable = true,
                            .required = false
                    ,
            ,
    ;
    // WiFi工作模式设置为STA
    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());

    ESP_LOGI(TAG, "wifi_station_initialize finished.");
    
	// 下面的代码不是必须的,但它演示了程序如何阻塞并等待连接成功
    /* 等待连接建立(WIFI_CONNECTED_BIT)或连接失败的次数达到最大值(WIFI_FAIL_BIT)。
     * 这些位通过 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", LIGHT_ESP_WIFI_SSID, LIGHT_ESP_WIFI_PASS);
     else if (bits & WIFI_FAIL_BIT) 
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", LIGHT_ESP_WIFI_SSID, LIGHT_ESP_WIFI_PASS);
     else 
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    

xEventGroupWaitBits 函数在这里不是必须的。 它是一个阻塞函数,将等待一个或多个事件位被设置,直到返回时间结束。
本示例中,它等待 WIFI_CONNECTED_BIT 或 WIFI_FAIL_BIT 中的任何一个事件位被设置,并且等待的最长时间是 portMAX_DELAY。

相关参数:

  • s_wifi_event_group 是事件组变量,用于存储事件位。
  • WIFI_CONNECTED_BIT | WIFI_FAIL_BIT 是要等待的事件位。WIFI_CONNECTED_BIT 表示 Wi-Fi 连接成功的事件,WIFI_FAIL_BIT 表示 Wi-Fi 连接失败的事件。
  • pdFALSE 和 pdTRUE 是宏,分别表示布尔值的 false 和 true,此处代表不需要等待所有事件位(pdFALSE)和不清除事件位(pdFALSE)。
  • portMAX_DELAY 是一个常量,表示无限等待。
  • 返回值(EventBits_t bits)是一个事件位变量,表示返回的事件位。

该代码实现了在等待 Wi-Fi 连接结果的同时不占用 CPU 资源,并在连接成功或失败时记录事件位以作后续处理。

事件组允许每个事件有多个位,前面要定义:

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

这里的BIT0 BIT1由开发者自行定义。

3. 事件回调

// 事件回调
static void event_handler(void *arg, esp_event_base_t event_base,
                          int32_t event_id, void *event_data)

    // 如果是Wi-Fi事件,并且事件ID是Wi-Fi事件STA_START
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) 
        esp_wifi_connect();
     else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) 
        // 如果是Wi-Fi事件,并且事件ID是Wi-Fi事件STA_DISCONNECTED
        /* 如果重试次数小于最大重试次数 */
        if (s_retry_num < LIGHT_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);
        
        ESP_LOGI(TAG, "connect to the AP fail");
     else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) 
        // 如果是IP事件,并且事件ID是IP事件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));

        // 将重试次数重置为 0;
        s_retry_num = 0;
        // 通过调用 xEventGroupSetBits 函数,将 WIFI_CONNECTED_BIT 设置到事件组中,表示成功连接到 AP
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    

五、完整代码

#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"


#define LIGHT_ESP_WIFI_SSID     "你的WIFI账号"
#define LIGHT_ESP_WIFI_PASS     "你的WiFi密码"
#define LIGHT_ESP_MAXIMUM_RETRY 5

// 事件组允许每个事件有多个位,这里只使用两个事件:
// 已经连接到AP并获得了IP
// 在最大重试次数后仍未连接
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi connection";

// FreeRTOS事件组,连接成功时发出信号
static EventGroupHandle_t s_wifi_event_group = NULL;
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)

    // 如果是Wi-Fi事件,并且事件ID是Wi-Fi事件STA_START
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) 
        esp_wifi_connect();
     else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) 
        // 如果是Wi-Fi事件,并且事件ID是Wi-Fi事件STA_DISCONNECTED
        /* 如果重试次数小于最大重试次数 */
        if (s_retry_num < LIGHT_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);
        
        ESP_LOGI(TAG, "connect to the AP fail");
     else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) 
        // 如果是IP事件,并且事件ID是IP事件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));

        // 将重试次数重置为 0;
        s_retry_num = 0;
        // 通过调用 xEventGroupSetBits 函数,将 WIFI_CONNECTED_BIT 设置到事件组中,表示成功连接到 AP
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    


static void wifi_initialize(void)

    // 创建一个事件组,用于管理Wi-Fi连接事件。
    s_wifi_event_group = xEventGroupCreate();

    // 初始化 TCP/IP 协议栈。
    ESP_ERROR_CHECK(esp_netif_init());

    // 创建默认事件循环。
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    // 创建默认的Wi-Fi网络接口。
    esp_netif_create_default_wifi_sta();
    // 设置 Wi-Fi 初始化配置为默认配置
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    // 注册事件处理器,以处理 Wi-Fi 和 IP 相关事件
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));


static void wifi_station_initialize(void)

    // 配置WiFi的配置信息
    wifi_config_t wifi_config = 
            .sta = 
                    .ssid = LIGHT_ESP_WIFI_SSID,
                    .password = LIGHT_ESP_WIFI_PASS,
                    // 启用WPA2模式,常用的WiFi连接方式
                    .threshold.authmode = WIFI_AUTH_WPA2_PSK,

                    .pmf_cfg = 
                            .capable = true,
                            .required = false
                    ,
            ,
    ;
    // WiFi工作模式设置为STA
    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());

    ESP_LOGI(TAG, "wifi_station_initialize finished.");

    /* 等待连接建立(WIFI_CONNECTED_BIT)或连接失败的次数达到最大值(WIFI_FAIL_BIT)。
     * 这些位通过 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", LIGHT_ESP_WIFI_SSID, LIGHT_ESP_WIFI_PASS);
     else if (bits & WIFI_FAIL_BIT) 
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", LIGHT_ESP_WIFI_SSID, LIGHT_ESP_WIFI_PASS);
     else 
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    


void app_main()

    int i = 0;
    ESP_LOGE(TAG, "app_main");
    // 初始化NVS存储区
    ESP_ERROR_CHECK(nvs_flash_init());

    // Wi-Fi初始化
    ESP_LOGI(TAG, "Wi-Fi initialization");
    wifi_initialize();

    // Wi-Fi Station初始化
    wifi_station_initialize();

    while (1) 
        ESP_LOGI(TAG, "[%02d] Hello world!", i++);
        vTaskDelay(pdMS_TO_TICKS(5000));
    


运行结果:

以上是关于ESP-C3入门8. 连接WiFi并打印信息的主要内容,如果未能解决你的问题,请参考以下文章

ESP-C3入门7. WIFI 操作 扫描WIFI列表

ESP-C3入门7. WIFI 操作 扫描WIFI列表

ESP-C3入门13. SoftAP模式

ESP-C3入门13. SoftAP模式

ESP-C3入门9. 创建TCP Server

ESP-C3入门9. 创建TCP Server