ESP32 在IDF_V5.3.1版本下实现AP无线热点模式!(带WIFI事件处理)

一、什么是ESP32的AP无线热点模式?

        ESP32 的 AP(Access Point)模式 是指 ESP32 作为无线接入点运行,它自己创建一个 Wi-Fi 网络,允许其他设备(如手机、电脑、平板等)直接连接到它上面,而不依赖于现有的路由器或 Wi-Fi 网络。下面详细解释一下:

1. AP 模式的基本概念

  • 自建网络:在 AP 模式下,ESP32 会广播一个 SSID,成为一个小型无线热点。其他设备可以扫描到这个 SSID 并连接进去。

  • 无需依赖路由器:与 STA(Station)模式不同,STA 模式下 ESP32 作为客户端连接到已有的 Wi-Fi 网络,而 AP 模式下 ESP32 则提供一个网络供其他设备接入。

  • 局域通信:连接到 ESP32 的设备可以在局域网内进行数据通信,比如通过 TCP/IP 协议互相通信,或者通过 ESP32 提供的 Web 服务器、MQTT 服务等进行交互。

2. ESP32 AP 模式的应用场景

  • IoT 设备配置:许多 IoT 设备在首次启动时会开启 AP 模式,让用户连接后通过网页配置设备的参数,再切换到 STA 模式。

  • 局域网数据交换:在没有现成 Wi-Fi 网络的环境下,可以利用 ESP32 建立临时网络,实现局部设备之间的数据传输或远程控制。

  • 离线应用:在需要独立运行并不依赖互联网的场景下,ESP32 的 AP 模式可以提供稳定的局域网连接。

3. AP 模式的特点与优势

  • 简单部署:不需要额外的路由器或 Wi-Fi 基础设施,只需配置 ESP32 的 AP 参数(如 SSID、密码、最大连接数等)即可启动网络。

  • 安全性:可以设置 WPA/WPA2 加密,确保只有授权设备能够连接到 ESP32 创建的网络。

  • 灵活性:适用于设备初始配置、临时数据交换或局域网服务等场景,十分灵活。

4.总结

  • ESP32 的 AP 模式 是将 ESP32 变成一个无线热点,使它能够独立建立 Wi-Fi 网络供其他设备连接。
  • 它适用于需要离线配置、局域网通信和临时数据交换的场景,不需要依赖外部路由器。
  • 在实际项目中,通过配置相应的参数(SSID、密码、最大连接数等),就能很方便地使用 ESP32 搭建一个小型的无线网络。

二、如何在ESP32上实现AP热点模式?

1. 引入头文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_mac.h"
#include "esp_log.h"
#include "esp_netif_net_stack.h"
#include "esp_netif.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/sys.h"
  • 标准库头文件:提供基础 C 语言函数支持。
  • FreeRTOS 头文件:支持多任务调度和实时操作系统功能。
  • ESP-IDF 系统和 NVS:用于系统初始化、重启和非易失性存储操作。
  • WiFi 和事件处理:使 ESP32 能够配置 WiFi、处理网络事件并打印调试信息。
  • 网络接口(esp-netif):管理网络连接接口和 TCP/IP 协议栈。
  • lwIP 库:提供底层的网络通信 API,支持 socket 编程等。

        这些头文件共同构成了 ESP32 应用程序的基础,使得开发者可以实现 WiFi 功能、网络通信和任务调度等功能。如果你正在编写或调试 ESP32 应用,这些头文件基本上是必不可少的。

2. 定义 WiFi AP 模式相关的宏

//定义目标AP名称和密码
#define ESP_WIFI_AP_SSID      "XiaoHai@iPhone"  
#define ESP_WIFI_AP_PASSWD    "123456788"
#define ESP_WIFI_CHANNEL 5
#define ESP_MAX_STA_CONN_AP 5 //定义设备连接AP最大重连次数

 这里定义了 WiFi 的基本参数:SSID、密码、通道和允许的最大连接数,根据实际需求可以修改。

3 . 定义 WiFi AP 模式下设备相关事件的宏和信息结构体

