admin管理员组

文章数量:1530919

已写文章链接

本专栏主要内容是记录基于ESP32的开发工作,包括介绍 ESP32 基础知识、开发环境搭建、基础外设使用、蓝牙、WiFi 、与微信小程序联动等知识,达到自己动手做一些智能硬件的目的。
开发过程中主要参考官方资料,包括官网、规格书、参考手册、编程指南、驱动包等。
本专栏适合对ESP32感兴趣,想要找一个简单入手教程的同学。

ESP32 基础知识(已完成)

(1)ESP32基础知识

开发环境搭建(已完成)

(2-1)开发环境搭建(基于Arduino)
(2-2)开发环境搭建(基于VS Code+PlatformIO)
(2-3)开发环境搭建(基于ESP-IDF软件)

基础外设使用(已完成)

(3-1)基础外设使用(GPIO)
(3-2)基础外设使用(USART)

蓝牙(已完成)

(4)蓝牙使用(Classic BT+BLE)

WiFi(已完成)

(5)WiFi使用(STA模式)

微信小程序(已完成)

(6)微信小程序(配网和开关灯)


本章会介绍一下 wifi 的基础知识。并给出扫描 wifi、按键、连接 wifi 的示例。

硬件和软件版本

本文章使用的软硬件版本如下。
硬件

  • 开发板:ESP32-DevKitC-32E
  • 模组:ESP32-WROOM-32E
  • 芯片:ESP32-DOWD-V3

软件

  • 开发环境:Arduino IDE V2.2.1
  • ESP32 软件包:V2.0.11

WiFi 基础知识

以下定义来自于 ChatGPT。

WiFi是一种无线网络技术,允许设备通过无线信号进行互联和互通。它使用无线电波来传输数据,使设备能够在没有物理连接的情况下进行网络通信。
WiFi的Station模式和AP模式是两种不同的操作模式,各自有着不同的功能和工作方式:
Station模式(站点模式):
作用: 在Station模式下,设备像普通的客户端一样连接到现有的WiFi网络,类似于笔记本电脑、智能手机等设备连接到家庭或办公室的无线路由器。
功能: 设备可以获取IP地址并与网络中的其他设备进行通信,能够接收和发送数据。它作为网络中的一个客户端,依赖于一个已建立的WiFi接入点来连接网络。
AP模式(接入点模式):
作用: 在AP模式下,设备充当WiFi接入点,允许其他设备通过WiFi连接到它所创建的网络。
功能: 设备在AP模式下可以创建自己的WiFi网络,其他设备可以搜索并连接到它创建的网络。它负责路由数据包并提供连接,类似于一个无线路由器。
区别:
功能角色不同: 在Station模式下,设备是连接到一个现有网络的客户端;而在AP模式下,设备是创建并提供WiFi网络的主机。
连接方式不同: 在Station模式下,设备连接到现有的WiFi网络;在AP模式下,设备创建自己的WiFi网络,其他设备连接到它。
网络管理权限不同: 在AP模式下,设备可以管理创建的网络设置和连接参数;而在Station模式下,设备需要遵循网络提供的设置。
需要注意的是,某些设备可能支持同时处于Station和AP模式,允许设备既连接到一个网络,同时也提供自己的网络给其他设备连接。

硬件连接

本章硬件无连接,开发板使用 WIFI 的 Station 模式来连接路由器。

现在有些路由器是双频的,即 2.4G 和 5G,其中 ESP32 的 wifi 硬件不支持 5G。所以后边我们连接 2.4G WIFI 即可。要是路由设置了多频合一,那有可能搜不到 wifi,在路由管理界面中关闭多频合一即可。

软件设计

源文件功能

本章使用Arduino的例程,选择示例—WiFi—WiFiClientConnect

这里先贴出源文件代码。源文件大概的流程是初始化了一个按键和 wifi,上电之后按照用户设定的ssidpassword尝试连接 wifi,有 wifi 未找见、wifi 连接失败、连接丢失、连接成功等状态,要是超时未连接成功,则认为连接失败,退出。使用按键可以关闭当前连接 wifi。

/* Wi-Fi STA Connect and Disconnect Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
   
*/
#include <WiFi.h>

const char* ssid     = "your-ssid";
const char* password = "your-password";

int btnGPIO = 0;
int btnState = false;

