ESP32无线传输(一)

Wi-Fi库

要使用 ESP32 Wi-Fi 功能,您需要做的第一件事就是包括WiFi.h代码中的库,如下所示:

#include <WiFi.h>

ESP32 Wi-Fi 模式

ESP32板可以充当Wi-Fi站、接入点或两者兼而有之。要设置 Wi-Fi 模式,请使用WiFi.mode()并将所需模式设置为参数:

模式说明
WiFi.mode(WIFI_STA)站点模式:ESP32连接到接入点
WiFi.mode(WIFI_AP)接入点模式:站点可以连接到ESP32
WiFi.mode(WIFI_AP_STA)接入点和连接到另一个接入点的站点

Wi-Fi站

当ESP32设置为Wi-Fi站时,它可以连接到其他网络(例如您的路由器)。在这种情况下,路由器会为您的 ESP 板分配一个唯一的 IP 地址。您可以通过参考ESP唯一IP地址,使用同样连接到同一网络的其他设备(站点)与ESP通信。
202510159789901.png
路由器已经连接到网络,因为我们可以使用ESP32板从网络上请求信息,例如API(天气数据)的资料,将数据发布到在线平台,使用来自互联网的图标和图像或包含 JavaScript 库来构建 Web 服务器页面。

将ESP32设置为站点并连接到Wi-Fi网络

在某些情况下,这可能不是最好的配置——当你附近没有网络,并且仍然想连接到ESP来控制它时。在此情景中,您必须将 ESP 板设置为接入点。

接入点

当您将ESP32板设置为接入点时,您可以使用任何具有Wi-Fi功能的设备进行连接,而无需连接到路由器。当您将ESP32设置为接入点时,您将创建自己的Wi-Fi网络,附近的Wi-Fi设备(站)可以连接到它,例如您的智能手机或电脑。所以,你不需要连接到路由器来控制它。
如果您想让几个ESP32设备在不需要路由器的情况下相互通信,这也很有用。
202510159789902.png

因为ESP32不会像您的路由器那样进一步连接到有线网络,所以它被称为soft-AP(软接入点)。这意味着,如果您尝试从互联网上加载库或使用固件,它将无法工作。如果您向互联网上的服务发出HTTP请求,将传感器读数发布到云端或使用互联网上的服务(例如发送电子邮件),它也不起作用。

将ESP32设置为接入点

要将ESP32设置为接入点,请将Wi-Fi模式设置为接入点:

WiFi.mode(WIFI_AP)

然后,使用softAP()方法如下:

WiFi.softAP(ssid, password);

ssid是您想给ESP32接入点起的名字,以及password是接入点的密码。如果您不想设置密码,请将其设置为NULL

还有其他可选参数,你可以传递给softAP()方法。以下是所有参数:

WiFi.softAP(const char* ssid, const char* password, int channel, int ssid_hidden, int max_connection)
  • ssid:接入点的名称——最多63个字符;
  • password:最少8个字符;如果您希望接入点打开则设置为NULL
  • channel:Wi-Fi频道编号(1-13);
  • ssid_hidden:(0=广播SSID,1=隐藏SSID);
  • max_connection:最大同时连接的客户端(1-4);

Wi-Fi站+接入点

ESP32可以同时设置为Wi-Fi站和接入点。将其模式设置为WIFI_AP_STA

WiFi.mode(WIFI_AP_STA);

以上是关于ESP32中关于WiFi模式说明。

扫描Wi-Fi网络

ESP32可以在其Wi-Fi范围内扫描附近的Wi-Fi网络。在您的Arduino IDE中,转到文件>示例>WiFi>WiFiScan。这将用一个图来展示ESP32板扫描范围内的Wi-Fi网络。
202510159789903.png

这对于检查您尝试连接的Wi-Fi网络是否在您的主板或其他应用程序的范围内很有用。您的Wi-Fi项目可能不经常工作,因为由于Wi-Fi强度不足,它可能无法连接到您的路由器。
下面是一个示例:

#include <Arduino.h>
// 引入WiFi库
#include <WiFi.h>


// 获取WiFi加密类型
const char* getEncryptionType(wifi_auth_mode_t authMode) {
  switch (authMode) {
    case WIFI_AUTH_OPEN:
      return "OPEN";
    case WIFI_AUTH_WEP:
      return "WEP";
    case WIFI_AUTH_WPA_PSK:
      return "WPA_PSK";
    case WIFI_AUTH_WPA2_PSK:
      return "WPA2_PSK";
    case WIFI_AUTH_WPA_WPA2_PSK:
      return "WPA_WPA2_PSK";
    case WIFI_AUTH_WPA2_ENTERPRISE:
      return "WPA2_ENTERPRISE";
    case WIFI_AUTH_WPA3_PSK:
      return "WPA3_PSK";
    case WIFI_AUTH_WPA2_WPA3_PSK:
      return "WPA2_WPA3_PSK";
    default:
      return "UNKNOWN";
  }
}