//定义事件标志位
#define DEVICE_CONNECTED_AP_BIT     BIT0
#define DEVICE_DISCONNECTED_AP_BIT  BIT1
#define DEVICE_GET_IP_AP_BIT        BIT2
//存放WIFI AP 模式下客户端设备连接AP后的信息
typedef struct wifi_sta_connect_Info
{
    esp_ip4_addr_t dev_ip; //客户端设备连接AP后获取的IP
    uint8_t dev_mac[6]; //客户端设备MAC地址
    uint8_t ap_ssid[32]; //AP的名称
    uint8_t ap_password[64]; //AP的密码

}wifi_ap_connect_info;

4. 初始化非易失性存储 (NVS)

        在使用 WiFi 功能之前,必须初始化 NVS,因为 WiFi 驱动会从 NVS 中读取配置信息。
流程:

  • 调用 nvs_flash_init() 初始化 NVS。
  • 如果返回错误(例如内存页不足或版本不匹配),则先擦除 NVS 再重新初始化。
    示例代码:
esp_err_t nvs_init(void)
{
    esp_err_t ret;
    ret = nvs_flash_init(); /* 初始化 NVS 第一次调用时,它会加载存储区域。如果存储区域有问题或不兼容,会抛出 ESP_ERR_NVS_NO_FREE_PAGES 或 ESP_ERR_NVS_NEW_VERSION_FOUND 错误。此时,我们会擦除存储并重新初始化。 */
    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();
    }
    return ret;
}

 5.WIFI AP模式初始化


/*
函数功能:WIFI AP模式初始化
形    参:
        wifi_ap_cfg:WIFI的配置
返 回 值:无
*/
void wifi_ap_init(wifi_config_t *wifi_ap_cfg)
{ 
    ESP_LOGI(TAG_AP, "wifi_ap_init.....");
    //1.创建新的事件循环.
    ESP_ERROR_CHECK(esp_event_loop_create_default()); 
    //2.初始化WIFI连接/断开的标志事件组
    wifi_event_group = xEventGroupCreate();
    //3.注册事件ID和IP获取服务函数
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL)); 
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,IP_EVENT_AP_STAIPASSIGNED,&wifi_event_handler,NULL,NULL)); 
    //4.网卡初始化.初始化底层TCP/IP堆栈
    ESP_ERROR_CHECK(esp_netif_init()); 
    //5.使用默认WiFi Station配置创建esp_netif对象,将netif连接到WiFi并注册默认WiFi处理程序。
    esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap(); 
    assert(ap_netif); //断言检查,确保程序在运行时满足特定的条件.
    //6.netif连接到WiFi并注册默认WiFi处理程序。
    esp_netif_set_default_netif(ap_netif);
    //7.初始化wifi配置参数为默认.
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 
    //8.为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API
    ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 
    ESP_LOGI(TAG_AP, "wifi init cfg !");
    //9.设置WIFI为AP模式
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_LOGI(TAG_AP, "wifi set ap mode !");
    //10.设置WIFI AP模式的配置
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, wifi_ap_cfg) );
    ESP_LOGI(TAG_AP, "wifi init ap finished !");
    //11.启动WIFI
    ESP_ERROR_CHECK(esp_wifi_start()); 
    ESP_LOGI(TAG_AP, "wifi start !");
    ESP_LOGI(TAG_AP, "wifi_init_softap finished. SSID:%s password:%s channel:%d",wifi_ap_cfg->ap.ssid,wifi_ap_cfg->ap.password,wifi_ap_cfg->ap.channel);
   
}   

        这就是 ESP32 以 AP 模式初始化的详细流程。通过这些步骤,ESP32 将创建一个无线接入点,允许其他设备直接连接并进行局域网通信。

6.WIFI 连接相关事件处理

        在 ESP32 AP 模式下,当有客户端(站点,STA)连接或断开时,系统会产生相应的 WiFi 事件,通过这些事件可以获取连接设备的相关信息,并执行相应的处理逻辑。

ESP-IDF 中常用的 AP 模式连接事件包括:

  • WIFI_EVENT_AP_STACONNECTED
    当一个客户端成功连接到 ESP32 作为 AP 时,会触发此事件。事件数据通常包含客户端的 MAC 地址和分配给它的 AID(Association Identifier)。

  • WIFI_EVENT_AP_STADISCONNECTED
    当一个客户端从 AP 断开连接时,会触发此事件。同样,事件数据中包含断开连接设备的 MAC 地址和 AID。

  • IP_EVENT_AP_STAIPASSIGNED
    当一个客户端设备连接到 ESP32 的 AP 后,AP 内部运行的 DHCP 服务器会为该客户端分配一个 IP 地址。一旦分配成功,就会触发 IP_EVENT_AP_STAIPASSIGNED 事件。

