Go Down

Topic: I2C RTC DS1307 verliert wieder die Zeit/Datum (Read 7180 times) previous topic - next topic

GoMega

Aug 27, 2013, 08:33 am Last Edit: Aug 27, 2013, 08:49 am by GoMega Reason: 1
Hallo zusammen,

ich bin dabei einen Arduino Mega mit etlichen DS18B20, DHT22, LCD- und Ethernet-Modul zu betreiben. Soweit funktioniert das ganze auch erstmal. Am besagten Mega hängt auch ein I2C RTC DS1307 Modul:

http://www.ebay.de/itm/I2C-RTC-DS1307-Real-Time-Clock-Realtime-Module-mit-LIR2032-Batterie-For-Tiny-RTC-/281012595404?pt=Bauteile&hash=item416da7eacc

Habe nun schon etliche Versuche durch, aber jedesmal wenn ich die Stromversorgung (USB zum PC) trenne und wieder anschließe, steht das Datum und die Uhrzeit wieder auf einem völlig anderen Wert. Ich kann die Uhrzeit mit diversen Beispielprogrammen aus dem WWW einstellen, auch mit dem "Time" aus der Arduino Bibliothek mit dem UNIX Txxxxxxx Zeitstempel. Es wird mir dann auch über Serial Out das richtige Datum/Zeit ausgegeben. Dann kann ich wieder mein Programm flashen und die Zeitdaten stimmen immer noch. Die Batterie habe ich schon geprüft.

Hat jemand einen Tip?!

Vielen Dank
GoMega

sschultewolter

Uploade mal das Beispiel ReadTime aus der DS1307 Libary. Danach resete den Arduino und gehe über die Arduino IDE auf den Serial Monitor. Was zeigt er dann an? Wenn dort dann alles richtig angezeigt wird, lade mal dein Sketch hoch, da muss ein Bock drin sitzen dann.
Keinen technischen Support über PN!

jurs


Hat jemand einen Tip?!


Mein Tipp:
Es liegt entweder an der Verkabelung/Anschluss des Moduls oder am verwendeten Software-Sketch!

Da Du beides nicht zeigst, na ja, kann man eben kaum mehr dazu sagen.

michael_x

Quote
Dann kann ich wieder mein Programm flashen und die Zeitdaten stimmen immer noch.


Dann ist evtl. die Batterie nicht richtig angeschlossen   ( : + / - : ) ...   oder sonst was  kaputt ?

GoMega

#4
Aug 27, 2013, 06:11 pm Last Edit: Aug 27, 2013, 06:16 pm by GoMega Reason: 1
Danke erst mal die Beiträge zu meiner Frage. Ich will mal versuchen zu antworten.

Als Bibliothek verwende ich diese: http://playground.arduino.cc/Code/Time.
Und daraus z.B. das "TimeRTCSet.pde" Beispiel:

Code: [Select]
/*
* TimeRTCSet.pde
* example code illustrating Time library with Real Time Clock.
*
* RTC clock is set in response to serial port time message
* A Processing example sketch to set the time is inclided in the download
*/

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


void setup()  {
 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");      
}

void loop()
{
 if(Serial.available())
 {
    time_t t = processSyncMessage();
    if(t >0)
    {
       RTC.set(t);   // set the RTC and the system time to the received value
       setTime(t);          
    }
 }
  digitalClockDisplay();  
  delay(1000);
}

void digitalClockDisplay(){
 // digital clock display of the time
 Serial.print(hour());
 printDigits(minute());
 printDigits(second());
 Serial.print(" ");
 Serial.print(day());
 Serial.print(" ");
 Serial.print(month());
 Serial.print(" ");
 Serial.print(year());
 Serial.println();
}

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

/*  code to process time sync messages from the serial port   */
#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message

time_t processSyncMessage() {
 // return the time if a valid sync message is received on the serial port.
 while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
   char c = Serial.read() ;
   Serial.print(c);  
   if( c == TIME_HEADER ) {      
     time_t pctime = 0;
     for(int i=0; i < TIME_MSG_LEN -1; i++){  
       c = Serial.read();          
       if( c >= '0' && c <= '9'){  
         pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
       }
     }  
     return pctime;
   }  
 }
 return 0;
}