void setup()
{
    Serial.begin(115200);
    delay(10);

    // Set GPIO0 Boot button as input
    pinMode(btnGPIO, INPUT);

    // We start by connecting to a WiFi network
    // To debug, please enable Core Debug Level to Verbose

    Serial.println();
    Serial.print("[WiFi] Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);
// Auto reconnect is set true as default
// To set auto connect off, use the following function
//    WiFi.setAutoReconnect(false);

    // Will try for about 10 seconds (20x 500ms)
    int tryDelay = 500;
    int numberOfTries = 20;

    // Wait for the WiFi event
    while (true) {
        
        switch(WiFi.status()) {
          case WL_NO_SSID_AVAIL:
            Serial.println("[WiFi] SSID not found");
            break;
          case WL_CONNECT_FAILED:
            Serial.print("[WiFi] Failed - WiFi not connected! Reason: ");
            return;
            break;
          case WL_CONNECTION_LOST:
            Serial.println("[WiFi] Connection was lost");
            break;
          case WL_SCAN_COMPLETED:
            Serial.println("[WiFi] Scan is completed");
            break;
          case WL_DISCONNECTED:
            Serial.println("[WiFi] WiFi is disconnected");
            break;
          case WL_CONNECTED:
            Serial.println("[WiFi] WiFi is connected!");
            Serial.print("[WiFi] IP address: ");
            Serial.println(WiFi.localIP());
            return;
            break;
          default:
            Serial.print("[WiFi] WiFi Status: ");
            Serial.println(WiFi.status());
            break;
        }
        delay(tryDelay);
        
        if(numberOfTries <= 0){
          Serial.print("[WiFi] Failed to connect to WiFi!");
          // Use disconnect function to force stop trying to connect
          WiFi.disconnect();
          return;
        } else {
          numberOfTries--;
        }
    }
}

void loop()
{
    // Read the button state
    btnState = digitalRead(btnGPIO);
    
    if (btnState == LOW) {
      // Disconnect from WiFi
      Serial.println("[WiFi] Disconnecting from WiFi!");
      // This function will disconnect and turn off the WiFi (NVS WiFi data is kept)
      if(WiFi.disconnect(true, false)){
        Serial.println("[WiFi] Disconnected from WiFi!");
      }
      delay(1000);
    }
}

更改一些功能

我们对源文件加一些改造,完成这个功能:上电之后扫描并打印周围的 wifi,按键按下后采用用户设定的 wifi 参数(ssid+password)连接指定 wifi,连接成功后打印当前 wifi 的 ip。
我们分解一下任务功能。完成大概 3 个任务:

  • 扫描周围 wifi 并打印。
  • 可以响应按键按下。
  • 连接指定 wifi,可以根据连接状态打印 ip。

扫描周围 wifi

Arduino有一个扫描 wifi 的例程,如下。

源文件如下,大概逻辑是初始化 wifi 为 STA 模式,每隔 5 秒扫描一次周围 wifi,如果扫描结果显示周围有 wifi,就打印 wifi 的 ssid 、信号强度、通道、加密方式。

/*
 *  This sketch demonstrates how to scan WiFi networks.
 *  The API is based on the Arduino WiFi Shield library, but has significant changes as newer WiFi functions are supported.
 *  E.g. the return value of `encryptionType()` different because more modern encryption is supported.
 */
#include "WiFi.h"

void setup()
{
    Serial.begin(115200);

    // Set WiFi to station mode and disconnect from an AP if it was previously connected.
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);

    Serial.println("Setup done");
}

void loop()
{
    Serial.println("Scan start");

    // WiFi.scanNetworks will return the number of networks found.
    int n = WiFi.scanNetworks();
    Serial.println("Scan done");
    if (n == 0) {
        Serial.println("no networks found");
    } else {
        Serial.print(n);
        Serial.println(" networks found");
        Serial.println("Nr | SSID                             | RSSI | CH | Encryption");
        for (int i = 0; i < n; ++i) {
            // Print SSID and RSSI for each network found
            Serial.printf("%2d",i + 1);
            Serial.print(" | ");
            Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
            Serial.print(" | ");
            Serial.printf("%4d", WiFi.RSSI(i));
            Serial.print(" | ");
            Serial.printf("%2d", WiFi.channel(i));
            Serial.print(" | ");
            switch (WiFi.encryptionType(i))
            {
            case WIFI_AUTH_OPEN:
                Serial.print("open");
                break;
            case WIFI_AUTH_WEP:
                Serial.print("WEP");
                break;
            case WIFI_AUTH_WPA_PSK:
                Serial.print("WPA");
                break;
            case WIFI_AUTH_WPA2_PSK:
                Serial.print("WPA2");
                break;
            case WIFI_AUTH_WPA_WPA2_PSK:
                Serial.print("WPA+WPA2");
                break;
            case WIFI_AUTH_WPA2_ENTERPRISE:
                Serial.print("WPA2-EAP");
                break;
            case WIFI_AUTH_WPA3_PSK:
                Serial.print("WPA3");
                break;
            case WIFI_AUTH_WPA2_WPA3_PSK:
                Serial.print("WPA2+WPA3");
                break;
            case WIFI_AUTH_WAPI_PSK:
                Serial.print("WAPI");
                break;
            default:
                Serial.print("unknown");
            }
            Serial.println();
            delay(10);
        }
    }
    Serial.println("");

    // Delete the scan result to free memory for code below.
    WiFi.scanDelete();

    // Wait a bit before scanning again.
    delay(5000);
}