WIFI AP模式下相关的WiFi事件处理服务实现:


/*
函数功能:WIFI连接事件回调服务函数,由于处理特定的WIFI事件
函数形参:
        arg:传入网卡控制块
        event_base:WIFI 事件
        event_id:事件 ID
        event_data:事件数据
*/
static 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_AP_STACONNECTED) //有设备连接到到AP
    {
        wifi_event_ap_staconnected_t *eventData = (wifi_event_ap_staconnected_t *)event_data;
        memcpy(wifi_ap_net_info.dev_mac,eventData->mac,sizeof(eventData->mac));
        xEventGroupSetBits(wifi_event_group, DEVICE_CONNECTED_AP_BIT);
        ESP_LOGI(TAG_AP, "station "MACSTR" join, AID=%d",MAC2STR(eventData->mac), eventData->aid);
    }
    else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED)  //有设备与AP断开连接
    {
        wifi_event_ap_staconnected_t *eventData = (wifi_event_ap_staconnected_t *)event_data;
        memcpy(wifi_ap_net_info.dev_mac,eventData->mac,sizeof(eventData->mac));
        ESP_LOGI(TAG_AP, "station "MACSTR" leave, AID=%d",MAC2STR(eventData->mac), eventData->aid);
        xEventGroupSetBits(wifi_event_group, DEVICE_DISCONNECTED_AP_BIT);
    }
    else if(event_base == IP_EVENT && event_id == IP_EVENT_AP_STAIPASSIGNED) //有设备连接到到AP并成功从AP分配到IP
    {
        ip_event_ap_staipassigned_t *eventData = (ip_event_ap_staipassigned_t *)event_data;
        memcpy(wifi_ap_net_info.dev_mac,eventData->mac,sizeof(eventData->mac));
        wifi_ap_net_info.dev_ip = eventData->ip;
        xEventGroupSetBits(wifi_event_group, DEVICE_GET_IP_AP_BIT);
        ESP_LOGI(TAG_AP, "DHCP server assigned IP to a client: MAC="MACSTR", IP="IPSTR"",MAC2STR(eventData->mac), IP2STR(&eventData->ip));
    }
    else
    {
        ESP_LOGI(TAG_AP,"Unexpected event ! event_id = %d \n",event_id);
    }
}

7.WIFI AP模式测试


/*
函数功能:WIFI AP模式连接AP测试
形    参:无
返 回 值:无
*/
void wifi_ap_test(void *pvParameters)
{
    nvs_init();

    uint8_t displayFlag=0;
    wifi_config_t wifi_ap_config = {
        .ap ={
            .ssid = ESP_WIFI_AP_SSID,
            .ssid_len = strlen(ESP_WIFI_AP_SSID),
            .channel = ESP_WIFI_CHANNEL,
            .password = ESP_WIFI_AP_PASSWD,
            .max_connection = ESP_MAX_STA_CONN_AP,
            .authmode = WIFI_AUTH_WPA2_PSK,
            .pmf_cfg.required = false,
        }
    };

    if (strlen(ESP_WIFI_AP_PASSWD) == 0) {
        wifi_ap_config.ap.authmode = WIFI_AUTH_OPEN;
    }
    memcpy(wifi_ap_net_info.ap_ssid,ESP_WIFI_AP_SSID,sizeof(ESP_WIFI_AP_SSID));
    memcpy(wifi_ap_net_info.ap_password,ESP_WIFI_AP_PASSWD,sizeof(ESP_WIFI_AP_PASSWD));
    st7789v_clearScreen(WHITE,USE_HORIZONTAL);
    wifi_ap_init(&wifi_ap_config);
    //*(uint8_t *)pvParameters = 1;
    display_wifi_ap_connect_info_to_lcd(4);
    while(1) 
    {
        //等待事件标志位:等待网络连接成功/失败。成功和失败的bits会在上面注册的wifi_event_handler函数中被设置。
        //xEventGroupWaitBits(事件组句柄,要等待的事件位,是否在函数返回前清除触发的标志位,是否等待所有指定的标志位,等待的时间(以系统滴答为单位) );
        EventBits_t bits = xEventGroupWaitBits(wifi_event_group,DEVICE_CONNECTED_AP_BIT | DEVICE_DISCONNECTED_AP_BIT | DEVICE_GET_IP_AP_BIT,pdTRUE,pdFALSE,portMAX_DELAY); 
        if(bits & DEVICE_CONNECTED_AP_BIT)
        {
            display_wifi_ap_connect_info_to_lcd(1);
        }
        else if(bits & DEVICE_DISCONNECTED_AP_BIT) 
        {
            display_wifi_ap_connect_info_to_lcd(2);
        }
        else if(bits & DEVICE_GET_IP_AP_BIT)
        {
            display_wifi_ap_connect_info_to_lcd(3);
        }
    }
}

