第4章 WiFi基础:Station模式、AP模式、WiFi扫描与连接流程
说到WiFi,很多刚入行的朋友容易把概念搞混。其实WiFi的工作模式没那么玄乎,说白了就两种:一种是去连别人,一种是让别人来连你。嗯,这就是我们今天要聊的Station模式和AP模式。
4.1 Station模式——咱们的设备去连路由器
Station模式,也叫STA模式。这是最常用的模式。我们的扫地机器人连上家里的路由器,用的就是STA模式。
我刚开始做WiFi项目时,总觉得STA模式就是配个SSID和密码就完事了。后来踩了不少坑才发现,事情没那么简单。
核心要点:STA模式下,设备作为客户端,主动连接一个已有的WiFi热点(AP)。连接成功后,设备会获得一个IP地址,然后就能上网了。
在ESP32上,初始化STA模式的代码大概长这样:
#include "esp_wifi.h"
#include "esp_event.h"
void wifi_init_sta(void)
{
// 初始化网络接口
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_sta();
// 初始化WiFi
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
// 配置STA模式
wifi_config_t wifi_config = {
.sta = {
.ssid = "MyHomeWiFi",
.password = "password123"
},
};
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
esp_wifi_start();
}
你看,代码本身不复杂。但实际项目中,我遇到过一个问题:WiFi连接成功后,设备突然断连了。排查了半天,发现是路由器开启了MAC地址过滤,而我的设备MAC地址没在白名单里。嗯,这种坑防不胜防。
4.2 AP模式——让设备变成一个小热点
AP模式,就是让我们的设备自己变成一个热点。其他设备(比如手机)可以连上来。
你想想看,扫地机器人第一次配网时,手机怎么知道该连哪个WiFi?其实就是机器人先开启AP模式,手机连上这个热点,然后通过手机把家里的WiFi信息告诉机器人。这就是所谓的智能配网。
我的经验:AP模式下,热点名称(SSID)最好带上设备标识,比如"RoboCleaner_XXXX"。这样用户在手机上一眼就能认出自己的设备。我曾经见过一个产品,所有设备的热点名都一样,结果用户配网时连错了邻居家的设备……
AP模式的代码示例:
void wifi_init_ap(void)
{
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
wifi_config_t wifi_config = {
.ap = {
.ssid = "RoboCleaner_AP",
.ssid_len = strlen("RoboCleaner_AP"),
.password = "12345678",
.max_connection = 4,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
},
};
esp_wifi_set_mode(WIFI_MODE_AP);
esp_wifi_set_config(WIFI_IF_AP, &wifi_config);
esp_wifi_start();
}
这里有个细节:AP模式下,密码长度不能少于8位。这是WiFi协议规定的。我见过有人设了个6位密码,结果死活连不上,还以为是代码写错了。
4.3 WiFi扫描——先看看周围有哪些热点
WiFi扫描,就是让设备去"听"一下周围有哪些WiFi信号。这个功能在配网时特别有用——手机把扫描到的热点列表发给用户,用户从中选择自家的WiFi。
扫描分为两种:
| 扫描类型 | 说明 | 耗时 |
|---|---|---|
| 主动扫描 | 设备主动发送探测请求帧,AP收到后会回复 | 较快,约1-3秒 |
| 被动扫描 | 设备监听AP定期发送的信标帧 | 较慢,约3-10秒 |
实际项目中,我一般用主动扫描。速度快,用户体验好。但要注意:主动扫描会发送广播帧,有些路由器会把它当成攻击行为。我之前就遇到过,某品牌路由器直接把我的设备拉黑了……
扫描的代码实现:
void wifi_scan(void)
{
uint16_t ap_count = 0;
wifi_ap_record_t ap_info[20];
esp_wifi_scan_start(NULL, true); // true表示阻塞等待扫描完成
esp_wifi_scan_get_ap_records(&ap_count, ap_info);
for (int i = 0; i < ap_count; i++) {
printf("SSID: %s, RSSI: %d, Channel: %d\n",
ap_info[i].ssid,
ap_info[i].rssi,
ap_info[i].primary);
}
}
注意:扫描时设备会短暂断开当前WiFi连接。如果你的设备正在传输数据,最好先暂停传输,等扫描完成后再恢复。我曾经因为这个原因,导致扫地机器人一边扫地图一边断网,结果地图数据丢了半张……
4.4 连接流程——从扫描到连上的完整步骤
好了,我们把前面几个知识点串起来。一个完整的WiFi连接流程是这样的:
- 初始化WiFi:设置模式(STA/AP/混合模式)
- 扫描热点:获取周围AP列表
- 选择目标:根据SSID匹配要连接的热点
- 配置认证:填入SSID和密码
- 发起连接:调用连接API
- 等待事件:监听连接成功或失败的回调
- 获取IP:连接成功后,通过DHCP获取IP地址
在ESP32上,连接事件的处理是这样的:
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(); // 开始连接
}
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
printf("WiFi连接成功!\n");
}
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;
printf("获取到IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
}
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
printf("WiFi断开了,尝试重连...\n");
esp_wifi_connect(); // 自动重连
}
}
这里有个关键点:连接失败后一定要做重连处理。WiFi信号不稳定是常态,扫地机器人可能在墙角、床底等信号差的地方工作。我习惯在断连事件里加一个重试计数器,连续失败5次就放弃,避免无限重试浪费电量。
避坑指南:我曾经遇到过一个问题——设备连上WiFi后,IP地址获取失败。查了半天,发现是DHCP服务器响应太慢,而我的代码在连接成功后立即开始发送数据,结果数据包全丢了。解决方案是:等GOT_IP事件触发后再开始通信。
4.5 混合模式——既要连网又要被连
有些场景下,设备需要同时工作在STA和AP模式。比如扫地机器人正常工作时连家里的WiFi(STA模式),同时开启一个AP模式用于调试或紧急配网。
这种模式叫混合模式(WIFI_MODE_APSTA)。代码上就是把前面两个配置合在一起:
esp_wifi_set_mode(WIFI_MODE_APSTA);
// 分别配置AP和STA
wifi_config_t ap_config = { /* ... */ };
wifi_config_t sta_config = { /* ... */ };
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
esp_wifi_start();
注意:混合模式下,AP和STA通常使用同一个WiFi射频。这意味着它们共享天线和信道。如果STA连接的信道是6,AP也只能用信道6。我见过有人强行把AP设成信道11,结果STA连不上网了……
好了,这一章的内容就这些。WiFi基础其实不难,但细节很多。下一章我们会聊WiFi配网方式,到时候会用到今天讲的这些知识。记住一句话:WiFi连接的本质,就是让两个设备在同一个信道上,用同一个协议说话。