Solved! RTC mit UDP-NTP synchronisieren

Hallo allerseits,
wie kann ich meine RTC mit dem NTP synchronisieren um sie aktuell zu halten?
Ich benutze die DS1307new.h

Hat jemand vieleicht einen fertigen Code, den ich für mich abändern kann ?

Ein riesen DANKE für Eure HIlfe

EDIT: gelöscht, weil Quatsch, deshalb Neu!

Moin,
habs hin bekommen, ist vieleicht nicht der schönste Sketch, aber es funktioniert. :grin:

Also, der folgende Sketch synchronisiert die Uhrzeit der RTC mit der Uhrzeit vom NTP automatisch.
Den Sketch habe ich getestet mit der Library DS1307new.h und Arduino 1.0.1

Mir reicht es den Sketch immer dann auszuführen, wenn ich das gefühl habe, die RTC geht nach oderso.
Vieleicht kann es ja auch jemand gebrauchen.

/*
 ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
 ##          created Fri 13 July 2012 at 22:20 am             ##
 ##          modified Sat 14 July 2012 at 00:05 pm            ##
 ##             by Stefan Blinkmann aka Cetax                 ##
 ##                 cetax at bk-s dot de                      ##
 ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
 */
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <DS1307new.h>
#include <Wire.h>

uint16_t startAddr = 0x0000;            // Start address to store in the NV-RAM
uint16_t lastAddr;                      // new address for storing in NV-RAM
uint16_t TimeIsSet = 0xaa55;            // Helper that time must not set again

long Std;    // Variable for Hour
long Min;    // Variable for Minute
long Sec;    // Variable for Second

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xEE, 0xF3 };
byte ip[] = { 192, 168, 178, 216 };
byte gateway[] = { 192, 168, 178, 1};
byte subnet[] = {255, 255, 255, 0};

unsigned int localPort = 8888;      // local port to listen for UDP packets

//IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server
IPAddress timeServer(130,149,17,21);
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;

void setup()
{
  Serial.begin(9600);
  // start Ethernet and UDP
    Ethernet.begin(mac, ip, gateway);  
  
  Udp.begin(localPort);
  Wire.begin();
  Serial.println("rtc ...");
  Serial.println(); 
  Serial.print("RTC Now: ");
  RTC.getTime();
  Serial.print(RTC.hour, DEC);
  Serial.print(":");
  Serial.print(RTC.minute, DEC);
  Serial.print(":");
  Serial.print(RTC.second, DEC);
  Serial.println();
  
  sendNTPpacket(timeServer); // send an NTP packet to a time server

    // wait to see if a reply 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 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;  
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);               

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // 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 Unix time:
    Serial.println(epoch);                               


    // print the hour, minute and second:
    Serial.print("The German Summertime is ");       // UTC(GMT) + 2 Hour
    Serial.print((epoch  % 86400L) / 3400);          // print the hour (86400 equals secs per day)
    Std = ((epoch  % 86400L) / 3400);
    Min = ((epoch %3600) / 60);
    Sec = (epoch %60);
    Serial.print(':');  
    if ( ((epoch % 3600) / 60) < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':'); 
    if ( (epoch % 60) < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch %60); // print the second
  }
// wait ten seconds before write Time
  delay(10000);  

