Pages: [1]   Go Down
Author Topic: Ways to update the RTC DS3231 from NTP server  (Read 1257 times)
0 Members and 1 Guest are viewing this topic.
Czech Republic
Offline Offline
Sr. Member
****
Karma: 3
Posts: 309
Absolute Beginner, yet.
Newbie in Arduino
since May 2013
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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


* Update_RTC_from_NTP.ino (20.86 KB - downloaded 62 times.)
Logged

Arduino Uno R3, Arduino Mega 2560 R3, Ethermega (R3), and some Ethernet Shields (R3), Chronodots, TMP36 sensors, DS18B20 sensors, LCDs/TFTs, RS232C to learn and play...

Offline Offline
Full Member
***
Karma: 3
Posts: 104
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
byte ip[4];

where you store the IP address of an online NTP server

you then call the function:

Code:
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

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

Code:
#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();
}
Logged

Czech Republic
Offline Offline
Sr. Member
****
Karma: 3
Posts: 309
Absolute Beginner, yet.
Newbie in Arduino
since May 2013
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

* NTP_RTC_TFT18_LCD_v020.ino (34.06 KB - downloaded 56 times.)
Logged

Arduino Uno R3, Arduino Mega 2560 R3, Ethermega (R3), and some Ethernet Shields (R3), Chronodots, TMP36 sensors, DS18B20 sensors, LCDs/TFTs, RS232C to learn and play...

Australia
Offline Offline
Jr. Member
**
Karma: 0
Posts: 99
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#define TIME_ZONE_HALF 0  /*, 1 or -1*/
then modify line 559 to:
Code:
result = secsSince1900 - 2208988800UL + TIME_ZONE_INT * SECS_PER_HOUR + TIME_ZONE_HALF * SECS_PER_HOUR / 2;
Logged

Czech Republic
Offline Offline
Sr. Member
****
Karma: 3
Posts: 309
Absolute Beginner, yet.
Newbie in Arduino
since May 2013
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Arduino Uno R3, Arduino Mega 2560 R3, Ethermega (R3), and some Ethernet Shields (R3), Chronodots, TMP36 sensors, DS18B20 sensors, LCDs/TFTs, RS232C to learn and play...

Pages: [1]   Go Up
Jump to: