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密码。

下面这张图,是我画的一个典型入网流程:

Wi-Fi设备入网流程(Station模式) 设备上电初始化 扫描周围AP 选择AP & 认证 DHCP获取IP地址 连接成功,开始通信 避坑提示 扫描AP时,建议设置超时 5-10秒。我曾经遇到过 设备卡在扫描阶段死循环。

实战技巧: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()。顺序不能乱。