Коррекция часиков на DS1307

ustas
Offline
Зарегистрирован: 12.03.2012

Есть у меня одна хорошая плата, но с хреновенько работающими RTC на DS1307 (часы "убегают" за сутки на час(!!!)).

Замена кварцевого резонатора не помогла.

Батарейка свежая, питание на саму микросхему приходит стабильное 5В. 

Возможно, проблема в том, что конструктивно кварц подключен не так, как написано в даташите на DS1307 (максимально короткие проводники, никаких кондеров в цепи - на моей плате (это готовая плата не моего производства) - около 7мм от кварца до микросхемы и от каждой ножки кварца на землю висит конденсатор (сдувать их пока не пробовал).

Ну не суть.. есть часы, они работают (плохо, но работают). На плате есть LAN - прикрутил синхронизацию времени по NTP (пример можно посмотерть тут: http://arduino.cc/en/Tutorial/UdpNtpClient). У меня код малость другой (видимо для своего скетча где-то в другом месте выдернул его, но это не важно).

Время по сети выдергивается, правильно преобразуется (вносится поправка моего часового пояса) и это время используется для корректировки времени RTC (привожу целиком функцию, которя дергается в loop():

void ntpRTCupdate() {
  if(millis() > nextNTPtime) {
    Udp.begin(localPort);
    sendNTPpacket(timeServer); // send an NTP packet to a time server

      // wait to see if a reply is available
    delay(200);  
    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:
      // calculate Unix time:
      unsigned long epoch = secsSince1900 - seventyYears;  
      // print Unix time:

      // введем корректировку для часового пояса 
      epoch = epoch + (TimeOffset * 3600L);     

      // скорректируем RTC
      RTC.adjust(DateTime(epoch));

      time2str(RTC.now(), lastNTP);

      nextNTPtime = millis()+NTPtimeSync;
    }
    Udp.stop();
  }
}

Время, когда эта корректировка произведена фиксируется (почему-то показалось, что это может пригодиться). 

Но вот уже второй раз замечаю, что не смотря на то, что синхронизация прошла "2 минуты назад" - часы бодро "убежали" на несколько минут (т.е. синхронизация не сработала).

Из-за чего такое может быть? Может, есть какая-то "правильная" процедура "подведения" часов (типа, "остановить" - "скорректировать" - "запустить")?

P.S. Сейчас смотрю, что лучше наверное фиксировать именно полученное время, а не брать после время с RTC сразу после корректировки.

Artur1985
Offline
Зарегистрирован: 19.02.2013

Здравствуйте.

У меня самого DS1307, но такого за ним не замечал.

>> Из-за чего такое может быть? Может, есть какая-то "правильная" процедура "подведения" часов (типа, "остановить" - "скорректировать" - "запустить")?

Увы, не подскажу. Попробуйте, явно задавать время, а не корректировать.
Пользовался методами установки времени из примера.

Сам пример.

#include <Wire.h>
#include "DS1307.h"

DS1307 clock;//define a object of DS1307 class
void setup()
{
	Serial.begin(9600);
	clock.begin();
	clock.fillByYMD(2013,1,19);//Jan 19,2013
	clock.fillByHMS(15,28,30);//15:28 30"
	clock.fillDayOfWeek(SAT);//Saturday
	clock.setTime();//write time to the RTC chip
}
void loop()
{
	printTime();
}
/*Function: Display time on the serial monitor*/
void printTime()
{
	clock.getTime();
	Serial.print(clock.hour, DEC);
	Serial.print(":");
	Serial.print(clock.minute, DEC);
	Serial.print(":");
	Serial.print(clock.second, DEC);
	Serial.print("	");
	Serial.print(clock.month, DEC);
	Serial.print("/");
	Serial.print(clock.dayOfMonth, DEC);
	Serial.print("/");
	Serial.print(clock.year+2000, DEC);
	Serial.print(" ");
	Serial.print(clock.dayOfMonth);
	Serial.print("*");
	switch (clock.dayOfWeek)// Friendly printout the weekday
	{
		case MON:
		  Serial.print("MON");
		  break;
		case TUE:
		  Serial.print("TUE");
		  break;
		case WED:
		  Serial.print("WED");
		  break;
		case THU:
		  Serial.print("THU");
		  break;
		case FRI:
		  Serial.print("FRI");
		  break;
		case SAT:
		  Serial.print("SAT");
		  break;
		case SUN:
		  Serial.print("SUN");
		  break;
	}
	Serial.println(" ");
}

Сам код установки времени.

clock.fillByYMD(2013,1,19);//Jan 19,2013
clock.fillByHMS(15,28,30);//15:28 30"
clock.fillDayOfWeek(SAT);//Saturday
clock.setTime();//write time to the RTC chip

 

У меня работает как часы. 
Они начинают идти именно с этого времени и не убегают вперед.

 

paf
Offline
Зарегистрирован: 25.01.2013

Я для  пользуюсь этим скетчем.

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include <Wire.h>
#include <DS1307.h>

void setup() {
  Serial.begin(9600);
  use();
  read_RTC();
}


// use explanation message
void use() {
  Serial.println("\nUSE      : u U r R h[00-23]m[00-59]s[00-59]j0[1-7]D[01-31]M[01-12]A[00-49]");
  Serial.println("\nEXEMPLE  : h09m35d03 set time to 09h35 and day of week 3 (thuesday).");
  Serial.println("\nCommands : h** : hour,  m** : minutes, s** : seconds, d0* : day of week");
  Serial.println("           M** : month,  Y** : year,   D** : day of month.");
  Serial.println("           r stops clock, R starts it. ");
  Serial.println("           u or U shows this message, all other caracter shows time.");
}

// DS1307 time read function
void read_RTC() {
	  Serial.print("\nActual time : ");
	  Serial.print(RTC.get(DS1307_HR,true)); //read the hour and also update all the values by pushing in true
	  Serial.print(":");
	  Serial.print(RTC.get(DS1307_MIN,false));//read minutes without update (false)
	  Serial.print(":");
	  Serial.print(RTC.get(DS1307_SEC,false));//read seconds
	  Serial.print(" ");                 // some space for a more happy life
	  Serial.print(RTC.get(DS1307_DOW,false));
	  Serial.print(" ");
	  Serial.print(RTC.get(DS1307_DATE,false));//read date
	  Serial.print("/");
	  Serial.print(RTC.get(DS1307_MTH,false));//read month
	  Serial.print("/");
	  Serial.println(RTC.get(DS1307_YR,false)); //read year
}

// set clock values
void write_RTC() {
      char value=0;
      char command=0;

      command = Serial.read();
      delay(50);				//delay to allow good serial port reading
      value=byte((Serial.read()-48)*10); 	//-48 becaus ASCII value for 0 is 48, 1 is 49, etc and *10 because we read tens first
      delay(50);
      value+=byte((Serial.read()-48));		//and then we read units

      switch (command) {
	case 'h' :
	  RTC.set(DS1307_HR,value);
	  Serial.print("hours set to ");
	  Serial.println(value,DEC);
	  break;
	case 'm' :
	  RTC.set(DS1307_MIN,value);
	  Serial.print("minutes set to ");
	  Serial.println(value,DEC);
	  break;
	case 's' :
	  RTC.set(DS1307_SEC,value);
	  Serial.print("seconds set to ");
	  Serial.println(value,DEC);
	  break;
	case 'D' :
	  RTC.set(DS1307_DATE,value);
	  Serial.print("day of month set to ");
	  Serial.println(value,DEC);
	  break;
	case 'd' :
	  RTC.set(DS1307_DOW,value);
	  Serial.print("day of week set to ");
	  Serial.println(value,DEC);
	  break;
	case 'M' :
	  RTC.set(DS1307_MTH,value);
	  Serial.print("month set to ");
	  Serial.println(value,DEC);
	  break;
	case 'Y' :
	  RTC.set(DS1307_YR,value);
	  Serial.print("year set to ");
	  Serial.println(value,DEC);
	  break;
	case 'u' :
	case 'U' :
	  use();
	  break;
	case 'r' :
	  RTC.stop();
	  Serial.println("Clock stopped");
	  break;
	case 'R' :
	  RTC.start();
	  Serial.println("Clock running");
	  break;
	default :
	  break;
      }
      read_RTC();
}

void loop() {
   if (Serial.available()) {
     write_RTC();
    }
}

 

RainMan
Offline
Зарегистрирован: 21.06.2011

может вам проще будет прогаммно корректировать ход часов? Вот посмотрите мою тему - http://www.kharkovforum.com/showthread.php?p=35680348#post35680348 может пригодится

dardik
Offline
Зарегистрирован: 09.03.2013

У меня была аналогичная проблема - часы убегали вперед за сутки на много. Купил новый кварц в радиомагазине, поставил вместо старого - теперь идут точно. Я думаю проблема с кварцем.

ustas
Offline
Зарегистрирован: 12.03.2012

кварц уже один раз менял - попробую еще разок махнуть (пока выкручивюсь синхронизацией часов по сети)

semeniako012
Offline
Зарегистрирован: 07.08.2017

Добрый день, топик старый, но проблема актуальна. Модуль часов спешит на 6 секунде каждый день. Я нашел статью по корректировке, но у меня никак не получается запустить скетч.... подскажите, где косяк?
 

#include <LiquidCrystal.h>
#include <Time.h>  
#include <Wire.h>  
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
float temp;
int tempAnalogPin = 1;
tmDriftInfo di;

void setup ()
{
  temp = (float(analogRead(tempAnalogPin))/1024.0)*500.0;  // initialize temp using first reading

  lcd.begin(16, 2);                         // set the lcd dimension
  lcd.clear();                              // LCD screen clear

  Serial.begin(9600);
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");

  di = RTC.read_DriftInfo();
  di.DriftDays = 1000;     // valid value 0 to 65,535
  di.DriftSeconds = 2800;  // fine tune this until your RTC sync with your reference time, valid value -32,768 to 32,767
  RTC.write_DriftInfo(di); // once you're happy with the drift setting you only have to read the DriftInfo and pass it to now2() or now3() function to get your drift corrected time

}

void loop()
{
  if(Serial.available()) {processSerialCommand();}
//  SerialDisplayDateTime(now3(di))    // use this if you don't have an LCD Display
  LcdDisplayDateTime(now3(di));
  LcdDisplayTemperature();
}

void LcdDisplayTemperature(){
  // read LM35 temperature sensor using Arduino anolog pin
  // takes the average of 300 readings
  temp = (temp*299/300)+((float(analogRead(tempAnalogPin))/1024.0)*500.0*1/300);
  lcd.setCursor(11, 1); lcd.print(temp); lcd.setCursor(15, 1); //lcd.print("C");
}

void LcdDisplayDateTime(time_t timeToDisplay){
  lcd.setCursor(0, 0);
  lcd.print(year(timeToDisplay)); lcd.print("/"); lcd.print(month(timeToDisplay)); lcd.print("/"); lcd.print(day(timeToDisplay));

  lcd.setCursor(11, 0);
  lcd.print(dayShortStr(weekday(timeToDisplay)));

  lcd.setCursor(0, 1);

  int myHour = hourFormat12(timeToDisplay);
  if (myHour < 10) { lcd.print(" "); lcd.print(myHour); } else { lcd.print(myHour); }
  lcd.print(":");

  int myMinute = minute(timeToDisplay);
  if (myMinute < 10) { lcd.print("0"); lcd.print(myMinute); } else { lcd.print(myMinute); }
  lcd.print(":");

  int mySec = second(timeToDisplay);
  if ( mySec < 10) { lcd.print("0"); lcd.print(mySec); } else { lcd.print(mySec); }

  if(isAM(timeToDisplay)) {lcd.print("AM");} else {lcd.print("PM");};
}

void SerialDisplayDateTime(time_t timeToDisplay){
  Serial.print(year(timeToDisplay)); Serial.print("/");
  Serial.print(monthShortStr(month(timeToDisplay)));Serial.print("/");
  Serial.print(day(timeToDisplay));Serial.print(" ");
  Serial.print(hourFormat12(timeToDisplay));
  printDigits(minute(timeToDisplay));
  printDigits(second(timeToDisplay));
  if(isAM(timeToDisplay)) {Serial.print("AM");} else {Serial.print("PM");}; Serial.print(" ");
  Serial.print(dayStr(weekday(timeToDisplay)));
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void processSerialCommand() {
  char c = Serial.read(); 
  switch(c){
    case 'T':
      // Command to set RTC time and update DriftInfo.DriftStart in the RTC battery back memory
      // Command format: TYYMMDDHHMMSS
      // Example: 2012 Oct 21 1:23pm is T121021132300
      delay(100); // Wait for all data to arrive
      if( Serial.available() == 12 ){  // process only if all expected data is available
        tmElements_t tme;
        time_t newTime;

        // Parse incomming 12 ASCII charaters into time_t
        // no error checking for numeric values in YYMDDHHMMSS fields, so be carefull!
        c = Serial.read(); tme.Year = c - '0';
        c = Serial.read(); tme.Year = 10*tme.Year; tme.Year += c-'0'; tme.Year += 30;
        c = Serial.read(); tme.Month = c - '0';
        c = Serial.read(); tme.Month = 10*tme.Month; tme.Month += c-'0';
        c = Serial.read(); tme.Day = c - '0';
        c = Serial.read(); tme.Day = 10*tme.Day; tme.Day += c-'0';
        c = Serial.read(); tme.Hour = c - '0';
        c = Serial.read(); tme.Hour = 10*tme.Hour; tme.Hour += c-'0';
        c = Serial.read(); tme.Minute = c - '0';
        c = Serial.read(); tme.Minute = 10*tme.Minute; tme.Minute += c-'0';
        c = Serial.read(); tme.Second = c - '0';
        c = Serial.read(); tme.Second = 10*tme.Second; tme.Second += c-'0';
        newTime = makeTime(tme);
        RTC.set(newTime);   // set the RTC and the system time to the received value
        setTime(newTime);

        tmDriftInfo diUpdate = RTC.read_DriftInfo();  // update DriftInfo in RTC
        diUpdate.DriftStart = newTime;
        RTC.write_DriftInfo(diUpdate);

        Serial.print("RTC Set to: "); SerialDisplayDateTime(newTime);
      }
      break;
    case 'I':
      // read and display DriftInfo from RTC memory
      tmDriftInfo diRead = RTC.read_DriftInfo();
      if (diRead.DriftStart == 0 | diRead.DriftDays == 0 | diRead.DriftSeconds == 0) {
        Serial.println("DriftInfo not set yet!");
        break;
      }
      Serial.println("*** DriftInfo Read from RTC Memory ***");
      Serial.print("DriftStart   : ");
      SerialDisplayDateTime(diRead.DriftStart); Serial.println();
      Serial.print("DriftDays    : ");
      Serial.println(diRead.DriftDays);
      Serial.print("DriftSeconds : ");
      Serial.println(diRead.DriftSeconds);
      Serial.print("Day(s) since drift start: ");
      Serial.println(float(now()-diRead.DriftStart)/float(SECS_PER_DAY));
      long tmp = now() - diRead.DriftStart;
      tmp *= diRead.DriftSeconds;
      Serial.print("Your RTC has Drifted(seconds): ");
      Serial.println(float(tmp)/float(SECS_PER_DAY * diRead.DriftDays));
      break;
  }
  while(Serial.available()){ Serial.read(); } // clear serial buffer
}
======Текст ошибки.===========
In file included from C:\Users\Dell\Desktop\DS1307 Drift Corrected\DriftCorrectedRTC\DriftCorrectedRTC.ino:4:0:
C:\Users\Dell\Documents\Arduino\libraries\DS1307RTC/DS1307RTC.h:19:19: error: 'tmElements_t' has not been declared
  static void read(tmElements_t &tm);
                   ^
C:\Users\Dell\Documents\Arduino\libraries\DS1307RTC/DS1307RTC.h:20:20: error: 'tmElements_t' has not been declared
  static void write(tmElements_t &tm);
                    ^
C:\Users\Dell\Documents\Arduino\libraries\DS1307RTC/DS1307RTC.h:21:9: error: 'tmDriftInfo' does not name a type
  static tmDriftInfo read_DriftInfo();         // new function not in original DS1307RC.h
        ^
C:\Users\Dell\Documents\Arduino\libraries\DS1307RTC/DS1307RTC.h:22:30: error: 'tmDriftInfo' has not been declared
  static void write_DriftInfo(tmDriftInfo di); // new function not in original DS1307RC.h
                             ^
DriftCorrectedRTC:9: error: 'tmDriftInfo' does not name a type
 tmDriftInfo di;
 ^
C:\Users\Dell\Desktop\DS1307 Drift Corrected\DriftCorrectedRTC\DriftCorrectedRTC.ino: In function 'void setup()':
DriftCorrectedRTC:19: error: 'setSyncProvider' was not declared in this scope
   setSyncProvider(RTC.get);   // the function to get the time from the RTC
                          ^
DriftCorrectedRTC:20: error: 'timeStatus' was not declared in this scope
   if(timeStatus()!= timeSet) 
                 ^
DriftCorrectedRTC:20: error: 'timeSet' was not declared in this scope
   if(timeStatus()!= timeSet) 
                     ^
DriftCorrectedRTC:25: error: 'di' was not declared in this scope

ссылка на библиотеки и скетч.

http://forum.arduino.cc/index.php?action=dlattach;topic=119054.0;attach=192244

bwn
Offline
Зарегистрирован: 25.08.2014

Косяк был в момент покупки 1307. Не тратьте время и поставьте 3231. Библиотеки совместимы.

semeniako012
Offline
Зарегистрирован: 07.08.2017

не подскажете проверенного продавца на али?

bwn
Offline
Зарегистрирован: 25.08.2014

Там где брал чипы в крайний раз, "страница недоступна". Недорогую мелочевку обычно беру где дешевле, пока без проблем.

semeniako012
Offline
Зарегистрирован: 07.08.2017

понял, спасибо!

sergey67
Offline
Зарегистрирован: 27.12.2017

ustas пишет:

кварц уже один раз менял - попробую еще разок махнуть (пока выкручивюсь синхронизацией часов по сети)

Если не секрет , то как ??? Мои убегают в перёд на 21 секунду в сутки ...

Олег Елин
Offline
Зарегистрирован: 26.08.2019

у меня тоже матерился нашел в тырнете, поставь  #include <TimeLib.h>- библы нет вот и не понимает 'tmElements_t' has not been declared ....

bwn
Offline
Зарегистрирован: 25.08.2014

Нэкрофил, аднака.)))