正点原子esp32s3在0.96寸oled屏幕上显示时间

之前实现了0.96寸的oled屏幕的显示实验,但是只是显示几个字没啥意思,总想着做点什么吧,今晚正好有空,就尝试一下从网络同步时间到oled上显示出来实时的时间吧。

正点原子esp32s3连0.96寸oled屏幕_esp32-s3 中文 oled-优快云博客

硬件如下:

正点原子ESP32S3开发板

淘宝7元购的0.96寸SPI接口的oled屏幕

实验步骤:

新建rtc项目。

这里要用到依赖:ESP32Time

把依赖添加到项目:

platoformio.ini

[env:dnesp32s3]
platform = espressif32
board = dnesp32s3
framework = arduino
upload_speed = 115200
monitor_speed = 115200
test_speed = 115200
debug_speed = 115200

lib_deps = fbiego/ESP32Time@^2.0.6

然后,我们要让时间在0.96寸的oled上显示出来,这时,我们就可以用到前面做的oled实验了。

正点原子esp32s3连0.96寸oled屏幕_esp32-s3 中文 oled-优快云博客

现在来重构原来的代码,将OLED功能封装到oled.h和oled.cpp中,原来的引脚设置不变,通过传参的方式传入。

主要步骤:

1. 创建oled.h:声明OLED类,包含初始化、显示时间等方法。

2. 创建oled.cpp:实现OLED类的方法。

3. 修改main.cpp:包含ESP32Time库,初始化RTC,并在循环中更新时间并显示。

oled.h

#ifndef OLED_H
#define OLED_H

#include <U8g2lib.h>
#include <Arduino.h>

class OLED {
public:
  // 构造函数初始化引脚
  OLED(uint8_t clk, uint8_t mosi, uint8_t cs, uint8_t dc, uint8_t rst);
  
  // 初始化OLED
  void begin();
  
  // 显示时间(日期+时间)
  void displayTime(const String& date, const String& time);
  
  // 清空屏幕缓冲区
  void clearBuffer();
  
  // 发送缓冲区内容到屏幕
  void sendBuffer();

private:
  U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI _u8g2;
};

#endif

oled.cpp

#include "oled.h"

OLED::OLED(uint8_t clk, uint8_t mosi, uint8_t cs, uint8_t dc, uint8_t rst)
  : _u8g2(U8G2_R0, cs, dc, rst)  // 初始化U8G2对象
{
  // 引脚配置通过U8G2构造函数传递
}

void OLED::begin() {
  _u8g2.begin();
  _u8g2.enableUTF8Print();
  _u8g2.setFont(u8g2_font_wqy12_t_gb2312); // 设置中文字体
  _u8g2.clearBuffer();
  _u8g2.sendBuffer();
}

void OLED::clearBuffer() {
  _u8g2.clearBuffer();
}

void OLED::sendBuffer() {
  _u8g2.sendBuffer();
}

void OLED::displayTime(const String& date, const String& time) {
  // 清空缓冲区
  clearBuffer();
  
  // 设置字体(确保每次显示都设置)
  _u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  
  // 居中显示日期
  int dateWidth = _u8g2.getUTF8Width(date.c_str());
  int dateX = (128 - dateWidth) / 2;
  _u8g2.drawUTF8(dateX, 20, date.c_str());
  
  // 居中显示时间
  int timeWidth = _u8g2.getUTF8Width(time.c_str());
  int timeX = (128 - timeWidth) / 2;
  _u8g2.drawUTF8(timeX, 45, time.c_str());
  
  // 发送到屏幕
  sendBuffer();
}

main.cpp

#include <Arduino.h>
#include <ESP32Time.h>
#include "oled.h"

// OLED引脚配置
#define OLED_CLK  12
#define OLED_MOSI 11
#define OLED_CS   7
#define OLED_DC   6
#define OLED_RST  5

// 创建对象
OLED oled(OLED_CLK, OLED_MOSI, OLED_CS, OLED_DC, OLED_RST);
ESP32Time rtc;  // RTC对象

// 辅助函数:格式化数字为两位字符串
String formatTwoDigits(int number) {
  if (number < 10) {
    return "0" + String(number);
  }
  return String(number);
}

void setup() {
  Serial.begin(115200);
  
  // 初始化OLED
  oled.begin();
  
  // 设置RTC时间为编译时间(实际使用时应该从NTP获取)
  // 获取编译时的日期和时间
  rtc.setTime(0, 0, 0, 16, 8, 2025);  // 设置当前时间为2025年8月16日
  
  // 显示初始信息
  oled.displayTime("初始化完成", "RTC已设置");
  delay(1000);
}

