1. 简介
前面一篇讲了WiFi的基站模式,演示了怎么编程连接AP,所以这一篇讲一讲AP模式,ESP32作AP,让其他的设备连接自己。
1.1 DHCP
这里需要补充一个知识点——DHCP服务器。当基站连接一个AP时,会被分配一个IP,那么这个IP一般就是通过AP中的DHCP服务器来分配的。
DHCP(Dynamic Host Configuration Protocol),全称动态主机配置协议,其可以实现网络动态合理地分配IP地址给主机使用。它主要的特定是可以统一管理、分配IP地址;同时提出了IP地址租期的概念,使得IP地址能更高效使用。
1.2 信道
配置AP时,可能会涉及到配置信道,信道通俗讲就是不同的频率段。像2.4G频段,一共有14个信道,每个信道的频宽为22MHz,正常来说只有中间的20MHz是能用的,其余的2MHz是保险频段而已。
AP能配置的信道数是跟它支持的频宽有关的,像ESP32最大频宽是40MHz,所以它可以配置2个信道。一个要注意的点是,相邻的信道其实是有重叠的,所以设置的时候我们最好选择互不重叠的信道;这种信道有4组,1/6/11、2/7/12、3/8/13和4/9/14。
另外一个要注意的点是,每个国家开放给民用的信道是不同的;像中国的话,支持1-13信道。
1.3 编程流程
1. 初始化阶段
- 调用 esp_event_loop_create() 创建一个系统事件任务,并初始化应用程序事件的回调函数;
- 调用 esp_netif_init() 创建一个 LwIP 核心任务,并初始化 LwIP 相关工作;
- 调用 esp_netif_create_default_wifi_sta() 创建有TCP/IP堆栈的默认网络接口实例绑定station;
- 调用函数 esp_wifi_init() 创建 Wi-Fi 驱动程序任务,并初始化 Wi-Fi 驱动程序;
2. 配置阶段
- 调用函数 esp_wifi_set_mode() 将 Wi-Fi 模式配置为 station 模式;
- 调用 esp_wifi_set_protocol() 设置 WiFi 支持的协议(可选,默认是全开);
- 调用 esp_wifi_set_bandwidth() 设置 WiFi 支持的带宽(可选);
- 调用 esp_wifi_set_country_code() 设置国家代码(可选);
- 调用函数 esp_wifi_set_config() 配置AP;
3. 启动阶段
- 调用 esp_wifi_start() 启动 Wi-Fi 驱动程序;
- 调用 esp_event_handler_instance_register() 注册对应的事件回调到应用当中;
4. 连接阶段
- WIFI_EVENT_AP_STACONNECTED 事件触发,应用回调作处理;
5. 断开阶段
-
WIFI_EVENT_AP_STADISCONNECTED 事件触发,应用回调作处理。
2. 例程
这个例程会配置ESP32作为AP,然后使用手机去连接ESP32。
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "nvs_flash.h"#include "lwip/err.h"
#include "lwip/sys.h"#include <string.h>#define TAG "app"
#define AP_SSID "ESP32"
#define AP_PASS "12345678"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_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_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d, reason=%d", MAC2STR(event->mac), event->aid, event->reason);}
}int app_main()
{/* 初始化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());ESP_ERROR_CHECK(nvs_flash_init());}/* 初始化WiFi协议栈 */ESP_ERROR_CHECK(esp_netif_init());ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_create_default_wifi_ap();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));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 = AP_SSID,.ssid_len = strlen(AP_SSID),.channel = 1,.password = AP_PASS,.max_connection = 10,.authmode = WIFI_AUTH_WPA_WPA2_PSK,},};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));ESP_ERROR_CHECK(esp_wifi_start());ESP_LOGI(TAG, "WiFi AP running at SSID: %s, password:%s", AP_SSID, AP_PASS);return 0;
}
总体的编程流程跟前面的介绍是大差不差的,这里主要讲一下配置AP的这个结构体;下面只挑几个常用的讲。
typedef struct {uint8_t ssid[32];uint8_t password[64];uint8_t ssid_len;uint8_t channel;wifi_auth_mode_t authmode;uint8_t ssid_hidden;uint8_t max_connection;uint16_t beacon_interval;uint8_t csa_count;uint8_t dtim_period;wifi_cipher_type_t pairwise_cipher;bool ftm_responder;wifi_pmf_config_t pmf_cfg;wifi_sae_pwe_method_t sae_pwe_h2e;
} wifi_ap_config_t;
- ssid:SSID,就是我们所说的WiFi名;
- password:WiFi密码;
- ssid_len:SSID长度;
- channel:信道,默认为1,设置时最好查询自己国家支持的信道;
- authmode:授权模式,如果不需要密码就用 WIFI_AUTH_OPEN,一般的话就选 WIFI_AUTH_WPA_WPA2_PSK 可以覆盖常用的几种授权方式;
- ssid_hidden:是否隐藏SSID,使能之后AP就不会广播自己的SSID,进行AP扫描的时候就扫不出来了;
- max_connection:最大连接数,默认是10,最大是15;
- beacon_interval:beacon 间隔,范围为100 ~ 60000ms,默认为100ms;这个就是AP广播SSID的包间隔。
当基站成功连接时,回调函数会接收到对方的MAC地址,及其他基本信息;在基站断开时也会返回前面的信息。