Ways to update the RTC DS3231 from NTP server

And because I'm a beginner, it will not be perfect.

Update_RTC_from_NTP.ino (20.9 KB)

K5CZ:
And because I'm a beginner, it will not be perfect.

i have code i use for my RTC. here is what you do.
you have a variable:

byte ip[4];

where you store the IP address of an online NTP server

you then call the function:

GET_NTP_TIME

where the time zone for my area is -6 since i am in central America.

This function stores the NTP time in the variables SETHOUR, SETMINUTE, and SETSECONDS. you can add code so it calculates the months, days and years as well.

when you have the new time, you call

setDateDs1307 to set the date within the clock. you then can call getDateDs1307 to get the time from the clock. it works perfectly for me, but i am using a DS1307

#include <EthernetUdp.h>
#define localPort 8888      // local port to listen for UDP packets. needed for the NTP servers for time updating
#define 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
EthernetUDP Udp;// A UDP instance to let us send and receive packets over UDP

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock

// Assumes you're passing in valid numbers

void setDateDs1307(byte set_second,        // 0-59
byte set_minute,        // 0-59
byte set_hour,          // 1-23
byte set_dayOfWeek,     // 1-7
byte set_dayOfMonth,    // 1-28/29/30/31
byte set_month,         // 1-12
byte set_year)          // 0-99
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(set_second));    // 0 to bit 7 starts the clock
  Wire.write(decToBcd(set_minute));
  Wire.write(decToBcd(set_hour));     
  Wire.write(decToBcd(set_dayOfWeek));
  Wire.write(decToBcd(set_dayOfMonth));
  Wire.write(decToBcd(set_month));
  Wire.write(decToBcd(set_year));
  Wire.write(0x10); // sends 0x10 (hex) 00010000 (binary) to control register - turns on square wave
  Wire.endTransmission();
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *get_second,
byte *get_minute,
byte *get_hour,
byte *get_dayOfWeek,
byte *get_dayOfMonth,
byte *get_month,
byte *get_year)
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  *get_second     = bcdToDec(Wire.read() & 0x7f);
  *get_minute     = bcdToDec(Wire.read());
  *get_hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
  *get_dayOfWeek  = bcdToDec(Wire.read());
  *get_dayOfMonth = bcdToDec(Wire.read());
  *get_month      = bcdToDec(Wire.read());
  *get_year       = bcdToDec(Wire.read());
}

void GET_NTP_TIME(int timezone)
{
  sendNTPpacket(); // send an NTP packet to a time server
  //wdt_reset();
    // wait to see if a reply is available
  delay(1000);  
  wdt_reset();
  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):
    unsigned long secsSince1900 = highWord << 16 | lowWord;  

    // 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 the hour, minute and second:    
    SETHOUR = int(((epoch+(timezone*3600))  % 86400)/3600);      
    SETMINUTE = int((epoch  % 3600)/60); 
    SETSECONDS = int(epoch %60);
  }
}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(void)
{
  // 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(ip, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket();
}

Here is my latest version - I use this program also for testing TFT and LCD displays (and also as a LCD clock), so this makes program a little bit complicated :wink:

NTP_RTC_TFT18_LCD_v020.ino (34.1 KB)

wallaceb:
where the time zone for my area is -6 since i am in central America.

And yet you forget your fairly close Venezuelan neighbours and fail to include non-integer timezones (UTC -4:30).

I often encounter this problem, as I live in Central Australia (UTC+9:30).

K5CZ's code has the same deficiency, his is probably easier to fix with:

after line 130 add a new line with:

#define TIME_ZONE_HALF 0  /*, 1 or -1*/

then modify line 559 to:

result = secsSince1900 - 2208988800UL + TIME_ZONE_INT * SECS_PER_HOUR + TIME_ZONE_HALF * SECS_PER_HOUR / 2;

I was never deeply interested in the timezone standard, but I noticed that the time shift is sometime counted in minutes instead of hours - so now I know why.

K5CZ:
Here is my latest version - I use this program also for testing TFT and LCD displays (and also as a LCD clock), so this makes program a little bit complicated :wink:

Sorry, but I´m missing something, please can you help me,

Severity Code Description Project File Line Suppression State
Error (active) identifier "tmElements_t" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 145
Error (active) identifier "month" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 268
Error (active) identifier "makeTime" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 399
Error (active) identifier "now" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 467
Error (active) identifier "day" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 471
Error (active) identifier "month" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 472
Error (active) identifier "monthShortStr" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 474
Error (active) identifier "year" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 479
Error (active) identifier "hour" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 480
Error (active) identifier "minute" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 481
Error (active) identifier "second" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 482
Error (active) identifier "weekday" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 488
Error (active) identifier "dayStr" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 491
Error (active) identifier "dayShortStr" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 494
Error (active) identifier "setSyncProvider" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 673
Error (active) identifier "setTime" is undefined rtcntp z:\Documents\Arduino\MeteorologyWeatherStation\rtcntp\rtcntp.ino 676

K5CZ:
Here is my latest version - I use this program also for testing TFT and LCD displays (and also as a LCD clock), so this makes program a little bit complicated :wink:

Hi ! I have a question. If for any reason, you lose connectivity after having acquired ip from the dhcp, how do you prevent the update by ntp from hanging the main loop? Thanks

Hi

Some useful information here as well: Here's how to get a more accurate RTC clock set from an NTP time server