// Set Time to RTC
RTC.setRAM(0, (uint8_t *)&startAddr, sizeof(uint16_t));
RTC.getRAM(55, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
  if (TimeIsSet != 0xaa55)
  {
    RTC.stopClock();
// Setzt das Datum  z.b. 15.6.2012        
    RTC.fillByYMD(2012,7,13);
// Setzt die Uhrzeit
    RTC.fillByHMS(Std,Min,Sec);
    
    RTC.setTime();
    TimeIsSet = 0xaa55;
    RTC.setRAM(5, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
    RTC.startClock();
  }
  else
  {
    RTC.getTime();
  }
Serial.print("RTC Neu: ");
  RTC.getTime();
  Serial.print(RTC.hour, DEC);
  Serial.print(":");
  Serial.print(RTC.minute, DEC);
  Serial.print(":");
  Serial.print(RTC.second, DEC);
  Serial.println();
}

void loop()
{
}

// 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 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(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

So ganz verstehe ich Dein Programm nicht. Das Datum setzt Du hart kodiert im Sketch und nur die Uhrzeit wird mit der NTP Zeit gesetzt. Nachdem Du die NTP-Zeit geholt hast, wartest Du eine Sekunde, ehe Du die Zeit der RTC setzt. Damit geht doch Deine Uhr automatisch schon mal eine Sekunde nach. Außerdem machst Du es Dir ziemlich kompliziert. Du bekommst Doch per NTP schon die Zeit in Sekunden seit 1900. Theroretisch brauchst Du da nur noch "100" Jahre drauf rechnen und hast die Zeit im time2000-Format mit dem Du die RTC simple setzen kannst.
Mario.

mkl0815:
So ganz verstehe ich Dein Programm nicht. Das Datum setzt Du hart kodiert im Sketch und nur die Uhrzeit wird mit der NTP Zeit gesetzt. Nachdem Du die NTP-Zeit geholt hast, wartest Du eine Sekunde, ehe Du die Zeit der RTC setzt. Damit geht doch Deine Uhr automatisch schon mal eine Sekunde nach.

mmhh, das stimmt. Daran hatte ich nicht gedacht. :blush:

mkl0815:
Außerdem machst Du es Dir ziemlich kompliziert. Du bekommst Doch per NTP schon die Zeit in Sekunden seit 1900. Theroretisch brauchst Du da nur noch "100" Jahre drauf rechnen und hast die Zeit im time2000-Format mit dem Du die RTC simple setzen kannst.

"Theoretisch" , aber da ich ja nicht weiß wie, war das für mich einfachste und schnellste Lösung.
Aber auf jedenfall verbesserungs bedürftig. Werde mal versuchen, deine Anregungen umzusetzten.
Das heißt ich muss jetzt erstmal den UnixTimestamp ins time2000-Format bringen...
Und dann einfach die time2000-Zeit übergeben.
Ich versuche mal....

So, ich habe mal die Anregungen von mkl0815 versucht umzusetzten.
Also, es funktioniert, der Sketch holt sich die Uhrzeit vom NTP-Server und setzt die RTC dementsprechend.
ABER, ich muss ein delay einbauen, da er sonst die zeit nicht richtig holt und oder setzt.
Ich habe dies aber auf je 500ms reduzieren können.

Vieleicht kann das ja mal jemand Testen ohne delay und mir ein Feedback geben.
Würde mich freuen.

Sicherlich kann man das sauberer schreiben, aber mir ging es nur ums setzten der Zeit,
also wer möchte darf gern Hand anlegen, vieleicht geht der Sketch ja auch kürzer…

/*
 ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
 ##                 Synco the RTC with NTP                    ##
 ##          created Fri 13 July 2012 at 10:20 pm             ##
 ##          modified Sat 14 July 2012 at 9:05 pm            ##
 ##             by Stefan Blinkmann aka Cetax                 ##
 ##                 cetax at bk-s dot de                      ##
 ###############################################################
 */
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <DS1307new.h>
#include <Wire.h>

uint16_t startAddr = 0x0000;            // Start address to store in the NV-RAM
uint16_t lastAddr;                      // new address for storing in NV-RAM
uint16_t TimeIsSet = 0xaa55;            // Helper that time must not set again

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xEE, 0xF3 };
byte ip[] = { 192, 168, 178, 216 };
byte gateway[] = { 192, 168, 178, 1};
byte subnet[] = {255, 255, 255, 0};

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(192, 43, 244, 18); // time.nist.gov 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 

EthernetUDP Udp; // A UDP instance to let us send and receive packets over UDP

unsigned long highWord;
unsigned long lowWord;
unsigned long secsSince1900;
unsigned long epoch;
unsigned long seventyYears;
unsigned long time_2000 = 946684800;
unsigned long timeNow;
unsigned long mesz;