void loop() {
  // 直接从RTC获取时间组件
  int year = rtc.getYear() + 1900;  // tm_year是从1900开始的年数
  int month = rtc.getMonth() + 1;   // 月份从0开始,需要+1
  int day = rtc.getDay();
  int hour = rtc.getHour(true);     // 24小时制
  int minute = rtc.getMinute();
  int second = rtc.getSecond();
  
  // 构建日期字符串 (格式: YYYY年MM月DD日)
  String dateStr = String(year) + "年" + 
                   formatTwoDigits(month) + "月" + 
                   formatTwoDigits(day) + "日";
  
  // 构建时间字符串 (格式: HH:MM:SS)
  String timeStr = formatTwoDigits(hour) + ":" + 
                   formatTwoDigits(minute) + ":" + 
                   formatTwoDigits(second);
  
  // 显示到OLED
  oled.displayTime(dateStr, timeStr);
  
  // 串口打印调试信息
  Serial.print("当前时间: ");
  Serial.print(dateStr);
  Serial.print(" ");
  Serial.println(timeStr);
  
  delay(1000);  // 每秒更新
}

原来的依赖也要拷贝过来:

platformio.ini

[env:dnesp32s3]
platform = espressif32
board = dnesp32s3
framework = arduino
upload_speed = 115200
monitor_speed = 115200
test_speed = 115200
debug_speed = 115200

lib_deps = 
    fbiego/ESP32Time@^2.0.6
	adafruit/Adafruit SSD1306@^2.5.15
	adafruit/Adafruit GFX Library@^1.12.1
	olikraus/U8g2 @ ~2.36.12

效果如下:

但是,这里的日期和时间是手动传入的:

rtc.setTime(0, 0, 0, 16, 8, 2025);  // 设置当前时间为2025年8月16日

接下来尝试一下通过ntp来同步网络时间:

需要的依赖:

NTPClient

WIFI(自带)

加入到项目:

我的项目名为rtc:

代码重写如下:

oled.h

#ifndef OLED_H
#define OLED_H

#include <U8g2lib.h>
#include <Arduino.h>

class OLED {
public:
  // 构造函数初始化引脚
  OLED(uint8_t clk, uint8_t mosi, uint8_t cs, uint8_t dc, uint8_t rst);
  
  // 初始化OLED
  void begin();
  
  // 显示时间(日期+时间)
  void displayTime(const String& date, const String& time);
  
  // 显示状态信息
  void displayStatus(const String& status);
  
  // 清空屏幕缓冲区
  void clearBuffer();
  
  // 发送缓冲区内容到屏幕
  void sendBuffer();

private:
  U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI _u8g2;
};

#endif

oled.cpp

#include "oled.h"

OLED::OLED(uint8_t clk, uint8_t mosi, uint8_t cs, uint8_t dc, uint8_t rst)
  : _u8g2(U8G2_R0, cs, dc, rst)  // 初始化U8G2对象
{
  // 引脚配置通过U8G2构造函数传递
}

void OLED::begin() {
  _u8g2.begin();
  _u8g2.enableUTF8Print();
  _u8g2.setFont(u8g2_font_wqy12_t_gb2312); // 设置中文字体
  _u8g2.clearBuffer();
  _u8g2.sendBuffer();
}

void OLED::clearBuffer() {
  _u8g2.clearBuffer();
}

void OLED::sendBuffer() {
  _u8g2.sendBuffer();
}

void OLED::displayTime(const String& date, const String& time) {
  clearBuffer();
  _u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  
  // 居中显示日期
  int dateWidth = _u8g2.getUTF8Width(date.c_str());
  int dateX = (128 - dateWidth) / 2;
  _u8g2.drawUTF8(dateX, 20, date.c_str());
  
  // 居中显示时间
  int timeWidth = _u8g2.getUTF8Width(time.c_str());
  int timeX = (128 - timeWidth) / 2;
  _u8g2.drawUTF8(timeX, 45, time.c_str());
  
  sendBuffer();
}

void OLED::displayStatus(const String& status) {
  clearBuffer();
  _u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  
  // 居中显示状态
  int statusWidth = _u8g2.getUTF8Width(status.c_str());
  int statusX = (128 - statusWidth) / 2;
  _u8g2.drawUTF8(statusX, 32, status.c_str());
  
  sendBuffer();
}

main.cpp

#include <Arduino.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP32Time.h>
#include "oled.h"