Von http://www.epochconverter.com/ habe ich mir die Unixzeit geholt und gebe diese über den Seriellen Monitor der Arduino IDE 1.0.5 Umgebung als z.B. T1377626902 ein. Dann wird die gewünschte Zeit angezeigt. Dann schreibe ich meinen eigenen Sketch auf den Mega, die Zeit/Datum ist nach dem der Arduino neu bootet immer noch richtig. Bei trennen der USB Verbindung und erneut verbinden wird dann aber eine ganz andere Zeit angezeigt. Jahr z.B. 2046 o.ä.

Viele Grüße
Mega

michael_x

#5
Aug 27, 2013, 06:29 pm Last Edit: Aug 27, 2013, 06:36 pm by michael_x Reason: 1
Schonmal die Spannung am BAT - Pin des DS1307 gemessen ?
Wenn der Arduino spannungslos ist ?

Nachtrag:
Direkt am 1307 - Chip ?

Sollte immer ca. 3V gegen GND haben...

Serenifly

Das mit dem Converter kann man sich auch sparen. Wenn du Time verwendest kannst du mit makeTime() die time_t Variable einfach aus Datum und Uhrzeit erzeugen.

Code: [Select]

TimeElements tm;
tm.Day = 27;
tm.Month = 8;
tm.Year = CalendarYrToTm(2013);
tm.Wday = 2;
tm.Hour = 18;
tm.Minute = 37;
tm.Second = 0;
time_t time = makeTime(tm);
RTC.set(time);
setTime(time);

GoMega

#7
Aug 27, 2013, 07:19 pm Last Edit: Aug 27, 2013, 07:22 pm by GoMega Reason: 1
Wenn ich den Sketch richtig verstanden habe, findet zum Anfang eine

Code: [Select]
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");    


Synchronisation mit der Systemzeit statt. Diese ist auch immer erfolgreich. Scheint aber nicht gepuffert zu werden. Die Batterie selbst ist i.O. 4,4 Volt Leerlaufspannung. Habe das Modul auf der einen Seite mit einer Stiftleiste betückt und +/- mit dem Meghaboard verbunden und SDA/SCL mit den Ports 20/21. Sollte ja soweit ok sein. Weiter muss ich doch nichts verdrahten?! Die Batterie ist doch Default auf dem Modul mit dem Chip verbunden. Das Messen der 3 Volt traue ich mir nicht wirklich zu, die Augen  :smiley-eek:

Das komische ist, das nach dem Stromlos machen immer die gleiche Uhrzeit da steht, auf die Sek. genau, so als ob due Uhrzeit nicht weiter gezählt wird. Hatte glaube irgendwo was gelesen das man das RTC Modul auch "stoppen" kann?!

In dem Moment wenn ich den SerialMonitor wieder aufrufe wird wieder die Systemzeit erfolgreich initialisiert und alles fängt von vorn an.
Gruß
Mega

Serenifly

Die Uhr wird angehalten wenn du Bit 7 im Sekunden-Register 00h setzt.

Siehe Seite 8:
http://datasheets.maximintegrated.com/en/ds/DS1307.pdf

michael_x

Die Uhr steht auch, nachdem die Backup-Batterie sie nicht versorgt hat, während die externe Spannung weg war.

Quote
Das Messen der 3 Volt traue ich mir nicht wirklich zu

Und wenn du testweise mal an BAT - Pin / GND auf dem Modul misst, oder statt der Batterie an diesen Pin 3V anlegst und dann eine Unterbrechung der Versorgungsspannung machst ?

Ein fehlerhafter Kontakt der Batterie ist wahrscheinlicher als subtilere Fehler mit dem Breakout-Modul oder dem Chip selbst ...
Hast du die Schutzfolie gegen Selbstentladung der Batterie entfernt ?   --- brauchst du nicht verraten, wenn's sowas war ;)


... die Augen  :smiley-eek:

Ich muss zum Glück nur meine  -4 Dioptrien - Brille absetzen und bin dann herrlich kurzsichtig.  8)

GoMega

Hallo,

Quote
Und wenn du testweise mal an BAT - Pin / GND auf dem Modul misst, oder statt der Batterie an diesen Pin 3V anlegst und dann eine Unterbrechung der Versorgungsspannung machst ?



Ich werde versuchen heute Abend mal die Spannung zu messen. Mit Bat-Pin meinst an der Seite bei der unbestückten Stiftleiste?! Eine Schutzfolie auf er Batterie war nicht drauf. Da ich aber mit dem Multimeter eine Anzeige von 4,4 V hatte, sollte da auch wirklich nichts gewesen sein. Und auf der Platine selbst sind nur die Kontakte.

Andere Frage, es ist doch egal, welche Seite ich mit dem Arduino verbinde?!

Was ich auch nicht ganz verstehe:

Code: [Select]
if(timeStatus()!= timeSet)

bringt mir immer ein Ok. Auch wenn hinterher im LCD-Display beispielsweise der 24.6.2038 steht. Die Systemzeit wird doch immer nur abgeglichen, wenn der Arduino am USB Port des Rechners hängt  :smiley-roll:?!

Gruß
Mega

michael_x


Mit Bat-Pin meinst an der Seite bei der unbestückten Stiftleiste?!
Ja


Was ich auch nicht ganz verstehe:

Code: [Select]
if(timeStatus()!= timeSet)

bringt mir immer ein Ok. Auch wenn hinterher im LCD-Display beispielsweise der 24.6.2038 steht. Die Systemzeit wird doch immer nur abgeglichen, wenn der Arduino am USB Port des Rechners hängt


Die Time library hat erstmal mit der RTC nichts zu tun,  wird nur über
Code: [Select]
setSyncProvider(RTC.get);    damit verknüpft. ( lesend, d.h. Time zeigt dir die von der RTC gelesenen Werte an  )

In
Code: [Select]
     time_t t = processSyncMessage();
     if(t >0)
     {
        RTC.set(t);   // set the RTC and the system time to the received value
        setTime(t);         
     }

setzt du die RTC ...

jurs

#12
Aug 28, 2013, 01:39 pm Last Edit: Aug 28, 2013, 01:47 pm by jurs Reason: 1

Andere Frage, es ist doch egal, welche Seite ich mit dem Arduino verbinde?!


Ja, die relevanten Pins VCC, GND, SDA und SCL sind an beiden Seiten der RTC-Platine vorhanden und Du kannst entweder die Pins der einen oder der anderen Seite verwenden.

Was Du allerdings nicht machen solltest: Einen Sketch zum Testen verwenden, den Du nicht verstehst und der diverse Libraries verwendet, die Du ebenfalls nicht verstehst.

Am besten verwendest Du zum Testen einer RTC-Uhr auch nur einen Sketch zum Testen einer RTC-Uhr. Solche Sketches werden zu RTC-Libraries immer als "Beispiel" mitgeliefert. Also mal im Software-Menü unter "Datei-Beispiele-[Name der Library]" nachschauen, wenn Du eine spezielle RTC-Library installiert hast.

Vollkommen ohne externe Libraries kannst Du mit diesem Sketch testen, der baut rein auf die in jeder Arduino-Software mitgelieferte Wire-Library auf. Der Sketch liest einerseits alle 10 Sekunden die aktuelle Uhrzeit aus der RTC aus und zeigt diese an. Andererseits kann Datum und Zeit über den seriellen Monitor gestellt werden.

Code: [Select]

#include <Wire.h>
// I2C Adresse der RTC ist 0x68 für DS1307 und DS3231
#define RTC_I2C_ADDRESS 0x68

int jahre,monate,tage,stunden,minuten,sekunden;
// wochentag bleibt in diesem Test-Sketch unberücksichtigt

void rtcReadTime(int &jahre, int &monate, int &tage, int &stunden, int &minuten, int &sekunden)
// aktuelle Zeit aus RTC auslesen
{
// Reset the register pointer
  Wire.beginTransmission(RTC_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(RTC_I2C_ADDRESS, 7);
  // A few of these need masks because certain bits are control bits
  sekunden    = bcdToDec(Wire.read() & 0x7f);
  minuten     = bcdToDec(Wire.read());
  stunden     = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
  /*wochentag   = */bcdToDec(Wire.read());
  tage        = bcdToDec(Wire.read());
  monate      = bcdToDec(Wire.read());
  jahre       = bcdToDec(Wire.read())+2000; 
}

void rtcWriteTime(int jahre, int monate, int tage, int stunden, int minuten, int sekunden)
// aktuelle Zeit in der RTC speichern
{
  Wire.beginTransmission(RTC_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(sekunden));    // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minuten));
  Wire.write(decToBcd(stunden));      // If you want 12 hour am/pm you need to set
                                   // bit 6 (also need to change readDateDs1307)
                                 
  Wire.write(decToBcd(0)); // Wochentag unberücksichtigt
  Wire.write(decToBcd(tage));
  Wire.write(decToBcd(monate));
  Wire.write(decToBcd(jahre-2000));
  Wire.endTransmission(); 
}

byte decToBcd(byte val) // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert decimal number to binary coded decimal
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)  // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert binary coded decimal to decimal number
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val/16*10) + (val%16) );
}