附录:WIFI AP 模式代码整合

 bsp_wifi_ap.h:

#ifndef __BSP_WIFI_AP_H
#define __BSP_WIFI_AP_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_mac.h"
#include "esp_log.h"
#include "esp_netif_net_stack.h"
#include "esp_netif.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/sys.h"


void wifi_ap_test(void *pvParameters);

#endif

bsp_wifi_ap.c

#include"bsp_wifi_ap.h"
#include"bsp_delay.h"
#include"bsp_lcd_st7789v_spi.h"


static const char *TAG_AP = "WIFI_AP";
void wifi_ap_init(wifi_config_t *wifi_ap_cfg);
void display_wifi_ap_connect_info_to_lcd(uint8_t displayFlag);

//定义目标AP名称和密码
#define ESP_WIFI_AP_SSID      "XiaoHai@iPhone"  
#define ESP_WIFI_AP_PASSWD    "123456788"
#define ESP_WIFI_CHANNEL 5
#define ESP_MAX_STA_CONN_AP 5 //定义设备连接AP最大重连次数

//定义事件标志位
#define DEVICE_CONNECTED_AP_BIT     BIT0
#define DEVICE_DISCONNECTED_AP_BIT  BIT1
#define DEVICE_GET_IP_AP_BIT        BIT2

//存放WIFI AP 模式下客户端设备连接AP后的信息
typedef struct wifi_sta_connect_Info
{
    esp_ip4_addr_t dev_ip; //客户端设备连接AP后获取的IP
    uint8_t dev_mac[6]; //客户端设备MAC地址
    uint8_t ap_ssid[32]; //AP的名称
    uint8_t ap_password[64]; //AP的密码

}wifi_ap_connect_info;

wifi_ap_connect_info  wifi_ap_net_info={0}; 
static int s_retry_num = 0; //重连目标AP的次数
static EventGroupHandle_t wifi_event_group; //定义一个事件标志组,用于WIFI连接/断开的标志
uint8_t ap_lcd_display_buff[100]={0}; //定义LCD显示缓存

/*
函数功能:WIFI连接事件回调服务函数,由于处理特定的WIFI事件
函数形参:
        arg:传入网卡控制块
        event_base:WIFI 事件
        event_id:事件 ID
        event_data:事件数据
*/
static 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_AP_STACONNECTED) //有设备连接到到AP
    {
        wifi_event_ap_staconnected_t *eventData = (wifi_event_ap_staconnected_t *)event_data;
        memcpy(wifi_ap_net_info.dev_mac,eventData->mac,sizeof(eventData->mac));
        xEventGroupSetBits(wifi_event_group, DEVICE_CONNECTED_AP_BIT);
        ESP_LOGI(TAG_AP, "station "MACSTR" join, AID=%d",MAC2STR(eventData->mac), eventData->aid);
    }
    else if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED)  //有设备与AP断开连接
    {
        wifi_event_ap_staconnected_t *eventData = (wifi_event_ap_staconnected_t *)event_data;
        memcpy(wifi_ap_net_info.dev_mac,eventData->mac,sizeof(eventData->mac));
        ESP_LOGI(TAG_AP, "station "MACSTR" leave, AID=%d",MAC2STR(eventData->mac), eventData->aid);
        xEventGroupSetBits(wifi_event_group, DEVICE_DISCONNECTED_AP_BIT);
    }
    else if(event_base == IP_EVENT && event_id == IP_EVENT_AP_STAIPASSIGNED) //有设备连接到到AP并成功从AP分配到IP
    {
        ip_event_ap_staipassigned_t *eventData = (ip_event_ap_staipassigned_t *)event_data;
        memcpy(wifi_ap_net_info.dev_mac,eventData->mac,sizeof(eventData->mac));
        wifi_ap_net_info.dev_ip = eventData->ip;
        xEventGroupSetBits(wifi_event_group, DEVICE_GET_IP_AP_BIT);
        ESP_LOGI(TAG_AP, "DHCP server assigned IP to a client: MAC="MACSTR", IP="IPSTR"",MAC2STR(eventData->mac), IP2STR(&eventData->ip));
    }
    else
    {
        ESP_LOGI(TAG_AP,"Unexpected event ! event_id = %d \n",event_id);
    }
}


