Have you ever wondered why your phone and computer always show the exact time without needing manual adjustments like traditional watches? The answer is NTP (Network Time Protocol)!
NTP is an internet protocol that allows devices to obtain precise time information from time servers over the network. For the Arduino UNO R4 WiFi, NTP can completely replace the traditional RTC (Real-Time Clock) module - the onboard WiFi module can directly connect to the internet and retrieve accurate time from public NTP servers, eliminating the need to purchase an additional clock module!
In this tutorial, you will learn:
This functionality is perfect for data logging, timers, IoT time-triggered devices, or any project that requires precise timekeeping!
NTP time synchronization requires two core functionalities: WiFi connection (to access the internet) and UDP communication (to send/receive NTP data). The Arduino UNO R4 WiFi's onboard ESP32-S3 module perfectly supports both functionalities, without requiring any additional hardware or modules.
| Item | Description |
|---|---|
| Hardware | Arduino UNO R4 WiFi Development Board |
| Connection Cable | USB-C data cable (for power and serial communication) |
| Network | 2.4G WiFi network (with internet access; 5G not supported) |
| Software | Computer with Arduino IDE installed |
| Core Library | WiFiS3 (Built-in for UNO R4 series) |
| Core Library | WiFiUdp (Built-in for UNO R4 series) |
Functionality:
WiFiS3 is a WiFi communication library specifically designed by Arduino for the ESP32-S3 module on the UNO R4 WiFi, providing the following core functions:
| Function Category | Specific Function | Example Functions |
|---|---|---|
| Connection Management | Connect/disconnect WiFi network | WiFi.begin(), WiFi.disconnect() |
| Status Query | Get connection status and network info | WiFi.status(), WiFi.localIP() |
| Network Information | Get IP, MAC, signal strength | WiFi.macAddress(), WiFi.RSSI() |
| DNS Resolution | Resolve domain name to IP address | WiFi.hostByName() |
Installation Method:
The WiFiS3 library is pre-installed in the board's core firmware at the factory. No manual download or installation is required. Simply import it in your code to use.
Exception Handling (Missing Library File):
If the Arduino IDE shows WiFiS3.h: No such file or directory during compilation, it means the board's core library is not installed correctly or the version is too old. Follow these steps to resolve:
Functionality:
WiFiUdp is an Arduino built-in UDP communication library for implementing lightweight network data transmission:
| Function Category | Specific Function | Example Functions |
|---|---|---|
| Initialization | Start UDP connection | Udp.begin(port) |
| Send Data | Send UDP packet | Udp.beginPacket(), Udp.write(), Udp.endPacket() |
| Receive Data | Receive UDP packet | Udp.parsePacket(), Udp.read() |
Why UDP Instead of TCP?
NTP protocol uses UDP instead of TCP for simple reasons:
Installation Method:
WiFiUdp library is part of the Arduino core library, no separate installation required for any Arduino board.
Understanding how NTP works helps you troubleshoot issues and modify the code. Here's a plain-language explanation of the entire process:
Step 1: Connect to WiFi
Just like your phone connects to a router to access the internet, the Arduino UNO R4 WiFi first connects to your home's 2.4G WiFi network (STA mode) and gains internet access.
Step 2: Find NTP Server
The board needs to know the NTP server's IP address. It uses DNS functionality to convert the domain name (like pool.ntp.org) into an IP address. This is similar to when you enter "www.google.com" in your browser, and it automatically finds Google's server IP address.
Step 3: Send Request
The board sends a 48-byte "request packet" to the NTP server via UDP protocol. This packet is like a letter saying "Please tell me what time it is now!" The NTP server uses port 123 by default.
Step 4: Receive Response
After receiving the request, the NTP server replies with a data packet containing a timestamp (the number of seconds elapsed since January 1, 1970, 00:00:00 UTC). This timestamp is in UNIX timestamp format.
Step 5: Convert Time
After receiving the timestamp, the board performs two operations:
Step 6: Display Time
Finally, the board converts the seconds into year, month, day, hour, minute, second format and displays it through the Serial Monitor, showing you the accurate time.
Mastering the following key parameters and functions allows you to modify the code according to your region or project requirements.
At the beginning of the code, you'll see these key parameters:
const char* ntpServer = "pool.ntp.org"; // NTP server domain
const unsigned int localPort = 8888; // Local UDP port
const long TIME_ZONE = 0 * 3600; // Timezone offset (seconds)
| Parameter | Description | Example |
|---|---|---|
ntpServer |
NTP server domain name. We use pool.ntp.org (global public NTP server network), but you can also use region-specific servers (e.g., China uses cn.pool.ntp.org, US uses time.nist.gov) |
"pool.ntp.org" |
localPort |
Local UDP port for receiving NTP responses. Can use any unused port (1024-65535) | 8888 |
TIME_ZONE |
Timezone offset (seconds). For example, Beijing time UTC+8 is 8 * 3600 (3600 seconds = 1 hour), New York UTC-5 is -5 * 3600 |
8 * 3600 |
Timezone Reference Table:
| Region | Timezone | TIME_ZONE Setting |
|---|---|---|
| Beijing/Shanghai/Hong Kong | UTC+8 | 8 * 3600 |
| Tokyo | UTC+9 | 9 * 3600 |
| Berlin/Paris | UTC+1 | 1 * 3600 |
| London | UTC+0 | 0 * 3600 |
| New York (Winter) | UTC-5 | -5 * 3600 |
| New York (Summer) | UTC-4 | -4 * 3600 |
| Los Angeles (Winter) | UTC-8 | -8 * 3600 |
| Los Angeles (Summer) | UTC-7 | -7 * 3600 |
WiFi.begin(ssid, password)
ssid (WiFi name, string), password (WiFi password, string)WiFi.status()
WL_CONNECTED (value 3) indicates successful connectionWiFi.localIP()
0.0.0.0 indicates DHCP allocation failureWiFi.hostByName(ntpServer, ip)
ip variablentpServer (domain name), ip (variable to store IP address)true on success, false on failureUdp.begin(localPort)
localPort (port number)Udp.beginPacket(ip, 123)
ip (server IP address), 123 (NTP port)Udp.write(packet, 48)
packet (data array), 48 (data length)Udp.endPacket()
Udp.parsePacket()
Udp.read(packet, 48)
packet arraypacket (array to store data), 48 (read length)getNtpTime()
currentUnixTimeprintTime(unsigned long seconds)
isLeap(int y)
true for leap year, false for common yearUsage: Open the NTP_TIME folder in the same directory, modify the SSID and password in the code to match your WiFi credentials, adjust the TIME_ZONE parameter according to your timezone, then upload the program to your Arduino UNO R4 board.
#include <WiFiS3.h>
#include <WiFiUdp.h>
WiFiS3.h: WiFi library specifically for Arduino UNO R4 WiFiWiFiUdp.h: UDP communication library for sending and receiving NTP dataconst char* ssid = ""; // Your WiFi name
const char* password = ""; // Your WiFi password
| Parameter | Description |
|---|---|
ssid |
WiFi network name (case-sensitive) |
password |
WiFi network password (case-sensitive) |
⚠️ Important: You must replace the content inside "" with your actual WiFi name and password!
const char* ntpServer = "pool.ntp.org";
const unsigned int localPort = 8888;
const long TIME_ZONE = 0 * 3600;
ntpServer: Global public NTP server, Chinese users can change to "cn.pool.ntp.org"localPort: Local UDP port, can use any unused port between 1024-65535TIME_ZONE: Must be modified according to your timezone! For Beijing time, change to 8 * 3600WiFiUDP Udp;
unsigned long currentUnixTime = 0;
unsigned long lastUpdate = 0;
Udp: UDP object for communicationcurrentUnixTime: Stores UNIX timestamp obtained from NTP serverlastUpdate: Records last sync time for periodic updatesvoid setup() {
Serial.begin(9600);
while (!Serial);
// Connect to WiFi
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED || WiFi.localIP() == IPAddress(0,0,0,0)) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected successfully!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Udp.begin(localPort);
Serial.println("Waiting for NTP time sync...\n");
}
Lines 5-6: Start serial communication (9600 baud rate), wait for Serial Monitor to open.
Lines 8-10: Print prompt message, start WiFi connection.
Lines 12-15: ⚠️ Critical Code!
This is a while loop with conditions:
WiFi.status() != WL_CONNECTED: WiFi not connectedWiFi.localIP() == IPAddress(0,0,0,0): IP address is 0.0.0.0Why Double-Check?
Because UNO R4 WiFi has a firmware bug where sometimes WiFi.status() returns connected, but IP address is still 0.0.0.0, causing no internet access. By double-checking, we ensure a valid IP address is truly obtained.
Lines 17-20: Print connection success message and IP address.
Line 22: Start UDP connection, listen on port 8888.
void loop() {
// Sync time every 10 seconds
if (millis() - lastUpdate > 10000) {
getNtpTime();
lastUpdate = millis();
}
// Show current time
printTime(currentUnixTime + (millis() - lastUpdate) / 1000);
delay(1000);
}
Lines 3-6: Sync NTP time every 10 seconds
millis(): Returns milliseconds since program startgetNtpTime() to sync timeLine 9: Display current time
currentUnixTime: Base time from NTP(millis() - lastUpdate) / 1000: Add elapsed seconds to keep time continuously updatingLine 10: Refresh display every second
void getNtpTime() {
IPAddress ip;
if (!WiFi.hostByName(ntpServer, ip)) return;
byte packet[48] = {0};
packet[0] = 0b11100011;
Udp.beginPacket(ip, 123);
Udp.write(packet, 48);
Udp.endPacket();
delay(150);
if (Udp.parsePacket()) {
Udp.read(packet, 48);
unsigned long sec = word(packet[40], packet[41]) << 16 | word(packet[42], packet[43]);
currentUnixTime = sec - 2208988800UL + TIME_ZONE;
}
}
Line 3: DNS resolution, convert domain name to IP address. If failed, return directly.
Lines 5-6: Construct NTP request packet
0b11100011 (NTP protocol format requirement)Lines 8-10: Send UDP packet
Lines 12-16: Receive and parse response
sec - 2208988800UL + TIME_ZONE
void printTime(unsigned long seconds) {
// Extract time components
int sec = seconds % 60;
seconds /= 60;
int min = seconds % 60;
seconds /= 60;
int hour = seconds % 24;
seconds /= 24;
// Calculate year
int year = 1970;
while (true) {
unsigned long days = isLeap(year) ? 366 : 365;
if (seconds < days) break;
seconds -= days;
year++;
}
// Calculate month and day
int monthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (isLeap(year)) monthDays[1] = 29;
int mon = 0;
while (seconds >= monthDays[mon]) seconds -= monthDays[mon++];
int day = seconds + 1;
// Print formatted time
Serial.print("Current Time: ");
Serial.print(year);Serial.print("-");
if(mon+1<10)Serial.print("0");Serial.print(mon+1);Serial.print("-");
if(day<10)Serial.print("0");Serial.print(day);Serial.print(" ");
if(hour<10)Serial.print("0");Serial.print(hour);Serial.print(":");
if(min<10)Serial.print("0");Serial.print(min);Serial.print(":");
if(sec<10)Serial.print("0");Serial.println(sec);
}
Lines 3-8: Extract hours, minutes, seconds
seconds % 60: Get seconds through moduloseconds /= 60: Get minutes through divisionLines 11-17: Calculate year
Lines 20-24: Calculate month and day
Lines 27-33: Format and print
if to add leading zeros (e.g., March displays as "03")YYYY-MM-DD HH:MM:SSbool isLeap(int y) {
return (y%4==0&&y%100!=0)||(y%400==0);
}
Leap Year Rules:
Examples:
| Parameter | Value | Description |
|---|---|---|
ssid |
String | WiFi network name (required) |
password |
String | WiFi network password (required) |
ntpServer |
"pool.ntp.org" |
NTP server domain |
localPort |
8888 |
Local UDP port |
TIME_ZONE |
8 * 3600 |
Timezone offset (Beijing time) |
Serial.begin(9600) |
9600 |
Serial baud rate (must match Serial Monitor) |
delay(150) |
150ms |
Wait time for NTP response |
| Sync Interval | 10000ms |
Sync time every 10 seconds |
Connecting to WiFi: MyHomeWiFi
.....
WiFi connected successfully!
IP Address: 192.168.1.105
Waiting for NTP time sync...
Current Time: 2024-05-20 14:30:05
Current Time: 2024-05-20 14:30:06
Current Time: 2024-05-20 14:30:07
Current Time: 2024-05-20 14:30:08
Current Time: 2024-05-20 14:30:09
Current Time: 2024-05-20 14:30:10
...
If time displays as 1970-00-00 00:00:00, it means no NTP server response received, please check network connection.
Symptom: Serial Monitor shows "WiFi connected successfully!" but IP address is 0.0.0.0, NTP sync fails.
Solutions:
Symptom: Serial Monitor shows "Waiting for NTP time sync..." then time keeps displaying 1970-00-00 00:00:00.
Solutions:
pool.ntp.org to cn.pool.ntp.org or time.nist.gov)delay(150) in getNtpTime() function to 200ms or 300ms (some networks have higher latency)Symptom: Time is displayed but incorrect (e.g., wrong timezone, wrong date).
Solutions:
TIME_ZONE parameter to match your local timezone (e.g., UTC+0 is 0, UTC+5 is 5*3600, UTC+8 is 8*3600)2208988800UL constant exists (this converts NTP time to UNIX time; removing it causes incorrect timestamps)isLeap() function works correctly (incorrect leap year detection causes wrong month/day)Symptom: Serial Monitor continuously shows dots, never connects to WiFi.
Solutions:
Easily modify the code according to your project needs:
if (millis() - lastUpdate > 10000) { // 10000ms = 10 seconds
Change to:
if (millis() - lastUpdate > 300000) { // 300000ms = 5 minutes
const char* ntpServer = "pool.ntp.org"; // Global
Change to:
const char* ntpServer = "cn.pool.ntp.org"; // China
Other options:
cn.pool.ntp.orguk.pool.ntp.orgus.pool.ntp.org or time.nist.govjp.pool.ntp.orgconst long TIME_ZONE = 8 * 3600; // Beijing time
Modify according to your timezone:
-5 * 36009 * 36001 * 3600Modify printTime() function to output to LCD screen (requires connecting LCD module and importing corresponding library):
void printTime(unsigned long seconds) {
// ... original time calculation code ...
lcd.setCursor(0, 0);
lcd.print(year); lcd.print("-");
lcd.print(mon+1); lcd.print("-");
lcd.print(day); lcd.print(" ");
lcd.print(hour); lcd.print(":");
lcd.print(min); lcd.print(":");
lcd.print(sec);
}
Combine with temperature, humidity, and other sensor readings to log timestamped data:
void loop() {
// ... time sync code ...
float temp = readTemperature(); // Hypothetical temperature reading function
Serial.print("Time: ");
printTime(currentUnixTime);
Serial.print(" Temperature: ");
Serial.print(temp);
Serial.println("°C");
delay(1000);
}
After mastering NTP time synchronization, you can try the following projects: