3、Wi-Fi协议详解:从标准演进到ESP实战
Wi-Fi,说白了就是物联网设备最常用的“联网入口”。我做了这么多年嵌入式,碰到的项目里十有八九都离不开它。这一章咱们就把Wi-Fi的来龙去脉、入网流程,以及ESP8266/ESP32怎么玩转它,一次性讲透。
3.1 Wi-Fi标准演进:802.11 b/g/n/ac/ax
Wi-Fi标准从1997年诞生到现在,一路迭代。我刚开始做项目那会儿,主流还是802.11b,速率只有11Mbps。放到今天,连个固件OTA都嫌慢。
下面这张表,是我个人习惯用来给团队新人做培训的,一目了然:
| 标准 | 频段 | 最大速率 | 关键特性 | 物联网适用性 |
|---|---|---|---|---|
| 802.11b | 2.4 GHz | 11 Mbps | DSSS调制,兼容性好 | 极低功耗场景,已淘汰 |
| 802.11g | 2.4 GHz | 54 Mbps | OFDM调制,向下兼容b | 老旧设备兼容 |
| 802.11n | 2.4/5 GHz | 600 Mbps | MIMO,HT40信道绑定 | 当前物联网主力 |
| 802.11ac | 5 GHz | 6.9 Gbps | MU-MIMO,256-QAM | 高带宽视频传输 |
| 802.11ax (Wi-Fi 6) | 2.4/5/6 GHz | 9.6 Gbps | OFDMA,TWT节能 | 大规模高密部署 |
核心观点:物联网设备选型,802.11n(Wi-Fi 4)目前性价比最高。802.11ax虽然好,但芯片成本和功耗对大部分传感器节点来说还是偏高。
为什么会这样?你想想看,一个温度传感器每隔5分钟上报一次数据,每次就几十个字节。802.11n的150Mbps对它来说已经绰绰有余。我去年做一个智能楼宇项目,用了50多个ESP32节点,全部跑在802.11n 2.4GHz频段,稳得很。
但要注意,802.11ac只支持5GHz频段。5GHz穿墙能力差,距离稍远信号就掉得厉害。我曾经在一个仓库项目里踩过这个坑——设备离AP隔了两堵墙,死活连不上。后来全部换回2.4GHz的802.11n才解决。
3.2 Wi-Fi入网流程:Station模式与AP模式
Wi-Fi设备入网,说白了就两种角色:Station(站点)和AP(接入点)。
Station模式,就是设备去连接别人。家里的手机连路由器,就是Station模式。物联网设备大部分时间都跑在这个模式下。
AP模式,就是设备自己当热点,让别人来连。比如你买了个智能插座,第一次配置时,它自己开个热点,你用手机连上去给它配Wi-Fi密码。
下面这张图,是我画的一个典型入网流程:
实战技巧:ESP32在Station模式下,建议先调用WiFi.scanNetworks()获取可用AP列表,再根据信号强度(RSSI)选择最优AP连接。不要硬编码SSID,否则换环境就抓瞎。
AP模式呢?流程刚好反过来。设备自己开热点,手机连上去,然后通过HTTP或UDP把Wi-Fi密码发给设备。设备收到后,再切回Station模式去连路由器。
嗯,这里要注意一个细节:AP模式下,设备通常只开一个简单的Web服务器,监听80端口。我习惯用ESPAsyncWebServer库,比原生的WebServer库性能好不少,尤其是在处理JSON数据时。
3.3 ESP8266/ESP32实战:Wi-Fi连接与配置
好了,理论讲完,咱们直接上代码。ESP8266和ESP32的Wi-Fi API基本一致,下面这段代码是我项目里常用的模板:
#include <WiFi.h>
// 配置Wi-Fi凭据
const char* ssid = "Your_SSID";
const char* password = "Your_PASSWORD";
void setup() {
Serial.begin(115200);
delay(1000);
// 设置Wi-Fi为Station模式
WiFi.mode(WIFI_STA);
// 开始连接
WiFi.begin(ssid, password);
Serial.print("正在连接Wi-Fi");
// 等待连接,超时30秒
int timeout = 30;
while (WiFi.status() != WL_CONNECTED && timeout > 0) {
delay(1000);
Serial.print(".");
timeout--;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n连接成功!");
Serial.print("IP地址: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("\n连接失败,请检查凭据");
}
}
void loop() {
// 检查连接状态,断线自动重连
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Wi-Fi断开,尝试重连...");
WiFi.reconnect();
delay(5000);
}
// 你的业务逻辑
delay(10000);
}
警告:千万不要在loop()里频繁调用WiFi.reconnect()。我曾经见过有人每秒重连一次,结果把AP搞崩了。建议至少间隔5秒以上,并且加上重试次数限制。
这段代码看起来简单,但有几个坑我得提醒你:
- Wi-Fi模式设置:ESP32默认是
WIFI_AP_STA模式(同时开启AP和Station)。如果你只用Station模式,一定要显式设置WiFi.mode(WIFI_STA),否则功耗会高不少。 - 连接超时:
WiFi.begin()是异步的,不会阻塞。但如果你不手动检查状态,代码会直接往下跑。我习惯加一个超时循环,避免死等。 - 断线重连:ESP32的Wi-Fi库自带自动重连功能,但有时候不靠谱。我建议在
loop()里主动检查状态,手动触发重连。
再说说AP模式的配置。下面这段代码,是让ESP32开一个热点,然后通过Web页面接收Wi-Fi密码:
#include <WiFi.h>
#include <WebServer.h>
WebServer server(80);
void setup() {
Serial.begin(115200);
// 设置AP模式
WiFi.mode(WIFI_AP);
WiFi.softAP("ESP32_Config", "12345678");
Serial.print("AP IP地址: ");
Serial.println(WiFi.softAPIP());
// 配置Web页面路由
server.on("/", HTTP_GET, []() {
String html = "<form action='/config' method='POST'>";
html += "SSID: <input name='ssid'><br>";
html += "Password: <input name='password' type='password'><br>";
html += "<input type='submit' value='连接'>";
html += "</form>";
server.send(200, "text/html", html);
});
server.on("/config", HTTP_POST, []() {
String ssid = server.arg("ssid");
String password = server.arg("password");
// 保存到EEPROM或Preferences
// 然后重启设备,切换为Station模式
server.send(200, "text/plain", "配置已保存,设备重启中...");
delay(1000);
ESP.restart();
});
server.begin();
}
void loop() {
server.handleClient();
}
个人经验:AP模式下的Web页面,建议用ESPAsyncWebServer库替代原生的WebServer。前者是异步的,不会阻塞主循环,而且支持WebSocket,做配置页面体验好很多。
最后,我分享一个我踩过的坑。有一次做智能灯控项目,设备在AP模式下配置完Wi-Fi密码后,切回Station模式时死活连不上。查了半天,发现是AP模式关闭后,Wi-Fi射频没有完全复位。解决方案很简单:在切换模式前,先调用WiFi.disconnect(true),再WiFi.mode(WIFI_STA),最后WiFi.begin()。顺序不能乱。