esp_err_t nvs_init(void)
{
    esp_err_t ret;
    ret = nvs_flash_init(); /* 初始化 NVS 第一次调用时,它会加载存储区域。如果存储区域有问题或不兼容,会抛出 ESP_ERR_NVS_NO_FREE_PAGES 或 ESP_ERR_NVS_NEW_VERSION_FOUND 错误。此时,我们会擦除存储并重新初始化。 */
    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();
    }
    return ret;
}

/*
函数功能:WIFI AP模式初始化
形    参:
        wifi_ap_cfg:WIFI的配置
返 回 值:无
*/
void wifi_ap_init(wifi_config_t *wifi_ap_cfg)
{ 
    ESP_LOGI(TAG_AP, "wifi_ap_init.....");
    //1.创建新的事件循环.
    ESP_ERROR_CHECK(esp_event_loop_create_default()); 
    //2.初始化WIFI连接/断开的标志事件组
    wifi_event_group = xEventGroupCreate();
    //3.注册事件ID和IP获取服务函数
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,ESP_EVENT_ANY_ID,&wifi_event_handler,NULL,NULL)); 
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,IP_EVENT_AP_STAIPASSIGNED,&wifi_event_handler,NULL,NULL)); 
    //4.网卡初始化.初始化底层TCP/IP堆栈
    ESP_ERROR_CHECK(esp_netif_init()); 
    //5.使用默认WiFi Station配置创建esp_netif对象,将netif连接到WiFi并注册默认WiFi处理程序。
    esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap(); 
    assert(ap_netif); //断言检查,确保程序在运行时满足特定的条件.
    //6.netif连接到WiFi并注册默认WiFi处理程序。
    esp_netif_set_default_netif(ap_netif);
    //7.初始化wifi配置参数为默认.
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 
    //8.为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API
    ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 
    ESP_LOGI(TAG_AP, "wifi init cfg !");
    //9.设置WIFI为AP模式
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_LOGI(TAG_AP, "wifi set ap mode !");
    //10.设置WIFI AP模式的配置
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, wifi_ap_cfg) );
    ESP_LOGI(TAG_AP, "wifi init ap finished !");
    //11.启动WIFI
    ESP_ERROR_CHECK(esp_wifi_start()); 
    ESP_LOGI(TAG_AP, "wifi start !");
    ESP_LOGI(TAG_AP, "wifi_init_softap finished. SSID:%s password:%s channel:%d",wifi_ap_cfg->ap.ssid,wifi_ap_cfg->ap.password,wifi_ap_cfg->ap.channel);
   
}   