执行结果如下。从结果中也能看到只能搜到 2.4G 的 wifi,搜不到 5G 的。

我们只需要做到上电时扫描即可。所以将loop中的函数放到setup中执行,最终代码如下:

/*
 *  This sketch demonstrates how to scan WiFi networks.
 *  The API is based on the Arduino WiFi Shield library, but has significant changes as newer WiFi functions are supported.
 *  E.g. the return value of `encryptionType()` different because more modern encryption is supported.
 */
#include "WiFi.h"

void setup()
{
    Serial.begin(115200);

    // Set WiFi to station mode and disconnect from an AP if it was previously connected.
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);

    Serial.println("Setup done");
    
    Serial.println("Scan start");
      // WiFi.scanNetworks will return the number of networks found.
    int n = WiFi.scanNetworks();
    Serial.println("Scan done");
    if (n == 0) {
        Serial.println("no networks found");
    } else {
        Serial.print(n);
        Serial.println(" networks found");
        Serial.println("Nr | SSID                             | RSSI | CH | Encryption");
        for (int i = 0; i < n; ++i) {
            // Print SSID and RSSI for each network found
            Serial.printf("%2d",i + 1);
            Serial.print(" | ");
            Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
            Serial.print(" | ");
            Serial.printf("%4d", WiFi.RSSI(i));
            Serial.print(" | ");
            Serial.printf("%2d", WiFi.channel(i));
            Serial.print(" | ");
            switch (WiFi.encryptionType(i))
            {
            case WIFI_AUTH_OPEN:
                Serial.print("open");
                break;
            case WIFI_AUTH_WEP:
                Serial.print("WEP");
                break;
            case WIFI_AUTH_WPA_PSK:
                Serial.print("WPA");
                break;
            case WIFI_AUTH_WPA2_PSK:
                Serial.print("WPA2");
                break;
            case WIFI_AUTH_WPA_WPA2_PSK:
                Serial.print("WPA+WPA2");
                break;
            case WIFI_AUTH_WPA2_ENTERPRISE:
                Serial.print("WPA2-EAP");
                break;
            case WIFI_AUTH_WPA3_PSK:
                Serial.print("WPA3");
                break;
            case WIFI_AUTH_WPA2_WPA3_PSK:
                Serial.print("WPA2+WPA3");
                break;
            case WIFI_AUTH_WAPI_PSK:
                Serial.print("WAPI");
                break;
            default:
                Serial.print("unknown");
            }
            Serial.println();
            delay(10);
        }
    }
    Serial.println("");

    // Delete the scan result to free memory for code below.
    WiFi.scanDelete();

    Serial.println("Scan finished");

}

void loop()
{
  
}

代码执行结果如下。

响应按键

这个功能采用之前 GPIO 章节的即可。读按键引脚电平的周期为 5 秒,所以按键要超过 5 秒才有效。

/* Wi-Fi STA Connect and Disconnect Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
   
*/
#include <WiFi.h>

#define LED 16
#define BUTTON 0

int btnGPIO = 0;
int btnState = false;

void setup()
{
    pinMode(LED, OUTPUT);
    pinMode(BUTTON, INPUT);
    
    Serial.begin(115200);
    delay(10);
}

void loop()
{
    if(digitalRead(BUTTON) == 0) 
    {
      digitalWrite(LED, HIGH);
      delay(1000);
    }
    delay(5000);
}

连接指定 wifi

我的网络如下。2.4G 的 SSID 为JinHuan_2,密码为自己设定的。

然后来做连接指定 wifi,并根据 wifi 连接结果打印 ip 的功能。改造一下开头的那个示例:示例—WiFi—WiFiClientConnect,在响应按键的基础上加入连接 wifi 功能。
代码如下。