void setup()
{
  Serial.begin(9600);
  // start Ethernet and UDP
    Ethernet.begin(mac, ip, gateway);  
  
  Udp.begin(localPort);
  Wire.begin();
  Serial.println("rtc ...");
  Serial.println(); 
  Serial.print("RTC Now: ");
  RTC.getTime();
  Serial.print(RTC.hour, DEC);
  Serial.print(":");
  Serial.print(RTC.minute, DEC);
  Serial.print(":");
  Serial.print(RTC.second, DEC);
  Serial.println();
  
  sendNTPpacket(timeServer); // send an NTP packet to a time server

  // wait to see if a reply is available
  delay(500);  
  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:

    highWord = word(packetBuffer[40], packetBuffer[41]);
    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):
    secsSince1900 = highWord << 16 | lowWord;  
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);               

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    seventyYears = 2208988800UL;     
    // subtract seventy years:
    epoch = secsSince1900 - seventyYears;  
    // print Unix time:
    Serial.println(epoch);   
    
    // print the hour, minute and second:
    Serial.print("The German Summertime is ");       // UTC(GMT) + 2 Hour
    Serial.print((epoch  % 86400L) / 3200);          // print the hour (86400 equals secs per day)
    Serial.print(':');  
    if ( ((epoch % 3600) / 60) < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':'); 
    if ( (epoch % 60) < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch %60); // print the second
  }
  else {
    Serial.println(" Keine Verbindung");
  }
// wait 1/2 seconds before write Time
  delay(500);  

// Unixtime(epoch) - Sek seit 2000(time_2000)
    //timeNow = epoch - time_2000;    
    mesz = epoch - time_2000;
    timeNow = mesz + 7200;
// Set Time to RTC
RTC.setRAM(0, (uint8_t *)&startAddr, sizeof(uint16_t));
RTC.getRAM(55, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
  if (TimeIsSet != 0xaa55)
  {
    RTC.stopClock();
// Setzt die Zeit und Datum als time2000
    RTC.fillByTime2000(timeNow);    
    RTC.setTime();
    TimeIsSet = 0xaa55;
    RTC.setRAM(5, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
    RTC.startClock();
  }
  else
  {
    RTC.getTime();
  }
  if (TimeIsSet == 0xaa55)              // check if the clock was set or not
  {
    Serial.println(" - Clock was set!");
  }
  else
  {
    Serial.println(" - Clock was NOT set!");
  }    
  
}

void loop()
{
  delay(10000); 
Serial.print("RTC Neu: ");
  RTC.getTime();
  Serial.print(RTC.hour, DEC);
  Serial.print(":");
  Serial.print(RTC.minute, DEC);
  Serial.print(":");
  Serial.print(RTC.second, DEC);
  Serial.println();
}

// 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 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(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

könntest du die wartezeit vielleicht minimieren (und vor allem dann delayfrei lösen) indem du anstatt

if ( Udp.parsePacket() )

while (!Udp.parsePacket()) ;

schreibst, und anschließen das weitere erledigst?

Hallo derder,
Danke für deinen Tip !
Hat funktioniert, habe es gerade 10x erfolgreich getestet. :grin:

derder:
könntest du die wartezeit vielleicht minimieren (und vor allem dann delayfrei lösen) indem du anstatt

if ( Udp.parsePacket() )

while (!Udp.parsePacket()) ;

schreibst, und anschließen das weitere erledigst?

Hier der geänderte Sketch ohne “delay”:
( Nicht hübsch, aber er funktioniert :wink: )

/*
 ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##
 ##                 Synco the RTC with NTP                    ##
 ##          created Fri 13 July 2012 at 10:20 pm             ##
 ##          modified Mon 16 July 2012 at 02:05 pm            ##
 ##             by Stefan Blinkmann aka Cetax                 ##
 ##                 cetax at bk-s dot de                      ##
 ###############################################################
 */
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <DS1307new.h>
#include <Wire.h>

uint16_t startAddr = 0x0000;            // Start address to store in the NV-RAM
uint16_t lastAddr;                      // new address for storing in NV-RAM
uint16_t TimeIsSet = 0xaa55;            // Helper that time must not set again

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xEE, 0xF3 };
byte ip[] = { 192, 168, 178, 216 };
byte gateway[] = { 192, 168, 178, 1};
byte subnet[] = {255, 255, 255, 0};

