ESP32 WiFi 开发

最近更新于 2024-05-05 12:31

1 前言

ESP32 买了快三个月了,当时用 Arduino IDE 配置好了开发环境,之后就开始吃灰。最近想起来,打算做个可以联网对时的时钟,所以开始学习探索了。

2 测试环境

2.1 硬件

  • ESP32-WROOM-32(只支持 2.4GHz 频段 WiFi)

2.2 软件

3 探索

3.1 WiFi 连接

/**
 * WiFi 连接程序
 * 启动后自动尝试连接设置的 WiFi
 * 如果连接失败,最多尝试 20 次
 * 连接成功后可以短接 GND 和 D15 引脚使 WiFi 连接断开
 */
#include <WiFi.h>

const char* ssid = "IYATT-yx_2.4GHz"; // WiFi 名
const char* password = "esp32test"; // 密码

int pin = 15; // D15 引脚用于控制断开 WiFi
int state = false; // 引脚状态

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

    pinMode(pin, INPUT_PULLUP);

    Serial.println();
    Serial.print("[WiFi] 尝试连接到 ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    // 失败尝试重连
    int try_delay = 1000; // 尝试间隔延时
    int number_of_tries = 20; // 尝试次数

    while (true)
    {
        // 检查 WiFi 连接状态
        switch(WiFi.status())
        {
            case WL_NO_SSID_AVAIL:
            {
                Serial.println("[WiFi] 没有找到 SSID");
                break;
            }
            case WL_CONNECT_FAILED:
            {
                Serial.print("[WiFi] 失败 - WiFi 未连接! 原因:");
                return;
            }
            case WL_CONNECTION_LOST:
            {
                Serial.println("[WiFi] 连接丢失");
                break;
            }
            case WL_SCAN_COMPLETED:
            {
                Serial.println("[WiFi] 扫描已完成");
                break;
            }
            case WL_CONNECTED:
            {
                Serial.println("[WiFi] 已连接!");
                Serial.print("[WiFi] IP 地址:");
                Serial.println(WiFi.localIP());
                return;
            }
            case WL_DISCONNECTED:
            {
                Serial.println("[WiFi] 连接已断开");
                break;
            }
            default:
            {
                Serial.print("[WiFi] WiFi 状态:");
                Serial.println(WiFi.status());
                break;
            }
        }
        delay(try_delay);

        if(number_of_tries <= 0)
        {
            Serial.print("[WiFi] 连接 WiFi 失败!");
            WiFi.disconnect();
            return;
        }
        else
        {
            --number_of_tries;
        }
    }
}

void loop()
{
    state = digitalRead(pin);

    if (state == LOW)
    {
        Serial.println("[WiFi] 正在断开连接!");
        if(WiFi.disconnect(true, false))
        {
        Serial.println("[WiFi] 已断开连接");
        }
        delay(1000);
    }
}

file

file

3.2 GET 请求

这里方便测试我就使用电脑上的 Python 运行 http 模块作为服务器端,下面是一个简易的 html 网页

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
</head>
<body>
    <h1>你好,世界!</h1>
</body>
</html>

命名保存为 index.html 文件

然后在这个文件所在的路径运行 http 服务(8080 端口)

python -m http.server 8080

file

同一局域网下的手机可以访问这个网页(电脑IP:8080 ),服务器这边就没啥问题了
file

然后是 ESP32 的代码

/**
 * GET 请求实现
 */
#include <WiFi.h>
#include <WiFiMulti.h>

WiFiMulti WiFiMulti; // 创建一个多 WiFi 实例,可以连接多个 WiFi

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

    WiFiMulti.addAP("IYATT-yx_2.4GHz", "esp32test"); // 首先连接到一个 WiFi,分别是名字和密码

    Serial.println();
    Serial.println();
    Serial.print("等待 WiFi 连接...... ");

    while(WiFiMulti.run() != WL_CONNECTED) // 连接失败时重试
    {
        Serial.print(".");
        delay(1000);
    }

    Serial.println("");
    Serial.println("WiFi 已连接");
    Serial.println("IP 地址: ");
    Serial.println(WiFi.localIP());

    delay(500);
}