/* Wi-Fi STA Connect and Disconnect Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
   
*/
#include <WiFi.h>

#define LED 16
#define BUTTON 0

const char* ssid     = "JinHuan_2";
const char* password = "your-password";

int btnGPIO = 0;
int btnState = false;

void setup()
{
    pinMode(LED, OUTPUT);
    pinMode(BUTTON, INPUT);
    
    Serial.begin(115200);
    delay(10);
      // Set WiFi to station mode and disconnect from an AP if it was previously connected.
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);

    Serial.println("Setup done");
    Serial.println("Scan start");
      // WiFi.scanNetworks will return the number of networks found.
    int n = WiFi.scanNetworks();
    Serial.println("Scan done");
    if (n == 0) {
        Serial.println("no networks found");
    } else {
        Serial.print(n);
        Serial.println(" networks found");
        Serial.println("Nr | SSID                             | RSSI | CH | Encryption");
        for (int i = 0; i < n; ++i) {
            // Print SSID and RSSI for each network found
            Serial.printf("%2d",i + 1);
            Serial.print(" | ");
            Serial.printf("%-32.32s", WiFi.SSID(i).c_str());
            Serial.print(" | ");
            Serial.printf("%4d", WiFi.RSSI(i));
            Serial.print(" | ");
            Serial.printf("%2d", WiFi.channel(i));
            Serial.print(" | ");
            switch (WiFi.encryptionType(i))
            {
            case WIFI_AUTH_OPEN:
                Serial.print("open");
                break;
            case WIFI_AUTH_WEP:
                Serial.print("WEP");
                break;
            case WIFI_AUTH_WPA_PSK:
                Serial.print("WPA");
                break;
            case WIFI_AUTH_WPA2_PSK:
                Serial.print("WPA2");
                break;
            case WIFI_AUTH_WPA_WPA2_PSK:
                Serial.print("WPA+WPA2");
                break;
            case WIFI_AUTH_WPA2_ENTERPRISE:
                Serial.print("WPA2-EAP");
                break;
            case WIFI_AUTH_WPA3_PSK:
                Serial.print("WPA3");
                break;
            case WIFI_AUTH_WPA2_WPA3_PSK:
                Serial.print("WPA2+WPA3");
                break;
            case WIFI_AUTH_WAPI_PSK:
                Serial.print("WAPI");
                break;
            default:
                Serial.print("unknown");
            }
            Serial.println();
            delay(10);
        }
    }
    Serial.println("");

    // Delete the scan result to free memory for code below.
    WiFi.scanDelete();

    Serial.println("Scan finished");
}

void loop()
{
    if(digitalRead(BUTTON) == 0) 
    {
      digitalWrite(LED, HIGH);

      Serial.print("[WiFi] Connecting to ");
      Serial.println(ssid);

      WiFi.begin(ssid, password);
      WiFi.setAutoReconnect(false);

      delay(1000);
    }
    
    if(WiFi.status() == WL_CONNECTED)
    {
      Serial.println("[WiFi] WiFi is connected!");
      Serial.print("[WiFi] IP address: ");
      Serial.println(WiFi.localIP());
    }
    else
    {
      Serial.print("[WiFi] WiFi Status: ");
      Serial.println(WiFi.status());
    }
    delay(5000);
}

执行结果如下,连接上了 SSID 为JinHuan_2的 wifi,并且获取到了 IP。

从路由器的管理界面也能看到 2.4G 的已连设备从 0 变为 1。

若我们想设置上电自动连接 wifi,则可以修改源码如下。

/* Wi-Fi STA Connect and Disconnect Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
   
*/
#include <WiFi.h>

#define LED 16
#define BUTTON 0

const char* ssid     = "JinHuan_2";
const char* password = "your-password";

int btnGPIO = 0;
int btnState = false;

void setup()
{
    pinMode(LED, OUTPUT);
    pinMode(BUTTON, INPUT);
    
    Serial.begin(115200);
    delay(10);

    Serial.print("[WiFi] Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);
    
    do
    {
      Serial.print("[WiFi] WiFi Status: ");
      Serial.println(WiFi.status());
      delay(1000);
    }while(WiFi.status() != WL_CONNECTED);

    Serial.println("[WiFi] WiFi is connected!");
    Serial.print("[WiFi] IP address: ");
    Serial.println(WiFi.localIP());
}

void loop()
{

}

执行结果如下。

本文标签: 模式wifiSTA