从零开始学ESP32:(二) 开启ESP32WIFI -STA和AP模式共存

从零开始学ESP32:个人笔记记录:

芯片型号: ESP32
网络环境支持:LWIP
IDF.PY-SDK: ESP-IDF v4.3
芯片功能: 支持STA/AP网络共存模式:

工程: esp-idf/examples/get-started/hello_world
例程: esp-idf/examples/wifi/getting_started/station/main


基本头文件:

#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"

Cmakelisys.txt配置

idf_component_register(SRCS "test_wlan.c"
                    INCLUDE_DIRS "."
                    INCLUDE_DIRS "$ENV{IDF_PATH}/components/spi_flash/include"
                    INCLUDE_DIRS "$ENV{IDF_PATH}/components/nvs_flash/include"
                    )

component.mk配置

COMPONENT_ADD_INCLUDEDIRS := .

基本实现代码和解析:

#define WIFI_CONNECTED_BIT          BIT0
#define WIFI_FAIL_BIT               BIT1
#define EXAMPLE_ESP_MAXIMUM_RETRY  10

#define AP_WIFI_SSID 				"ESP32-AP-MODU" //创建出来的AP模式WIFI(热点)
#define AP_WIFI_PASS 				"123456789"     //AP模式密码

#define STA_WIFI_SSID				"my_wifi"    //连接路由WIFI的账号
#define STA_WIFI_PASS   			"123456789"  //连接路由WIFI的密码

//重封装打印
#define D_BUG(frtc, frtl...)    \ 
	    do{ ESP_LOGI( __FUNCTION__ , frtc,##frtl); } while(0) 

static EventGroupHandle_t s_wifi_event_group;  //全局事件句柄



void W_staDisConnectedEv(void)
{
    if(s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
    {
        esp_wifi_connect();
        s_retry_num++;
        D_BUG("retry to connect to the AP \r\n");
    }
    else
    {
        xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
    }
    D_BUG("connect to the AP fail \r\n");
    return ;
}


void W_apStaConnectedEv( void* event_data  )
{
    wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;

    D_BUG("station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid);
    /* 一台设备连接到ESP32 */
}

void W_apStaDisConnectEv( void* event_data )
{
    wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
    D_BUG("station "MACSTR" leave, AID=%d", MAC2STR(event->mac), event->aid); 
    /* 一台设备离开了ESP32 */
}


void W_ipGotHostAddr( void* event_data )
{
    ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
    D_BUG("got ip:" IPSTR, IP2STR(&event->ip_info.ip) );
    s_retry_num = 0;
    xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}

/*************************
 * 函数;W_eventHandler 
 * 
 * 
 * 说明: 事件处理回调函数
 *  */
 
static void W_eventHandler( void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data  )
{
    /* 事件剥离 */
    if( event_base == WIFI_EVENT )
    {
        switch ( event_id )
        {
            case WIFI_EVENT_STA_START:          esp_wifi_connect();                break; // STA START
            case WIFI_EVENT_STA_STOP:           D_BUG("STA stop\r\n"); break; // STA STOP 
            case WIFI_EVENT_STA_DISCONNECTED:   W_staDisConnectedEv();             break; // STA RECONECT 
            case WIFI_EVENT_AP_START:           D_BUG("AP start\r\n"); break; // AP  START 
            case WIFI_EVENT_AP_STOP:            D_BUG("AP stop\r\n");  break; // AP  STOP
            case WIFI_EVENT_AP_STACONNECTED:    W_apStaConnectedEv( event_data );  break; // 一台设备连接AP
            case WIFI_EVENT_AP_STADISCONNECTED: W_apStaDisConnectEv(event_data );  break; // 一台设备断开AP                             
            default:  break;
        }
    }
    else if( event_base == IP_EVENT )  // 路由事件ID 组
    {
        switch ( event_id )
        {
            case IP_EVENT_STA_GOT_IP:        W_ipGotHostAddr(event_data);       break; //获取到指定IP
            case IP_EVENT_STA_LOST_IP:       D_BUG("AP stop\r\n");  break;
            case IP_EVENT_AP_STAIPASSIGNED:  D_BUG("AP stop\r\n");  break;
            default:  break;
        }
    }
    return ;
}



/*******************************
 * 函数: WLAN_netConfDev
 *
 * 
 * 说明: WIFI - AP -STA 共存模式同时开启函数
 *  */
void WLAN_netConfDev(char * ssid_sta , char * pwssd_sta )
{
	int  STA_MAX_RETRY_NUM = 10;  // sta 模式下最大连接次数
    int  AP_WIFI_CHANNEL   = 13;  // AP 模式下得通道
    int  AP_MAX_STA_CONN   = 3;   // AP支持最大STA连接数 - 允许最大连接数量
    
    esp_event_handler_instance_t instance_any_id = {0};  //处理ID 实例句柄
    esp_event_handler_instance_t instance_got_ip = {0};  //处理IP 实例句柄
    
    s_wifi_event_group = xEventGroupCreate();            // 创建全局事件 
    ESP_ERROR_CHECK(esp_netif_init());                   // 网络子系统底层初始化
    ESP_ERROR_CHECK(esp_event_loop_create_default());    // 创建默认循环发送队列
    esp_netif_create_default_wifi_sta();		         //创建网络配置-默认是STA 
    
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); // WIFI设备配置
    ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 			     // WIFI设备初始化
   
    /* 创建ID 事件实例回调 
     * WIFI_EVENT       = WIFI事件
     * ESP_EVENT_ANY_ID = 监听所有得ID事件
     * W_eventHandler   = 回调函数
     * NULL
     * instance_any_id  = 处理ID实例句柄
     * */
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &W_eventHandler,
                                                        NULL,
                                                        &instance_any_id));
    /* 创建IP 事件实例回调  
     * WIFI_EVENT          = WIFI事件
     * IP_EVENT_STA_GOT_IP = STA事件
     * W_eventHandler      = 回调函数
     * NULL
     * instance_any_id  = 处理IP实例句柄
     * */
    
    ESP_ERROR_CHECK( esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &W_eventHandler,
                                                        NULL,
                                                        &instance_got_ip) );
                                                     
/* 创建 并 初始化STA对象 */
	    wifi_config_t wifi_configSta = {
        .sta = 
        {
	        /*ssid 和 password 成员在结构体里面是数组,不能直接将指针丢给它 
	         * 在外面赋值 
	         * strcpy( (char *) wifi_configSta.sta.ssid     ,  STA_WIFI_SSID);
	         * strcpy( (char *) wifi_configSta.sta.password ,  STA_WIFI_PASS);
	        */
          // .ssid     = STA_WIFI_SSID;
         // .password = STA_WIFI_PASS;				
	     .threshold.authmode = WIFI_AUTH_WPA2_PSK,
         .pmf_cfg = {
                .capable = true,
                .required = false,
            },
        },
    };
   strcpy( (char *) wifi_configSta.sta.ssid     ,  ssid_sta );
   strcpy( (char *) wifi_configSta.sta.password ,  pwssd_sta);
	/* 创建 并 初始化AP对象 */
    wifi_config_t wifi_configAP = {
        .ap = 
        {
            .ssid           = AP_WIFI_SSID,
            .ssid_len       = strlen( AP_WIFI_SSID ),
            .channel        = AP_WIFI_CHANNEL,
            .password       = AP_WIFI_PASS,
            .max_connection = AP_MAX_STA_CONN,
            .authmode       = WIFI_AUTH_WPA_WPA2_PSK,
        }
    };

/*** 
 * 注意: 将两个成员合成一个结构体里面然后 进行配置的时候,是无效的
 * 必须是STA 和 AP 各自一个结构体成员
 *  */
    // 设置WIFI为 AP-STA 共存模式
    ESP_ERROR_CHECK(esp_wifi_set_mode( WIFI_MODE_APSTA) );
	// 设置AP模式配置
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP , &wifi_configAP) );
	// 设置STA模式配置
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_configSta) );

    ESP_ERROR_CHECK(esp_wifi_start() ); 
    D_BUG("wifi_init_sta finished.\r\n");
    /* 等待全局事件发生 -- 发生对应事件就等于完成一个动作 */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
                                            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
                                            pdFALSE,
                                            pdFALSE,
                                            portMAX_DELAY);
            
    if (bits & WIFI_CONNECTED_BIT) 
    {
        D_BUG("connected to ap SSID:%s password:%s \r\n",ssid, pwssd);
    }
    else if (bits & WIFI_FAIL_BIT) 
    {
        D_BUG("Failed to connect to SSID:%s, password:%s \r\n",ssid, pwssd);
    } 
    else 
    {
        D_BUG("UNEXPECTED EVENT \r\n");
    }