/*
函数功能:WIFI AP模式连接AP测试
形    参:无
返 回 值:无
*/
void wifi_ap_test(void *pvParameters)
{
     nvs_init();
    uint8_t displayFlag=0;
    wifi_config_t wifi_ap_config = {
        .ap ={
            .ssid = ESP_WIFI_AP_SSID,
            .ssid_len = strlen(ESP_WIFI_AP_SSID),
            .channel = ESP_WIFI_CHANNEL,
            .password = ESP_WIFI_AP_PASSWD,
            .max_connection = ESP_MAX_STA_CONN_AP,
            .authmode = WIFI_AUTH_WPA2_PSK,
            .pmf_cfg.required = false,
        }
    };

    if (strlen(ESP_WIFI_AP_PASSWD) == 0) {
        wifi_ap_config.ap.authmode = WIFI_AUTH_OPEN;
    }
    memcpy(wifi_ap_net_info.ap_ssid,ESP_WIFI_AP_SSID,sizeof(ESP_WIFI_AP_SSID));
    memcpy(wifi_ap_net_info.ap_password,ESP_WIFI_AP_PASSWD,sizeof(ESP_WIFI_AP_PASSWD));
    st7789v_clearScreen(WHITE,USE_HORIZONTAL);
    wifi_ap_init(&wifi_ap_config);
    //*(uint8_t *)pvParameters = 1;
    display_wifi_ap_connect_info_to_lcd(4);
    while(1) 
    {
        //等待事件标志位:等待网络连接成功/失败。成功和失败的bits会在上面注册的wifi_event_handler函数中被设置。
        //xEventGroupWaitBits(事件组句柄,要等待的事件位,是否在函数返回前清除触发的标志位,是否等待所有指定的标志位,等待的时间(以系统滴答为单位) );
        EventBits_t bits = xEventGroupWaitBits(wifi_event_group,DEVICE_CONNECTED_AP_BIT | DEVICE_DISCONNECTED_AP_BIT | DEVICE_GET_IP_AP_BIT,pdTRUE,pdFALSE,portMAX_DELAY); 
        if(bits & DEVICE_CONNECTED_AP_BIT)
        {
            display_wifi_ap_connect_info_to_lcd(1);
        }
        else if(bits & DEVICE_DISCONNECTED_AP_BIT) 
        {
            display_wifi_ap_connect_info_to_lcd(2);
        }
        else if(bits & DEVICE_GET_IP_AP_BIT)
        {
            display_wifi_ap_connect_info_to_lcd(3);
        }
    }
}


