Difference between revisions of "Arduino: RTC DS3231 NTP Sync"
		
		
		
		
		
		Jump to navigation
		Jump to search
		
				
		
		
	
Onnowpurbo (talk | contribs)  (Created page with "==Source==   #include "Wire.h" #include <Time.h> #include <SPI.h> #include <Ethernet.h> #include <EthernetUdp.h>  #define DS3231_I2C_ADDRESS 0x68  // Ethernet library configur...")  | 
				Onnowpurbo (talk | contribs)   | 
				||
| Line 2: | Line 2: | ||
| − | #include "Wire.h"  | + |  #include "Wire.h"  | 
| − | #include <Time.h>  | + |  #include <Time.h>  | 
| − | #include <SPI.h>  | + |  #include <SPI.h>  | 
| − | #include <Ethernet.h>  | + |  #include <Ethernet.h>  | 
| − | #include <EthernetUdp.h>  | + |  #include <EthernetUdp.h>  | 
| − | + | ||
| − | #define DS3231_I2C_ADDRESS 0x68  | + |  #define DS3231_I2C_ADDRESS 0x68  | 
| − | + | ||
| − | // Ethernet library configuration  | + |  // Ethernet library configuration  | 
| − | byte mac[] = { 0x24, 0x7B, 0xA2, 0x4A, 0x52, 0x10 };  | + |  byte mac[] = { 0x24, 0x7B, 0xA2, 0x4A, 0x52, 0x10 };  | 
| − | IPAddress timeServer(128, 138, 140, 44 ); // time.nist.gov  | + |  IPAddress timeServer(128, 138, 140, 44 ); // time.nist.gov  | 
| − | + | ||
| − | unsigned int localPort = 8888;  | + |  unsigned int localPort = 8888;  | 
| − | const int NTP_PACKET_SIZE= 48;        | + |  const int NTP_PACKET_SIZE= 48;        | 
| − | byte packetBuffer[NTP_PACKET_SIZE];    | + |  byte packetBuffer[NTP_PACKET_SIZE];    | 
| − | EthernetUDP Udp;  | + |  EthernetUDP Udp;  | 
| − | + | ||
| − | void setup()  | + |  void setup()  | 
| − | {  | + |  {  | 
| − | + |    // Setup Communication  | |
| − | + |    Wire.begin();  | |
| − | + |    Serial.begin(9600);  | |
| − | + |    Serial.print("OK Serial\n");  | |
| − | + |    Ethernet.begin(mac);  | |
| − | + |    Serial.print("OK LAN\n");  | |
| − | + |    Udp.begin(localPort);  | |
| − | + | ||
| − | + |    Serial.print("OK Comm\n");  | |
| − | + |    setSyncInterval(10); // Set seconds between re-sync  | |
| − | + |    setSyncProvider(getNtpTime);  | |
| − | + |    getNtpTime;  | |
| − | + |    Serial.print("OK NTP\n");  | |
| − | + | ||
| − | + |    // set the initial time here:  | |
| − | + |    // DS3231 seconds, minutes, hours, day, date, month, year  | |
| − | + |    // setDS3231time(30,33,9, 2 ,28,11,16);  | |
| − | }  | + |  }  | 
| − | + | ||
| − | void loop()  | + |  void loop()  | 
| − | {  | + |  {  | 
| − | + |    setSyncProvider(getNtpTime);  | |
| − | + |    // set the initial time here:  | |
| − | + |    // DS3231 seconds, minutes, hours, day, date, month, year  | |
| − | + |    setDS3231time(second(), minute(), hour()+7, 5 , 7, 6, 18);  | |
| − | + | ||
| − | + |    displayTime(); // display the real-time clock data on the Serial Monitor,  | |
| − | + |    getNtpTime;  | |
| − | + |    // delay(1000);     | |
| − | }  | + |  }  | 
| − | + | ||
| − | + |  /*----------------- DS3231 ----------------------*/  | |
| − | + | ||
| − | /*----------------- DS3231 ----------------------*/  | + |  // Convert normal decimal numbers to binary coded decimal  | 
| − | + |  byte decToBcd(byte val)  | |
| − | // 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)  | 
| − | // Convert binary coded decimal to normal decimal numbers  | + |  {  | 
| − | byte bcdToDec(byte val)  | + |    return ( (val / 16 * 10) + (val % 16) );  | 
| − | {  | + |  }  | 
| − | + | ||
| − | }  | + |  void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte  | 
| − | + |                     dayOfMonth, byte month, byte year)  | |
| − | void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte  | + |  {  | 
| − | + |    // sets time and date data to DS3231  | |
| − | {  | + |    Wire.beginTransmission(DS3231_I2C_ADDRESS);  | 
| − | + |    Wire.write(0); // set next input to start at the seconds register  | |
| − | + |    Wire.write(decToBcd(second)); // set seconds  | |
| − | + |    Wire.write(decToBcd(minute)); // set minutes  | |
| − | + |    Wire.write(decToBcd(hour)); // set hours  | |
| − | + |    Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)  | |
| − | + |    Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)  | |
| − | + |    Wire.write(decToBcd(month)); // set month  | |
| − | + |    Wire.write(decToBcd(year)); // set year (0 to 99)  | |
| − | + |    Wire.endTransmission();  | |
| − | + |  }  | |
| − | + |  void readDS3231time(byte *second,  | |
| − | }  | + |                      byte *minute,  | 
| − | void readDS3231time(byte *second,  | + |                      byte *hour,  | 
| − | + |                      byte *dayOfWeek,  | |
| − | + |                      byte *dayOfMonth,  | |
| − | + |                      byte *month,  | |
| − | + |                      byte *year)  | |
| − | + |  {  | |
| − | + |    Wire.beginTransmission(DS3231_I2C_ADDRESS);  | |
| − | {  | + |    Wire.write(0); // set DS3231 register pointer to 00h  | 
| − | + |    Wire.endTransmission();  | |
| − | + |    Wire.requestFrom(DS3231_I2C_ADDRESS, 7);  | |
| − | + |    // request seven bytes of data from DS3231 starting from register 00h  | |
| − | + |    *second = bcdToDec(Wire.read() & 0x7f);  | |
| − | + |    *minute = bcdToDec(Wire.read());  | |
| − | + |    *hour = bcdToDec(Wire.read() & 0x3f);  | |
| − | + |    *dayOfWeek = bcdToDec(Wire.read());  | |
| − | + |    *dayOfMonth = bcdToDec(Wire.read());  | |
| − | + |    *month = bcdToDec(Wire.read());  | |
| − | + |    *year = bcdToDec(Wire.read());  | |
| − | + |  }  | |
| − | + |  void displayTime()  | |
| − | }  | + |  {  | 
| − | void displayTime()  | + |    byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;  | 
| − | {  | + |    // retrieve data from DS3231  | 
| − | + |    readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,  | |
| − | + |                   &year);  | |
| − | + |    // send it to the serial monitor  | |
| − | + |    Serial.print(hour, DEC);  | |
| − | + |    // convert the byte variable to a decimal number when displayed  | |
| − | + |    Serial.print(":");  | |
| − | + |    if (minute < 10)  | |
| − | + |    {  | |
| − | + |      Serial.print("0");  | |
| − | + |    }  | |
| − | + |    Serial.print(minute, DEC);  | |
| − | + |    Serial.print(":");  | |
| − | + |    if (second < 10)  | |
| − | + |    {  | |
| − | + |      Serial.print("0");  | |
| − | + |    }  | |
| − | + |    Serial.print(second, DEC);  | |
| − | + |    Serial.print(" ");  | |
| − | + |    Serial.print(dayOfMonth, DEC);  | |
| − | + |    Serial.print("/");  | |
| − | + |    Serial.print(month, DEC);  | |
| − | + |    Serial.print("/");  | |
| − | + |    Serial.print(year, DEC);  | |
| − | + |    Serial.print(" Day of week: ");  | |
| − | + |    switch (dayOfWeek) {  | |
| − | + |      case 1:  | |
| − | + |        Serial.println("Sunday");  | |
| − | + |        break;  | |
| − | + |      case 2:  | |
| − | + |        Serial.println("Monday");  | |
| − | + |        break;  | |
| − | + |      case 3:  | |
| − | + |        Serial.println("Tuesday");  | |
| − | + |        break;  | |
| − | + |      case 4:  | |
| − | + |        Serial.println("Wednesday");  | |
| − | + |        break;  | |
| − | + |      case 5:  | |
| − | + |        Serial.println("Thursday");  | |
| − | + |        break;  | |
| − | + |      case 6:  | |
| − | + |        Serial.println("Friday");  | |
| − | + |        break;  | |
| − | + |      case 7:  | |
| − | + |        Serial.println("Saturday");  | |
| − | + |        break;  | |
| − | + |    }  | |
| − | + |  }  | |
| − | + | ||
| − | }  | + | |
| − | + |  /*-------- NTP code ----------*/  | |
| − | + | ||
| − | + |  unsigned long getNtpTime()  | |
| − | + |  {  | |
| − | /*-------- NTP code ----------*/  | + |    sendNTPpacket(timeServer); // send an NTP packet to a time server  | 
| − | + |      delay(500);  | |
| − | unsigned long getNtpTime()  | + | |
| − | {  | + |      if ( Udp.parsePacket() ) {  | 
| − | + |       Udp.read(packetBuffer,NTP_PACKET_SIZE);  | |
| − | + |       unsigned long hi = word(packetBuffer[40], packetBuffer[41]);  | |
| − | + |       unsigned long low = word(packetBuffer[42], packetBuffer[43]);  | |
| − | + |       unsigned long secsSince1900 = hi << 16 | low;    | |
| − | + |       const unsigned long seventyYears = 2208988800UL;        | |
| − | + |       unsigned long epoch = secsSince1900 - seventyYears;  | |
| − | + |       return epoch;  | |
| − | + |    }  | |
| − | + |    return 0; // return 0 if unable to get the time  | |
| − | + |  }    | |
| − | + | ||
| − | + |  unsigned long sendNTPpacket(IPAddress& address)  | |
| − | + |  {  | |
| − | }  | + |    memset(packetBuffer, 0, NTP_PACKET_SIZE);  // set all bytes in the buffer to 0    | 
| − | + | ||
| − | unsigned long sendNTPpacket(IPAddress& address)  | + |    // Initialize values needed to form NTP request  | 
| − | {  | + |    packetBuffer[0] = B11100011;   // LI, Version, Mode  | 
| − | + |    packetBuffer[1] = 0;     // Stratum  | |
| − | + |    packetBuffer[2] = 6;     // Max Interval between messages in seconds  | |
| − | + |    packetBuffer[3] = 0xEC;  // Clock Precision  | |
| − | + |    // bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset  | |
| − | + |    packetBuffer[12]  = 49;  // four-byte reference ID identifying  | |
| − | + |    packetBuffer[13]  = 0x4E;  | |
| − | + |    packetBuffer[14]  = 49;  | |
| − | + |    packetBuffer[15]  = 52;    | |
| − | + | ||
| − | + |    // send the packet requesting a timestamp:  | |
| − | + |    Udp.beginPacket(address, 123); //NTP requests are to port 123  | |
| − | + |    Udp.write(packetBuffer,NTP_PACKET_SIZE);  | |
| − | + |    Udp.endPacket();  | |
| − | + |  }  | |
| − | |||
| − | |||
| − | |||
| − | }  | ||
Latest revision as of 07:56, 7 June 2018
Source
#include "Wire.h"
#include <Time.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#define DS3231_I2C_ADDRESS 0x68
// Ethernet library configuration
byte mac[] = { 0x24, 0x7B, 0xA2, 0x4A, 0x52, 0x10 };
IPAddress timeServer(128, 138, 140, 44 ); // time.nist.gov
unsigned int localPort = 8888;
const int NTP_PACKET_SIZE= 48;     
byte packetBuffer[NTP_PACKET_SIZE]; 
EthernetUDP Udp;
void setup()
{
  // Setup Communication
  Wire.begin();
  Serial.begin(9600);
  Serial.print("OK Serial\n");
  Ethernet.begin(mac);
  Serial.print("OK LAN\n");
  Udp.begin(localPort);
  Serial.print("OK Comm\n");
  setSyncInterval(10); // Set seconds between re-sync
  setSyncProvider(getNtpTime);
  getNtpTime;
  Serial.print("OK NTP\n");
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  // setDS3231time(30,33,9, 2 ,28,11,16);
}
void loop()
{
  setSyncProvider(getNtpTime);
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  setDS3231time(second(), minute(), hour()+7, 5 , 7, 6, 18);
  
  displayTime(); // display the real-time clock data on the Serial Monitor,
  getNtpTime;
  // delay(1000);  
}
/*----------------- DS3231 ----------------------*/
// 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) );
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
                   dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second,
                    byte *minute,
                    byte *hour,
                    byte *dayOfWeek,
                    byte *dayOfMonth,
                    byte *month,
                    byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void displayTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
                 &year);
  // send it to the serial monitor
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute < 10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second < 10)
  {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print(" Day of week: ");
  switch (dayOfWeek) {
    case 1:
      Serial.println("Sunday");
      break;
    case 2:
      Serial.println("Monday");
      break;
    case 3:
      Serial.println("Tuesday");
      break;
    case 4:
      Serial.println("Wednesday");
      break;
    case 5:
      Serial.println("Thursday");
      break;
    case 6:
      Serial.println("Friday");
      break;
    case 7:
      Serial.println("Saturday");
      break;
  }
}
/*-------- NTP code ----------*/
unsigned long getNtpTime()
{
  sendNTPpacket(timeServer); // send an NTP packet to a time server
    delay(500);
  
    if ( Udp.parsePacket() ) {
     Udp.read(packetBuffer,NTP_PACKET_SIZE);
     unsigned long hi = word(packetBuffer[40], packetBuffer[41]);
     unsigned long low = word(packetBuffer[42], packetBuffer[43]);
     unsigned long secsSince1900 = hi << 16 | low; 
     const unsigned long seventyYears = 2208988800UL;     
     unsigned long epoch = secsSince1900 - seventyYears;
     return epoch;
  }
  return 0; // return 0 if unable to get the time
} 
unsigned long sendNTPpacket(IPAddress& address)
{
  memset(packetBuffer, 0, NTP_PACKET_SIZE);  // set all bytes in the buffer to 0  
  // Initialize values needed to form NTP request
  packetBuffer[0] = B11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum
  packetBuffer[2] = 6;     // Max Interval between messages in seconds
  packetBuffer[3] = 0xEC;  // Clock Precision
  // bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset
  packetBuffer[12]  = 49;  // four-byte reference ID identifying
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52; 
  // send the packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket();
}