Go Down

Topic: Ways to update the RTC DS3231 from NTP server (Read 8872 times) previous topic - next topic


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


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:

Code: [Select]
byte ip[4];

where you store the IP address of an online NTP server

you then call the function:

Code: [Select]

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

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

Code: [Select]

#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.write(decToBcd(set_second));    // 0 to bit 7 starts the clock
  Wire.write(0x10); // sends 0x10 (hex) 00010000 (binary) to control register - turns on square wave

// 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.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
    // 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):
    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


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 ;-)


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:
Code: [Select]

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

then modify line 559 to:
Code: [Select]

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.

Go Up