Go Down

Topic: UDP NTP Client - NIST Internet Time Service changes (Read 5 times) previous topic - next topic


Thanks SurferDude,
I will look at putting that code into my project.

Will this patch be included before the next release for people, otherwise there could potentially be a flood of questions?



Dec 19, 2012, 01:55 pm Last Edit: Dec 19, 2012, 02:03 pm by SurferTim Reason: 1
I modified the code to include error checking on the dns resolution. It should look like this:
Code: [Select]
 // you probably want this IP global
 IPAddress ntpIP;

 DNSClient dns;

 if(dns.getHostByName("pool.ntp.org",ntpIP)) {
   Serial.print("NTP IP from the pool: ");
 else Serial.println("dns lookup failed");

edit: Renamed IP variable to ntpIP.


Dec 19, 2012, 04:42 pm Last Edit: Dec 20, 2012, 05:16 pm by SurferTim Reason: 1
This is the UdpNtpClient example modified for dhcp and dns NTP server. Let me know if it works for you.
Code: [Select]
Udp NTP Client with DHCP and dns acquired NTP server IP

Get the time from a Network Time Protocol (NTP) time server
Demonstrates use of UDP sendPacket and ReceivePacket
For more on NTP time servers and the messages needed to communicate with them,
see http://en.wikipedia.org/wiki/Network_Time_Protocol

created 4 Sep 2010
by Michael Margolis
modified 17 Sep 2010
by Tom Igoe
modified 19 Dec 2012
by Tim Dicus

This code is in the public domain.
#include <SPI.h>        
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Dns.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer; // pool.ntp.org NTP server

const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

char weekday[7][4] = {"THU","FRI","SAT","SUN","MON","TUE","WED"};

void setup()

 // disable SD SPI while starting w5100
 Serial.print(F("Starting w5100..."));
 else {
  Serial.print(F("ip = "));

 DNSClient dns;
 if(dns.getHostByName("pool.ntp.org",timeServer)) {
   Serial.print(F("NTP server ip :"));
 else Serial.print(F("dns lookup failed"));


void loop()
 sendNTPpacket(timeServer); // send an NTP packet to a time server

   // wait to see if a reply is available
 if ( Udp.parsePacket() ) {  
   // We've received a packet, read the data from it
   Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer

   //the timestamp starts at byte 40 of the received packet and is four bytes,
   // or two words, long. First, esxtract the two words:

   unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
   unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);  
   // combine the four bytes (two words) into a long integer
   // this is NTP time (seconds since Jan 1 1900):
   Serial.print(" ");
   Serial.print(" ");
   Serial.print(" ");
   unsigned long secsSince1900 = highWord << 16 | lowWord;  
   Serial.print(F("Seconds since Jan 1 1900 = " ));

   // now convert NTP time into everyday time:
   Serial.print(F("Unix time = "));
   // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
   const unsigned long seventyYears = 2208988800UL;    
   // subtract seventy years:
   unsigned long epoch = secsSince1900 - seventyYears;  
   // print Unix time:

   unsigned long dayCount = epoch / 86400UL;
   Serial.print(F("DayCount = "));

   Serial.print(F("Day of week = "));

   // print the hour, minute and second:
   Serial.print(F("The UTC time is "));       // UTC is the time at Greenwich Meridian (GMT)
   Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day)
   if ( ((epoch % 3600) / 60) < 10 ) {
     // In the first 10 minutes of each hour, we'll want a leading '0'
   Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
   if ( (epoch % 60) < 10 ) {
     // In the first 10 seconds of each minute, we'll want a leading '0'
   Serial.println(epoch %60); // print the second

 // wait another 599 seconds (one second delay was above)  10 minutes
 for(int y=0;y<599;y++)
    // count off the minutes
    if(y%60 == 0) Serial.println(y/60);

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address)
 // set all bytes in the buffer to 0
 memset(packetBuffer, 0, NTP_PACKET_SIZE);
 // Initialize values needed to form NTP request
 // (see URL above for details on the packets)
 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;

 // all NTP fields have been given values, now
 // you can send a packet requesting a timestamp:  
 Udp.beginPacket(address, 123); //NTP requests are to port 123

edit: Corrected time delay loop again. It counts off the minutes and checks time every 10 minutes (was 1 minute). I was on to the second after 10 minutes.


Dec 20, 2012, 03:41 pm Last Edit: Dec 20, 2012, 03:45 pm by MichaelMeissner Reason: 1

edit: Corrected time delay loop. It checks time every minute.

From an internet perspective, you really should not be polling the NTP server every minute.  If every device on the internet does this, it will eventually mean people will stop offering NTP servers, and the infrastructure will be clogged with all of these packets to the remaining hosts offering the service.

Also, if you pay for your internet as a metered service, having your device continually polling the NTP server will mean you will get pushed over your limit and either it will slow down your connection, it will start charging you more, or cut off service all together (I've seen all 3 in cell phone contracts).

Poll once when you start up, and then keep local time, and poll every so often (every few hours perhaps) to adjust the time.  In terms of keeping local time, perhaps getting one of the real time clocks, and use that.  Use NTP occasionally to update the clock.

Also, having the delays in the code means your device can't do anything else while it is waiting for a response, unless you are using interrupts.  I do wish the Arduino library provided a standard way of doing blink without delay that all of the library functions used.


Dec 20, 2012, 03:48 pm Last Edit: Dec 20, 2012, 05:18 pm by SurferTim Reason: 1
Hi Michael. I agree. I used that only as a test. This should really be used with a RTC, and checked every hour or so. The real purpose was to show how close I could come to the correct time just using delay(). The millis routine would probably be even better (more accurate?). It appears the original code may have checked even more often that this.  :(

If this works for most, I will put this code in the wiki with a longer delay and a warning to that effect.

Also, having the delays in the code means your device can't do anything else while it is waiting for a response, unless you are using interrupts.

Not quite true. That is why I divide that 59 second time up into 1 second delays. A switch-case on the loop counter works well for "time slicing".

edit: I didn't like the one minute thing. I changed it to check every 10 minutes, and count off the minutes since the last check.

Go Up