/*
函数功能:WIFI连接AP信息显示
形    参:
        displayMode:
                     1:有设备连接到AP!  2:有设备从AP上离开 3:有设备连接到AP,并已分配到ip! 4:显示AP名称和密码
返 回 值:无
*/
void display_wifi_ap_connect_info_to_lcd(uint8_t displayMode)
{
    static uint8_t old_displayMode = 0;
    if(displayMode != old_displayMode)
    {
        st7789v_clearScreen(WHITE,USE_HORIZONTAL);
    }
    if(displayMode == 1) //有设备连接到AP!
    {
        old_displayMode = 1;
        st7789v_displayString(10,10,(uint8_t *)" WIFI AP TEST :",RED,WHITE,24,0,USE_HORIZONTAL);
        st7789v_displayString(10,40,(uint8_t *)"One device connect to ap !",BLUE,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_SSID: %-20s",wifi_ap_net_info.ap_ssid);
        st7789v_displayString(10,80,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_PWD: %-20s",wifi_ap_net_info.ap_password);
        st7789v_displayString(10,100,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"DEV_MAC: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(wifi_ap_net_info.dev_mac));
        st7789v_displayString(10,120,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
    }
    else if(displayMode == 2)//有设备从AP上离开
    {
        old_displayMode = 2;
        st7789v_displayString(10,10,(uint8_t *)" WIFI AP TEST :",RED,WHITE,24,0,USE_HORIZONTAL);
        st7789v_displayString(10,40,(uint8_t *)"One device leave ap !",RED,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_SSID: %-20s",ESP_WIFI_AP_SSID);
        st7789v_displayString(10,80,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_PWD: %-20s",ESP_WIFI_AP_PASSWD);
        st7789v_displayString(10,100,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"DEV_MAC: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(wifi_ap_net_info.dev_mac));
        st7789v_displayString(10,120,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
    }
    else if(displayMode == 3) //有设备连接到AP,并已分配到ip!
    {
        old_displayMode = 8;
        st7789v_displayString(10,10,(uint8_t *)" WIFI AP TEST :",RED,WHITE,24,0,USE_HORIZONTAL);
        st7789v_displayString(10,40,(uint8_t *)"Client get ip from DHCP !",BLUE,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_SSID: %-20s",ESP_WIFI_AP_SSID);
        st7789v_displayString(10,80,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_PWD: %-20s",ESP_WIFI_AP_PASSWD);
        st7789v_displayString(10,100,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"DEV_IP: %d.%d.%d.%d",IP2STR(&wifi_ap_net_info.dev_ip));
        st7789v_displayString(10,120,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"DEV_MAC: %02x:%02x:%02x:%02x:%02x:%02x",MAC2STR(wifi_ap_net_info.dev_mac));
        st7789v_displayString(10,140,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
    }
    else if(displayMode == 4)//显示AP名称和密码
    {
        old_displayMode = 4;
        st7789v_displayString(10,10,(uint8_t *)" WIFI AP TEST :",RED,WHITE,24,0,USE_HORIZONTAL);
        st7789v_displayString(10,40,(uint8_t *)"Watting device to connect ap!",RED,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_SSID: %-20s",ESP_WIFI_AP_SSID);
        st7789v_displayString(10,80,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
        sprintf(ap_lcd_display_buff,"AP_PWD: %-20s",ESP_WIFI_AP_PASSWD);
        st7789v_displayString(10,100,ap_lcd_display_buff,BLACK,WHITE,16,0,USE_HORIZONTAL);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 22.04 一键部署MinerU1.1.0

MinerU MinerU是一款将PDF转化为机器可读格式的工具&#xff08;如markdown、json&#xff09;&#xff0c;可以很方便地抽取为任意格式。 MinerU诞生于书生-浦语的预训练过程中&#xff0c;我们将会集中精力解决科技文献中的符号转化问题&#xff0c;希望在大模型时代为科技发…

AI工作流+专业知识库+系统API的全流程任务自动化

我有点悲观&#xff0c;甚至很沮丧&#xff0c;因为AI留给普通人的机会不多了&#xff0c;这既是人类之间权力的斗争&#xff0c;也是硅基生命和碳基生命的斗争。AI自动化是无法避免的趋势&#xff0c;如果人类不能平权&#xff0c;那就只能跪下接受审判。 通过整合AI工作流、专…

2026考研趋势深度解析:政策变化+高效工具指南

2026考研深度解析&#xff1a;趋势洞察高效工具指南&#xff0c;助你科学备战上岸 从政策变化到工具实战&#xff0c;这份千字攻略解决99%考生的核心焦虑 【热点引入&#xff1a;考研赛道进入“高难度模式”】 2025年全国硕士研究生报名人数突破520万&#xff0c;报录比预计扩…

javacv将mp4视频切分为m3u8视频并播放

学习链接 ffmpeg-demo 当前对应的 gitee代码 Spring boot视频播放(解决MP4大文件无法播放)&#xff0c;整合ffmpeg,用m3u8切片播放。 springboot 通过javaCV 实现mp4转m3u8 上传oss 如何保护会员或付费视频&#xff1f;优酷是怎么做的&#xff1f; - HLS 流媒体加密 ffmpe…

二叉树(数据结构)

二叉树 二叉树也是用过递归定义的结构 先序遍历又称前序遍历 ​​ ​​ 按照先序遍历的方法去手算处理这个二叉树 ​​ 先A B C 再 A B D E C&#xff08;也就是把B换成BDE再放进去&#xff09; 再 A B D E C F 看这个插入的方法要掌握像二叉树这样向一个…

如何利用国内镜像从huggingface上下载项目

1、利用镜像快速下载项目 在huggingface上下载模型时速度太慢&#xff0c;可以用下面的方法 pip install -U huggingface_hub pip install huggingface-cliexport HF_ENDPOINThttps://hf-mirror.comhuggingface-cli download --resume-download shenzhi-wang/Llama3-8B-Chine…

Http升级为Https - 开发/测试服环境

1.应用场景 主要用于开发/测试服环境将http升级为https, 防止前端web(浏览器)出现Mixed Content报错; 2.学习/操作 1.文档阅读 deepseek 问答; 2.整理输出 报错信息: Mixed Content: The page at <URL> was loaded over HTTPS, but requested an insecure XMLHttpRequ…

网页制作01-html,css,javascript初认识のhtml的基本标记

一、 Html简介 英文全称是 hyper text markup language,超文本标记语言,是全球广域网上描述网页内容和外观的标准. Html作为一款标记语言,本身不能显示在浏览器中.标记语言经过浏览器的解释和编译,才能正确地反映html标记语言的内容. 1.html 的基本标记 1&#xff09;头部标…

分布式 IO 模块:水力发电设备高效控制的关键

在能源领域不断追求高效与可持续发展的今天&#xff0c;水力发电作为一种清洁、可再生的能源形式&#xff0c;备受关注。而要实现水力发电设备的高效运行&#xff0c;精准的控制技术至关重要。分布式 IO 模块&#xff0c;正悄然成为水力发电设备高效控制的核心力量。 传统挑战 …

【前端框架】vue2和vue3的区别详细介绍

Vue 3 作为 Vue 2 的迭代版本&#xff0c;在性能、语法、架构设计等多个维度均有显著的变革与优化。以下详细剖析二者的区别&#xff1a; 响应式系统 Vue 2 实现原理&#xff1a;基于 Object.defineProperty() 方法实现响应式。当一个 Vue 实例创建时&#xff0c;Vue 会遍历…

使用linux脚本部署discuz博客(详细注释版)

使用脚本部署一个discuzz项目 1.显示当前环境状态 防火墙状态 selinux状态 httpd状态 由上可知&#xff0c;虚拟机已处于最初始状态 2.脚本编写 #!/bin/bash #这是一个通过脚本来部署discuzz博客 firewalld关闭 systemctl stop firewalld if [ $? -eq 0 ];then echo "…

【代码审计】-Tenda AC 18 v15.03.05.05 /goform接口文档漏洞挖掘

路由器&#xff1a;Tenda AC 18 v15.03.05.05 固件下载地址&#xff1a;https://www.tenda.com.cn/material?keywordac18 1./goform/SetSpeedWan 接口文档&#xff1a; formSetSpeedWan函数中speed_di参数缓冲区溢出漏洞&#xff1a; 使用 binwalk -eM 解包固件&#xff0c…

正式页面开发-登录注册页面

整体路由设计&#xff1a; 登录和注册的切换是切换组件或者是切换内容&#xff08;v-if和 v-else)&#xff0c;因为点击两个之间路径是没有变化的。也就是登录和注册共用同一个路由。登录是独立的一级路由。登录之后进到首页&#xff0c;有三个大模块&#xff1a;文章分类&…

Unity 位图字体

下载Bitmap Font Generator BMFont - AngelCode.com 解压后不用安装直接双击使用 提前设置 1、设置Bit depth为32 Options->Export options 2、清空所选字符 因为我们将在后边导入需要的字符。 Edit->Select all chars 先选择所有字符 Edit->Clear all chars i…

双重差分学习笔记

双重差分适用的研究场景&#xff1a; 研究某项政策或者冲击造成的影响 例如&#xff0c;某某小学在2024.12.12日颁布了小红花激励措施&#xff0c;我们要研究这项措施对学生成绩的影响&#xff0c;此时&#xff0c;就可以使用双重差分模型。 双重差分适用的数据类型&#xf…

项目设置内网 IP 访问实现方案

在我们平常的开发工作中&#xff0c;项目开发、测试完成后进行部署上线。比如电商网站、新闻网站、社交网站等&#xff0c;通常对访问不会进行限制。但是像企业内部网站、内部管理系统等&#xff0c;这种系统一般都需要限制访问&#xff0c;比如内网才能访问等。那么一个网站应…

数仓搭建(hive):DWB层(基础数据层)

维度退化: 通过减少表的数量和提高数据的冗余来优化查询性能。 在维度退化中&#xff0c;相关的维度数据被合并到一个宽表中&#xff0c;减少了查询时需要进行的表连接操作。例如&#xff0c;在销售数据仓库中&#xff0c;客户信息、产品信息和时间信息等维度可能会被合并到一…

多模态特征提取与融合助力高光谱+LiDAR数据分类性能飞跃

目录 论文解读 总体架构 CMIIE 模块工作模式 MLFFC模块工作模式 论文解读 提出了一种新的多模态特征提取模块CMIIE,可以捕获高光谱和LiDAR数据之间的互补信息。设计了一个多层特征融合分类模块MLFFC,通过对不同层级的特征进行融合来提高分类性能。使用对抗学习策略来指导网…

Flutter 正在推进全新 PlatformView 实现 HCPP, 它又用到了 Android 上的什么黑科技

跨平台开发里的 PlatformView 实现一直是一个经久不衰的话题&#xff0c;在之前的 《深入 Flutter 和 Compose 的 PlatformView 实现对比》 我们就详细聊过 Flutter 和 Compose 在 PlatformView 实现上的异同之处&#xff0c;也聊到了 Compose 为什么在相同实现上对比 Flutter …

Qt/C++面试【速通笔记一】

Qt 信号与槽机制 什么是信号&#xff08;Signal&#xff09;和槽&#xff08;Slot&#xff09;&#xff1f; 在Qt中&#xff0c;信号&#xff08;Signal&#xff09;和槽&#xff08;Slot&#xff09;是实现对象之间通信的一种机制。信号是对象在某些事件发生时发出的通知&…