// 阻塞扫描WiFi网络
void wifiScan() {
  Serial.println("开始扫描WiFi网络");
  // WiFi.scanNetworks()返回发现的WiFi网络数量
  int numSsid = WiFi.scanNetworks();
  if(numSsid == 0) {
    Serial.println("没有发现WiFi网络");
  } else {
    Serial.printf("发现%d个WiFi网络\n", numSsid);
    // 打印扫描结果
    for (int i = 0; i < numSsid; i++) {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print("    RSSI: (");
      Serial.print(WiFi.RSSI(i));
      Serial.print("dBm)");
      Serial.print("    Ch:");
      Serial.print(WiFi.channel(i));
      Serial.print("    ");
      Serial.println(getEncryptionType(WiFi.encryptionType(i)));
      delay(10);
    }
    
  }
  //... 扫描循环结束后 ...
  // 删除扫描结果以释放内存
  WiFi.scanDelete(); 
  Serial.println("扫描完成");
  
}

// 异步扫描WiFi网络
void wifiScanSync() {
  
  WiFi.scanNetworks(true);  // 传递true参数以启用异步扫描
  Serial.println("开始扫描WiFi网络");
}




void setup() {
  
  Serial.begin(115200);
  // 设置WiFi模式为STA(Station)模式 
  // 将WiFi设置为站模式,如果AP之前已连接,则断开与AP的连接
  WiFi.mode(WIFI_STA);
  // 断开WiFi连接
  WiFi.disconnect();
  Serial.println("WiFi已设置为STA模式并断开连接");
  // 阻塞扫描 wifi网络
  // wifiScan();
  // 异步扫描 wifi网络
  wifiScanSync();
}

void loop() {
  
  
  int scanResult = WiFi.scanComplete();
  if (scanResult >= 0) {
    Serial.println("扫描已完成,处理结果");
    Serial.printf("发现%d个WiFi网络\n", scanResult);
    for (int i = 0; i < scanResult; ++i) {
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print("    RSSI: (");
      Serial.print(WiFi.RSSI(i));
      Serial.print("dBm)");
      Serial.print("    Ch:");
      Serial.print(WiFi.channel(i));
      Serial.print("    ");
      Serial.println(getEncryptionType(WiFi.encryptionType(i)));
    }

    //... 扫描循环结束后 ...
    // 删除扫描结果以释放内存
    WiFi.scanDelete(); 
  }
  
  delay(5000);

}

我们可以将上面的代码编译后上传到ESP开发板中,并检查可用的网络以及RSSI(接收信号强度指示器)
202510159789904.png
运行后找到了6个

示例代码说明

WiFi.scanNetworks()返回找到的网络数量

int n = WiFi.scanNetworks();

扫描后,您可以访问每个网络的参数
WiFi.SSID()打印特定网络的SSID:

Serial.print(WiFi.SSID(i));

WiFi.RSSI()返回该网络的RSSI。RSSI代表接收信号强度指示器。它是射频客户端设备从接入点或路由器接收的功率水平的估计度量。

Serial.print(WiFi.RSSI(i));

WiFi.encryptionType()返回网络加密类型。这个具体的例子在开放网络的情况下放了一个*。然而,该函数可以返回以下选项之一(而不仅仅是开放网络):

  • WIFI_AUTH_OPEN
  • WIFI_AUTH_WEP
  • WIFI_AUTH_WPA_PSK
  • WIFI_AUTH_WPA2_PSK
  • WIFI_AUTH_WPA_WPA2_PSK
  • WIFI_AUTH_WPA2_ENTERPRISE

扫描Wi-Fi网络的阻塞与非阻塞

在代码里面有两种扫描Wi-Fi网络的方式:阻塞和非阻塞。
WiFi.scanNetworks() 默认是阻塞式调用,这意味着在扫描过程中,你的程序会暂停执行其他任务。对于简单的程序这没问题,但对于需要同时处理其他任务(如响应按钮、处理传感器数据等)的复杂应用,这会是个问题。
所以我在代码里面也同样实现了非阻塞的扫描:

  • 调用 WiFi.scanNetworks(true) 启动非阻塞扫描
  • loop() 中定期检查 WiFi.scanComplete() 的返回值,当返回值大于或等于 0 时,表示扫描完成
  • 处理完结果后,可以调用 WiFi.scanDelete()

删除扫描结果以释放内存

WiFi.scanNetworks() 会在内部分配内存来存储扫描结果。如果你的程序会多次调用 wifiScan(),最好在处理完结果后调用 WiFi.scanDelete() 来释放这部分内存,防止内存泄漏。对于长时间运行的应用尤其重要。

  //... 扫描循环结束后 ...
  // 删除扫描结果以释放内存
  WiFi.scanDelete(); 
  Serial.println("扫描完成");

评论

等风等雨等你来