/* 清除当前申请的设备句柄 */
    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);
}



/* 主函数进行调用 */
int app_main( void )
{
	WLAN_netConfDev( STA_WIFI_SSID ,  STA_WIFI_PASS );
}



/* 完 */

额外提及一下设置AP的地址和网关,子网掩码等等信息 参考下面


void W_setApDhcpInfo()
{
	tcpip_adapter_ip_info_t  apNetConfInfo  = {0};
	//初始化网络和DHCP有关内存,必须要提前执行这个API 不然下面操作直接让设备重启
	tcpip_adapter_init();  
	// 将AP模式的DHCP 模式先关闭
	tcpip_adapter_dhcps_stop ( TCPIP_ADAPTER_IF_AP );
	//将对应的地址转成对应的字节序, 要注意apNetConfInf成员是结构体嵌套结构体,才是数组
	//
	IP4_ADDR( &apNetConfInfo.ip      , 192 , 168 , 1   , 1);  //设置IP
	IP4_ADDR( &apNetConfInfo.gw      , 192 , 168 , 1   , 1);  //设置网关
	IP4_ADDR( &apNetConfInfo.netmask , 255 , 255 , 255 , 0);  //设置子网掩码
	
	tcpip_adapter_set_ip_info( TCPIP_ADAPTER_IF_AP , &apNetConfInfo ); //设置IP信息
	
	tcpip_adapter_dhcps_stop(  TCPIP_ADAPTER_IF_AP ); //重新启动AP模式 DHCP 
}

这个函数可以上面的 AP/STA 模式启动之后执行 

成功之后正常情况是:
连接上当前路由的WIFI 并且打印处对应的IP
然后使用手机搜索WIFI的时候会发现多出一个$(AP_WIFI_SSID)名称的热点。


说明:笔记使用-记录(抄袭我就吊你 J J )
关注微信公众号 一起学习 ( 技术Code城 )

你可能感兴趣的:(ESP32,c语言)