Many times, when we use ESP32 without the assistance of RTC clock chip, we need an external clock source to provide accurate time for synchronization.
After some understanding, you can use the NTP server to synchronize time.
/* Internet clock based on NTP server
*/
#include <Arduino.h>
#include <stdlib.h>
// Time library
#include <TimeLib.h>
// WiFi library
#include <WiFi.h>
#include <WiFiMulti.h>
#include <WiFiUdp.h>
#include <Wire.h>
//OLED library
#include <Adafruit_SSD1306.h>
#include <U8g2_for_Adafruit_GFX.h>
//OLED definition
//Screen size definition
#define SCREEN_WIDTH 128 // width
#define SCREEN_HEIGHT 64 // Height
//OLED I2C definition
#define OLED_RESET -1 // RESET
#define SCREEN_ADDRESS 0x3C // I2C address
// Adafruit_SSD1306 display object
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// U8G2_FOR_ADAFRUIT_GFX display object
U8G2_FOR_ADAFRUIT_GFX u8g2_for_adafruit_gfx;
//WiFi definition
#define WIFI_SSID "OpenBSD"
#define WIFI_PASS "13581882013"
WiFiMulti WiFiMulti;
//NTP definition
static const char ntpServerName[] = "ntp.aliyun.com";
const int timeZone = 8; // time zone
//Communication data packet definition
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE];
// UDP definition
WiFiUDP Udp;
unsigned int localPort = 8888;
// NTP method and object definition
time_t getNtpTime();
// Time display status
time_t prevDisplay = 0;
/**
* showtime display time
**/
void showtime() {
int Hour = hour();
int Min = minute();
int Sec = second();
int HourHigh, HourLow, MinHigh, MinLow, SecHigh, SecLow;
char buff[50];
sprintf(buff, "%02d:%02d:%02d", Hour, Min, Sec);
u8g2_for_adafruit_gfx.setFont(u8g2_font_fur20_tn); // Chinese font
u8g2_for_adafruit_gfx.setCursor(8, 52); // start writing at this position
u8g2_for_adafruit_gfx.print(buff);
}
/**
* getNtpTime NTP time synchronization
**/
time_t getNtpTime() {
IPAddress ntpServerIP; //NTP server address
while (Udp.parsePacket() > 0)
; // Discard any previously received packets
// Initiate NTP request
Serial.println("Transmit NTP Request");
WiFi.hostByName(ntpServerName, ntpServerIP); // Get IP
Serial.print(ntpServerName);
Serial.print(": ");
Serial.println(ntpServerIP);
sendNTPpacket(ntpServerIP); // Send data packet
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // Read data packet
unsigned long secsSince1900;
// Convert data
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
// Return data
return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response :-(");
return 0;
}
/**
* sendNTPpacket sends NTP data packets
**/
void sendNTPpacket(IPAddress &address) {
//Clear buff
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Generate request data
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// Send NTP data packet
Udp.beginPacket(address, 123);
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
void setup() {
//Serial port initialization
Serial.begin(115200);
// Communication initialization
Wire.begin();
// OLED initialization
Serial.println(F("SSD1306 init:"));
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;)
; // loop
} else {
Serial.println(F("SSD1306 allocation ok"));
}
// Display the default Adafruit splash screen
display.display();
delay(1000);
// Associate u8g8 to Adafruit GFX
u8g2_for_adafruit_gfx.begin(display);
//WiFi connection processing
WiFiMulti.addAP(WIFI_SSID, WIFI_PASS);
while (WiFiMulti.run() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
// Open UDP
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(localPort);
Serial.println("waiting for sync");
// Set NTP time synchronization
setSyncProvider(getNtpTime);
setSyncInterval(300);
// Delay
delay(500);
}
void loop() {
// Display time
if (timeStatus() != timeNotSet) { // Check and update the latest time
if (now() != prevDisplay) {
prevDisplay = now();
// Clear the display cache
display.clearDisplay();
// Picture frame
display.drawRoundRect(0, 0, display.width() - 1, 16, 1, SSD1306_WHITE); // Status bar
display.drawRoundRect(0, 16, display.width() - 1, display.height() - 16, 1, SSD1306_WHITE); // Content area
u8g2_for_adafruit_gfx.setFontDirection(0); // Display direction: from left to right (default)
u8g2_for_adafruit_gfx.setForegroundColor(WHITE); // Apply Adafruit GFX color
u8g2_for_adafruit_gfx.setFont(u8g2_font_unifont_t_chinese2); // Chinese font
u8g2_for_adafruit_gfx.setCursor(25, 12); // Display coordinates
u8g2_for_adafruit_gfx.print("Net Clock");
showtime(); // Display time
// show
display.display();
}
}
// Delay
delay(50);
}
In the actual test verification, an ESP32-E development board and an SSD 1306 128x64 OLED were used. The specific results are as follows: