之前实现了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获取准确的时间了。
1万+

被折叠的 条评论
为什么被折叠?



