配件

  1. ESP32 30P CP2102 Type-C 开发板 

  2. 0.96寸 OLED 屏幕 (I2C接口) 

接线

#四针oled接线
SDA -> ESP32 的 G21
SCL -> ESP32 的 G22
VCC -> ESP32 的 3V3
GND -> ESP32 的 GND

IDE:Arduino IDE

安装U8g2lib字体库

#include <WiFi.h>
#include <U8g2lib.h>
#include <Wire.h>
#include "time.h"
 
const char* ssid = "xxx";
const char* password = "xxx";
// 2. NTP 服务器配置
const char* ntpServer = "ntp.aliyun.com"; // 阿里云 NTP 服务器
const long  gmtOffset_sec = 8 * 3600;     // 中国时区为 UTC+8,即 8*3600 秒
const int   daylightOffset_sec = 0;      // 中国没有夏令时
unsigned long syncInterval = 3600 * 1000;
unsigned long lastSyncTime = 0;
// 3. 硬件对象初始化
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
 
void syncTimeNetwork() {
  Serial.println("\n--- 开始网络对时任务 ---");
  
  //必须先设置模式为 STA,才能唤醒 WiFi 硬件
  WiFi.mode(WIFI_STA); 
  delay(10); // 给硬件一点点启动时间
  
  WiFi.begin(ssid, password);

  int retry = 0;
  // 等待连接,最多等 15 秒 (30 * 500ms)
  while (WiFi.status() != WL_CONNECTED && retry < 30) {
    delay(500);
    Serial.print(".");
    retry++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi 已连接!正在同步时间...");
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    
    // 给系统一点时间去获取 NTP 数据包
    struct tm timeinfo;
    if (getLocalTime(&timeinfo, 10000)) { // 增加一个10秒的超时等待
      Serial.println("网络对时成功!当前时间: ");
      Serial.println(&timeinfo, "%F %T");
      lastSyncTime = millis(); // 【只有对时成功才重置一小时定时器】
    } else {
      Serial.println("时间获取超时,内部 RTC 将继续走时。");
      // 如果对时失败,让它 5 分钟后再尝试,而不是 1 小时
      lastSyncTime = millis() - (syncInterval - 300000); 
    }

    // 任务完成,关闭 WiFi 模块省电
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
    Serial.println("WiFi 已关闭,已切回本地走时模式");
  } else {
    Serial.println("\nWiFi 连接失败,放弃本次对时。");
    // 失败了,5 分钟后再次尝试
    lastSyncTime = millis() - (syncInterval - 300000); 
    WiFi.mode(WIFI_OFF); // 即使失败也要关掉,避免一直耗电
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  u8g2.begin();
  u8g2.enableUTF8Print();
 
  syncTimeNetwork(); 
  // 注意:不需要在 setup 里写 lastSyncTime = millis(),函数内部已经写了
}
 
void loop() {
  if(millis() - lastSyncTime  > syncInterval){
    syncTimeNetwork();
    lastSyncTime = millis();
  }
  struct tm timeinfo;
  
  // --- 步骤 C: 获取本地时间 ---
  if (!getLocalTime(&timeinfo)) {
    Serial.println("无法获取时间");
    return;
  }
 
  // --- 步骤 D: 在 OLED 上显示 ---
  u8g2.clearBuffer();
  
  // 显示日期 (年-月-日)
  u8g2.setFont(u8g2_font_wqy12_t_gb2312a);
  u8g2.setCursor(20, 15);
  u8g2.printf("%04d-%02d-%02d", 
              timeinfo.tm_year + 1900, 
              timeinfo.tm_mon + 1, 
              timeinfo.tm_mday);
 
  // 显示大字时间 (时:分:秒)
  // 使用一种大号的数字字体(u8g2 内置很多数字字体)
  u8g2.setFont(u8g2_font_logisoso24_tn); 
  u8g2.setCursor(10, 45);
  u8g2.printf("%02d:%02d:%02d", 
              timeinfo.tm_hour, 
              timeinfo.tm_min, 
              timeinfo.tm_sec);
 
  // 显示星期
  u8g2.setFont(u8g2_font_wqy12_t_gb2312a);
  const char* weekDays[] = {"日", "一", "二", "三", "四", "五", "六"};
  u8g2.setCursor(45, 60);
  u8g2.printf("星期%s", weekDays[timeinfo.tm_wday]);
 
  u8g2.sendBuffer();
 
  delay(1000); // 每秒刷新一次
}

成果

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