2013/08/17

NTP Server Synchronized DS1307 RTC Using TimeAlarms Library

This sketch calls alarm functions at 7:30 am and at 7:30 pm (19:30) and sync DS1307, Arduino system time. At startup the Arduino system time is synchronized with DS1307. The sketch output time and "Sync OK" message to Arduino serial monitor at every successful synchronization.

A DHCP server is needed.

Requirements
1. Arduino Uno R3
2. W5100 Ethernet Shield
3. RTC Sensor Shield

Schetch

/*
 * TimeAlarmNTPSyncRTC.ino
 *
 * This sketch calls alarm functions at 7:30 am and at 7:30 pm (19:30)
 * and sync DS1307, Arduino system time 
 *
 * At startup the time is sync with DS1307
 */

#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <TimeAlarms.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

// Enter a MAC address for your controller bellow.
// 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(140, 112, 2, 188); // ntp2.ntu.edu.tw 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;
// timeZoneOffset = (Time Zone) * 3600L eg. (+8) * 3600L = 28800L for Taipei, Taiwan
const long timeZoneOffset = 28800L; 
// sync to NTP server every "ntpSyncTime" seconds, set to 1 hour or more to be reasonable
unsigned long ntpSyncTime = 21600;
// keep track of how long ago we updated the NTP server
// unsigned long ntpLastUpdate = 0;
// adjust the sync latency with computer NTP client in seconds 
unsigned int syncLatency = 2;

void setup()
{
  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  // create the alarms 
  Alarm.alarmRepeat(7,30,0, ntpSyncDS1307);  // 7:30am every day
  Alarm.alarmRepeat(19,30,0, ntpSyncDS1307);  // 7:30pm every day 
  
  // start Ethernet and UDP
  if (Ethernet.begin(mac) == 0) {
    for (;;);
  }
  Udp.begin(localPort); 
ntpSyncDS1307();
}

void  loop(){  
  Alarm.delay(100); // wait 1/10 second between cycles
}

// functions to be called when an alarm triggers:
void ntpSyncDS1307() {
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  // wait to see if a replay is available
  delay(1000);
  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 timstamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, extract 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;
    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800L;
    // substract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears + timeZoneOffset + syncLatency;
    setTime(epoch);
    RTC.set(epoch);
    // ntpLastUpdate = now();
    // output time and "Sync OK" message every sync 
    Serial.print(year());
    Serial.print('-');
    Serial.print(month());
    Serial.print('-');
    Serial.print(day());
    Serial.print(' ');
    Serial.print(hour());
    Serial.print(':');
    Serial.print(minute());
    Serial.print(':');
    Serial.print(second());
    Serial.print(' ');
    Serial.println("Sync OK");
  }
}

// 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 clodk
  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);
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

No comments:

Post a Comment