int getIntFromString (char *stringWithInt, byte num)
// input: pointer to a char array
// returns an integer number from the string (positive numbers only!)
// num=1, returns 1st number from the string
// num=2, returns 2nd number from the string, and so on
{
  char *tail;
  while (num>0)
  {
    num--;
    // skip non-digits
    while ((!isdigit (*stringWithInt))&&(*stringWithInt!=0)) stringWithInt++;
    tail=stringWithInt;
    // find digits
    while ((isdigit(*tail))&&(*tail!=0)) tail++;
    if (num>0) stringWithInt=tail; // new search string is the string after that number
  } 
  return(strtol(stringWithInt, &tail, 0));



void setup()
{
  Wire.begin();       // initialisiert die Wire-Library
  Serial.begin(9600); // Serielle Kommunikation starten
  while (!Serial);    // wait for serial port to connect. Needed for Leonardo only
  Serial.println("\r\nRTC Demo Sketch by jurs for German Arduino Forum");
  Serial.println("Dieser Sketch zeigt die aktuelle Zeit alle 10 Sekunden im 'Serial Monitor'.");
  Serial.println("Du kannst die Zeit mit einem 'set' Befehl im 'Serial Monitor' neu setzen.");
  Serial.println("\r\nBeispiel:");
  Serial.println("set 28.08.2013 10:54\r\n");
}


void machsAlle10Sekunden(){
  static unsigned long prevMillis=-20000;
  char linebuf[30];
  if (millis()-prevMillis<10000) return; // Zeit noch nicht erreicht, Funktion abbrechen
  prevMillis=millis();
  // RTC Uhr auslesen
  rtcReadTime(jahre,monate,tage,stunden,minuten,sekunden);
  // Zeit für Ausgabe formatieren
  snprintf(linebuf,sizeof(linebuf),"%02d.%02d.%04d %02d:%02d:%02d Uhr",tage,monate,jahre,stunden,minuten,sekunden);
  // Zeit auf serieller Schnittstelle ausgeben
  Serial.println(linebuf);
}

void behandleSerielleBefehle()
{
  char linebuf[30];
  byte counter;
  if (Serial.available())
  {
    delay(100); // Warte auf das Eintreffen aller Zeichen vom seriellen Monitor
    memset(linebuf,0,sizeof(linebuf)); // Zeilenpuffer löschen
    counter=0; // Zähler auf Null
    while (Serial.available())
    {
      linebuf[counter]=Serial.read(); // Zeichen in den Zeilenpuffer einfügen
      if (counter<sizeof(linebuf)-1) counter++; // Zeichenzähler erhöhen
    }
    // Ab hier ist die Zeile eingelesen
    if (strstr(linebuf,"set")==linebuf) // Prüfe auf Befehl "set" zum Setzen der Zeit
    { // Alle übermittelten Zahlen im String auslesen
      tage=getIntFromString (linebuf,1);
      monate=getIntFromString (linebuf,2);
      jahre=getIntFromString (linebuf,3);
      stunden=getIntFromString (linebuf,4);
      minuten=getIntFromString (linebuf,5);
      sekunden=getIntFromString (linebuf,6);
    }
    else
    {
      Serial.println("Befehl unbekannt.");
      return;
    }
    // Ausgelesene Werte einer groben Plausibilitätsprüfung unterziehen:
    if (jahre<2000 || monate<1 || monate>12 || tage<1 || tage>31 || (stunden+minuten)==0)
    {
      Serial.println(linebuf);
      Serial.println("\r\nFehlerhafte Zeitangabe im 'set' Befehl");
      Serial.println("\r\nBeispiel:");
      Serial.println("set 28.08.2013 10:54\r\n");
      return;
    }
    rtcWriteTime(jahre, monate, tage, stunden, minuten, sekunden);
    Serial.println("Zeit und Datum wurden auf neue Werte gesetzt.");
  }
}


void loop()
{
  machsAlle10Sekunden();
  behandleSerielleBefehle();
}


Funktioniert Deine Uhr mit diesem Sketch?
Oder auch das nicht?

GoMega

Geht, geht nicht, geht ...

Quote
Quote from: GoMega on Today at 08:45:14 am

Mit Bat-Pin meinst an der Seite bei der unbestückten Stiftleiste?!
Ja

Gemessen habe ich, sind 3,1 Vl. Sollte also ok sein.

Quote
Was Du allerdings nicht machen solltest: Einen Sketch zum Testen verwenden, den Du nicht verstehst und der diverse Libraries verwendet, die Du ebenfalls nicht verstehst.


Ich habe nicht den Anspruch alles verstehen zu wollen, erst recht nicht sämtliche Libraries. Ich möchte sie in erster Linie nur anwenden/verwenden. Und von daher weiß ich auch nicht, was an der Time-Lib. von arduino.cc falsch sein soll. Dein Sketch, den ich in ähnlicher Form schon im Internet gefunden habe, funktioniert, funktioniert nicht, ...

D.h. direkt nach dem flashen und dem starten des SerialMonitor wird das richtige Datum und die Uhrzeit angezeigt. Unterbreche ich allerdings die Stromversorgung und starte dann wieder den SerialMonitor , kommt das in der Ausgabe:

Code: [Select]
RTC Demo Sketch by jurs for German Arduino Forum
Dieser Sketch zeigt die aktuelle Zeit alle 10 Sekunden im 'Serial Monitor'.
Du kannst die Zeit mit einem 'set' Befehl im 'Serial Monitor' neu setzen.

Beispiel:
set 28.08.2013 10:54

165.165.2165 45:165:85 Uhr
165.165.2165 45:165:85 Uhr
165.165.2165 45:165:85 Uhr
165.165.2165 45:165:85 Uhr
28.08.2013 19:57:03 Uhr
28.08.2013 19:57:13 Uhr
28.08.2013 19:57:23 Uhr
28.08.2013 19:57:33 Uhr
28.08.2013 19:57:43 Uhr
28.08.2013 19:57:53 Uhr
28.08.2013 19:58:03 Uhr
28.08.2013 19:58:13 Uhr


set funktioniert auch nicht:

Code: [Select]
set 28.08.2013 21:00

Fehlerhafte Zeitangabe im 'set' Befehl

Beispiel:
set 28.08.2013 10:54

28.08.2013 20:06:53 Uhr
28.08.2013 20:07:03 Uhr


Da hatte ich mit dem "TimeRTCSet.pde" aus der Time-Biblio mehr Erfolg.

Lässt sich auch beliebig wiederholen. Mal dauert es länger, mal nicht so lange bis die Zeit/Datumausgabe wieder stimmt.

Ich glaube ich kaufe mir ein neues RTC Modul und probiere es damit. Vielleicht hat es ja doch ein Hardwarefehler.

Vielen Dank
Mega

jurs


Code: [Select]

165.165.2165 45:165:85 Uhr
165.165.2165 45:165:85 Uhr
165.165.2165 45:165:85 Uhr
165.165.2165 45:165:85 Uhr
28.08.2013 19:57:03 Uhr
28.08.2013 19:57:13 Uhr
28.08.2013 19:57:23 Uhr



Heißt das, die Uhr "startet in den ersten 30 Sekunden mit falschen Werten" und gibt danach korrekte Werte aus, wenn mein Sketch ca. eine halbe Minute lang gelaufen ist? Mit oder ohne zwischenzeitliche Stromunterbrechung?


set funktioniert auch nicht:


Sorry, mein Fehler. Das Setzen der Zeit mit set funktioniert schon, aber das von mir eingefügte Beispiel ist falsch. Es dürfen keine führenden Nullen in den einzelnen Werten enthalten sein.

Streiche im Sketch:
Code: [Select]

      Serial.println("set 28.08.2013 10:54\r\n");


Setze stattdessen im Sketch:
Code: [Select]

      Serial.println("set 28.8.2013 10:54");
      Serial.println("(Werte jeweils OHNE FUEHRENDE NULLEN eingeben!\r\n");


Wobei die Trennzeichen optional bzw. beliebig sind, Du kannst auch andere Trennzeichen oder Leerzeichen verwenden:
set 28 8 2013 10 54
set 28, 8, 2013, 10, 54
Funktioniert alles.
Nur nicht mit führenden Nullen in den Werten.
Wenn Du auch die Sekunden setzen möchtest, brauchst Du am Ende nur einen Wert dranhängen:
set 28.8.2013 10:54:20
(Setzt dann auch die Sekunden)

Go Up