unsigned int localPort = 8888;      // local port to listen for UDP packets

IPAddress timeServer(192, 43, 244, 18); // time.nist.gov 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 

EthernetUDP Udp; // A UDP instance to let us send and receive packets over UDP

unsigned long highWord;
unsigned long lowWord;
unsigned long secsSince1900;
unsigned long epoch;
unsigned long seventyYears;
unsigned long time_2000 = 946684800;
unsigned long timeNow;
unsigned long mesz;

void setup()
{
  Serial.begin(9600);
  // start Ethernet and UDP
    Ethernet.begin(mac, ip, gateway);  
  
  Udp.begin(localPort);
  Wire.begin();
  Serial.println("rtc ...");
  Serial.println(); 
  Serial.print("RTC Now: ");
  RTC.getTime();
  Serial.print(RTC.hour, DEC);
  Serial.print(":");
  Serial.print(RTC.minute, DEC);
  Serial.print(":");
  Serial.print(RTC.second, DEC);
  Serial.println();
  
  sendNTPpacket(timeServer); // send an NTP packet to a time server

  while (!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:

    highWord = word(packetBuffer[40], packetBuffer[41]);
    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):
    secsSince1900 = highWord << 16 | lowWord;  
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);               

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    seventyYears = 2208988800UL;     
    // subtract seventy years:
    epoch = secsSince1900 - seventyYears;  
    // print Unix time:
    Serial.println(epoch);   
    
    // print the hour, minute and second:
    Serial.print("The NTP Time is ");       // UTC(GMT) + 2 Hour
    Serial.print((epoch  % 86400L) / 3000);          // print the hour (86400 equals secs per day)
    Serial.print(':');  
    if ( ((epoch % 3600) / 60) < 10 ) {
      // In the first 10 minutes of each hour, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute)
    Serial.print(':'); 
    if ( (epoch % 60) < 10 ) {
      // In the first 10 seconds of each minute, we'll want a leading '0'
      Serial.print('0');
    }
    Serial.println(epoch %60); // print the second

// Unixtime(epoch) - Sek seit 2000(time_2000) 
    mesz = epoch - time_2000;
    timeNow = mesz + 7200;
// Set Time to RTC
RTC.setRAM(0, (uint8_t *)&startAddr, sizeof(uint16_t));
RTC.getRAM(55, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
  if (TimeIsSet != 0xaa55)
  {
    RTC.stopClock();
// Setzt die Zeit und Datum als time2000
    RTC.fillByTime2000(timeNow);    
    RTC.setTime();
    TimeIsSet = 0xaa55;
    RTC.setRAM(5, (uint8_t *)&TimeIsSet, sizeof(uint16_t));
    RTC.startClock();
  }
  else
  {
    RTC.getTime();
  }
  if (TimeIsSet == 0xaa55)              // check if the clock was set or not
  {
    Serial.println(" - Clock was set!");
  }
  else
  {
    Serial.println(" - Clock was NOT set!");
  }    
  
}

void loop()
{
  delay(10000); 
Serial.print("RTC New: ");
  RTC.getTime();
  Serial.print(RTC.hour, DEC);
  Serial.print(":");
  Serial.print(RTC.minute, DEC);
  Serial.print(":");
  Serial.print(RTC.second, DEC);
  Serial.println();
}

// 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 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(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer,NTP_PACKET_SIZE);
  Udp.endPacket(); 
}

Schön, das es geklappt hat. Als kleine Fingerübung wäre es klasse, das in eine oder zwei Funktionen zu packen, die man dann einfach in andere Projekte übernehmen kann.
Mario.

Wie meinst d :roll_eyes:u das ?