void loop()
{
    const char * host = "192.168.1.249"; //  服务器地址
    const uint16_t port = 8080; // 服务器端口

    Serial.print("正在连接到 ");
    Serial.println(host);

    WiFiClient client; // 用于创建 TCP 连接

    if (!client.connect(host, port)) // 连接服务器
    {
        Serial.println("连接失败!");
        Serial.println("5 秒后重试......");
        delay(5000);
        return;
    }

    client.print("GET /index.html HTTP/1.1\n\n"); // 发送 GET 请求,获取 index.html 文件

    int maxloops = 0;

    // 等待服务器返回数据
    while (!client.available() && maxloops < 1000)
    {
        ++maxloops;
        delay(1);
    }

    if (client.available() > 0) // 如果有数据返回
    {
        String response = client.readString();
        Serial.println("服务器返回的内容:");
        Serial.println(response);
    }
    else
    {
        Serial.println("连接超时");
    }

    Serial.println("正在关闭连接。");
    client.stop();

    Serial.println("等待 5 秒后重试......");
    delay(5000);
}

运行后可以看到串口输出了请求到的内容
file

Python 这边也会显示 ESP32 的请求记录
file

3.3 NTP 时间同步

3.3.1 第三方库

源码

#include <WiFi.h>
#include <NTP.h>

const char * ssid = "IYATT-yx_2.4GHz";
const char * password = "esp32test";

WiFiUDP wifi_udp;
NTP ntp(wifi_udp);

void setup()
{
    const char * ntp_server = "ntp.aliyun.com"; // NTP 服务器,默认的感觉应该不如国内的稳定

    Serial.begin(115200);
    delay(100);

    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.println("正在尝试连接 WiFi ......");
        delay(1000);
    }
    Serial.println("WiFi 已连接");

    ntp.isDST(false); // 禁止夏令时
    ntp.timeZone(8); // 北京时间
    ntp.begin(ntp_server);
    Serial.println("开始同步时间:");
}

void loop()
{
    ntp.update();
    Serial.println(ntp.formattedTime("%Y.%m.%d %A %T")); // 格式化规则同 strftime
    delay(1000);
}

file

3.3.2 官方 API

前面探索 NTP 时间同步的时候不知道 ESP32 内部有系统时间,也不知道官方有提供时间同步功能。本来的计划是 ESP32 还要外接一个实时时钟模块,结果在查阅资料的时候发现官方文档说内部有系统时间,那就大大地简化了。不过因为没有独立电源供电,一旦外接电源断开时钟就会丢失,而实时时钟模块自身是可以使用外部电池供电维持走时。

#include <WiFi.h>

void setup()
{
    const char * ssid = "IYATT-yx_2.4GHz";
    const char * password = "esp32test";
    const char * ntp_server = "ntp.aliyun.com"; // NTP 服务器
    const int gmt_offset = 8 * 60 * 60; // UTC/GMT+8,东 8 时区偏移量,单位秒
    const int daylight_offset = 0; // 夏令时偏移值,单位秒

    Serial.begin(115200);
    delay(1000);

    // 设置时区
    setenv("TZ", "CST-8", 1); // TZ 是时区环境变量,CST-8 是中国标准时间,1 表示覆盖旧值
    tzset(); // 作用时区变量

    // 连接 WiFi
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        Serial.println("正在尝试连接 WiFi ......");
        delay(1000);
    }
    Serial.println("WiFi 已连接");
    delay(1000);

    // 同步时间
    configTime(gmt_offset, daylight_offset, ntp_server);
    Serial.println("完成时间同步");
    delay(2000);
}

void loop()
{
    time_t now = 0;
    struct tm time_info;
    char strftime_buf[64] = {'\0'};

    time(&now);
    localtime_r(&now, &time_info);
    strftime(strftime_buf, sizeof(strftime_buf), "%Y.%m.%d %A %T", &time_info);
    Serial.println(strftime_buf);
    delay(1000);
}

file

ESP32 WiFi 开发
Scroll to top