// OLED引脚配置
#define OLED_CLK  12
#define OLED_MOSI 11
#define OLED_CS   7
#define OLED_DC   6
#define OLED_RST  5

// WiFi配置 - 请修改为您的网络信息
const char* ssid = "你家的wifi";
const char* password = "你家的wifi密码";

// NTP配置
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600; // 北京时间 (UTC+8)
const int daylightOffset_sec = 0;    // 中国不使用夏令时

// 创建对象
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, ntpServer, gmtOffset_sec, daylightOffset_sec);
OLED oled(OLED_CLK, OLED_MOSI, OLED_CS, OLED_DC, OLED_RST);
ESP32Time rtc; // RTC对象

// 辅助函数:格式化数字为两位字符串
String formatTwoDigits(int number) {
  if (number < 10) {
    return "0" + String(number);
  }
  return String(number);
}

// 连接WiFi
void connectToWiFi() {
  Serial.print("正在连接WiFi: ");
  Serial.println(ssid);
  
  oled.displayStatus("连接WiFi中...");
  
  WiFi.begin(ssid, password);
  
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
    oled.displayStatus("WiFi连接中 " + String(attempts/2) + "秒");
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi连接成功!");
    Serial.print("IP地址: ");
    Serial.println(WiFi.localIP());
    oled.displayStatus("WiFi连接成功");
    delay(1000);
  } else {
    Serial.println("\nWiFi连接失败!");
    oled.displayStatus("WiFi连接失败");
    delay(3000);
  }
}

// 同步NTP时间
void syncNTPTime() {
  Serial.println("正在从NTP服务器获取时间...");
  oled.displayStatus("同步NTP时间");
  
  timeClient.begin();
  timeClient.update();
  
  if (timeClient.getEpochTime() > 1600000000) { // 验证时间是否合理(大于2020年)
    unsigned long epochTime = timeClient.getEpochTime();
    struct tm *ptm = gmtime((time_t *)&epochTime);
    
    // 设置RTC时间
    rtc.setTimeStruct(*ptm);
    
    Serial.print("NTP时间同步成功: ");
    Serial.println(timeClient.getFormattedTime());
    oled.displayStatus("时间同步成功");
    delay(1000);
  } else {
    Serial.println("NTP时间获取失败!");
    oled.displayStatus("时间同步失败");
    delay(3000);
  }
}

void setup() {
  Serial.begin(115200);
  
  // 初始化OLED
  oled.begin();
  
  // 连接WiFi
  connectToWiFi();
  
  // 同步NTP时间
  if (WiFi.status() == WL_CONNECTED) {
    syncNTPTime();
  } else {
    // 设置默认时间
    rtc.setTime(0, 0, 0, 16, 8, 2025);
    oled.displayStatus("使用默认时间");
    delay(1000);
  }
  
  // 显示初始完成信息
  oled.displayTime("时间已就绪", "00:00:00");
  delay(1000);
}

void loop() {
  // 直接从RTC获取时间组件
  int year = rtc.getYear();
  int month = rtc.getMonth() + 1;   // 月份从0开始,需要+1
  int day = rtc.getDay();
  int hour = rtc.getHour(true);     // 24小时制
  int minute = rtc.getMinute();
  int second = rtc.getSecond();
  
  // 构建日期字符串 (格式: YYYY年MM月DD日)
  String dateStr = String(year) + "年" + 
                   formatTwoDigits(month) + "月" + 
                   formatTwoDigits(day) + "日";
  
  // 构建时间字符串 (格式: HH:MM:SS)
  String timeStr = formatTwoDigits(hour) + ":" + 
                   formatTwoDigits(minute) + ":" + 
                   formatTwoDigits(second);
  
  // 显示到OLED
  oled.displayTime(dateStr, timeStr);
  
  // 每12小时重新同步一次时间
  static unsigned long lastSyncTime = 0;
  if (millis() - lastSyncTime > 12 * 3600 * 1000 && WiFi.status() == WL_CONNECTED) {
    syncNTPTime();
    lastSyncTime = millis();
  }
  
  // 串口打印调试信息
  static unsigned long lastPrint = 0;
  if (millis() - lastPrint > 1000) {
    Serial.print("当前时间: ");
    Serial.print(dateStr);
    Serial.print(" ");
    Serial.println(timeStr);
    lastPrint = millis();
  }
  
  delay(100);  // 短延时减少功耗
}

运行效果:

显示效果如下:

可以看到,现在可以通过wifi从ntp获取准确的时间了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FightingFreedom

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值