Forum: Projekte & Code Real Time Clock mit RTC4513 EPSON


von Manni (Gast)


Angehängte Dateien:

Lesenswert?

An alle Clock Fans,

häufig wird eine Real Time Clock in einem uC System benötigt. Clocks 
sind schon in endlicher Zahl hier im Forum vorgestellt worden, aber 
dieses C Programm basiert auf dem EPSON Chip RTC4513 (2,10 € bei 
Reichelt), der durch nur 3 Anschlüsse zum Laufen gebracht werden kann.

Der Vorteil dieser Implementierung ist, dass man gänzlich auf die 
internen Timer verzichten kann, wenn diese schon andere Aufgaben 
übernehmen müssen. Nachteil: kostet ca. 2K Programmspeicher.

Einmal gesetzt, kann jederzeit Sekunde, Minute, Stunde und Tag, Monat 
und Jahr abgerufen werden; ebenso der Wochentag.

Die beigelegte C Software wurde für den ATmega32 mit 8MHz Clock 
entwickelt und besteht aus Main.c und RealTimeClock.c sowie die 
dazugehörigen .h files und wurde entwickelt unter AVR Studio 4.13, Build 
528.

Die "public" Funktionen erlauben das Setzen und das Auslesen der Uhr, so 
wie in Main.c dargestellt.

Viel Spaß beim ausprobieren !!
Gruß
Manni

von Manni (Gast)


Lesenswert?

Keine S/W ohne Bugs !!

Diesmal aber von der harmlosen Sorte. In der Funktion RTC_GetDayOfWeek 
muss hinter "while (i&0x08);" noch die Anweisung:

  i = i&0x08;

eingefügt werden. Weitere Bugs nehme ich gerne entgegen.

Gruß
Manni

von T.S. (Gast)


Lesenswert?

Jede SW hat Bugs. Das ist normal, sonst wäre sie keine. ;)

Der '4513 sieht sehr interessant aus, vor allem wegen seiner wenigen 
Pins die am µC benötigt werden. Den habe ich bis jetzt nicht 
wahrgenommen - danke für die Info.

Dein Code ist in sich schlüssig und nachvollziehbar. Obwohl ich den Chip 
nicht habe zum ausprobieren kann ich an Deiner 'Handschrift' erkennen 
dass es nicht Dein erstes Werk war. Respekt!

Du hast jetzt aber Schuld wenn ich meinem Liebling '58321 in Zukunft 
untreu werde... Aber: Wie sind Deine Erfahrungen über einen längeren 
Zeitraum?

Der '58321 macht bei mir -1s in 3 Wochen, gepuffert mit 0,1F Goldcap. 
Ein Wert mit dem ich sehr zufrieden bin - auch bei hoher Pin-Zahl.

Was mir besonders gut an den RTC's gefällt: Zeit einstellen und dann 
vergessen. Ein unschätzbarer Vorteil gegenüber anderen Lösungen.

Torsten

von Manni (Gast)


Angehängte Dateien:

Lesenswert?

Die Genauigkeit sollte so ca. bei 1s pro Tag liegen (zuzüglich dV und dT 
Variationen) laut Datenblatt auf Seite 16 --> also nix in deiner 
gewohnten Größenordnung.

Für meine Application reicht das aber vollkommen aus, da ich jede Stunde 
mit DCF synchronisiere.

Anbei eine überarbeitete Version mit einfacherem Code zum Setzen und 
Lesen der Clock. Spart Platz im Flash, jetzt nur noch 1.8 KByte.

Gruß
Manni

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

@Manni,

also ich hab nachm Compilieren (AVR-GCC 4.1.1, -Os) nur 1068 Bytes raus, 
wie kommst Du auf 1,8kB ?


Ich hab auch noch ein paar kleine Änderungen gemacht:

1.
Das mit den extra Bit-Funktionen finde ich ziemlich unübersichtlich, 
daher habe ich Bitvariablen verwendet.

Ich finde x = 0; bzw. x = 1; ist schneller lesbar.

Auf die Codegröße hat das keinen Einfluß.


2.
Schieben um ne Variable unterstützt der AVR nicht, muß also per 
Softwareroutine simuliert werden.

Sieht auf dem Oszi recht lustig aus, wie dann die höherwertigen Bits 
immer länger dauern.

Da aber eh nur aufeinanderfolgende Bits ausgegeben werden, ist das 
Schieben der Variable anstelle der Maske effektiver.


3.
Indexzugriff unterstützt der AVR nicht, muß also per Softwareroutine 
simuliert werden.

Daher ist die Pointerschreibweise (*x++) effektiver.


4.
Zählschleifen setze ich gerne auf den Startwert und lasse sie runter 
zählen.
Dann sieht man gleich im ersten Ausdruck die Anzahl der Durchläufe.
Oftmals ist auch Runterzählen effektiver (kein extra Null-Test nötig).


Komme nun auf 960 Byte.


Anbei die Änderungen.


Peter

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

P.S.:

Und hier noch der Bitdefinitions-Header.


Peter

von Manni (Gast)


Lesenswert?

@Peter

Wie Torsten oben schon sagte, hat jeder so seine Handschrift. Aber deine 
ist auch nicht von schlechten Eltern --> Man lernt doch immer noch was 
dazu !!

Deine Änderungen konnte ich alle nachvollziehen und machen auch Sinn, 
nur die Anweisung:

#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)

muss ich erst noch verdauen, ist anscheinend etwas schwerere Kost. 
Vielleicht hilft ne Nacht drüber schlafen.

Ich habe dann natürlich deinen geänderten Code sofort am "lebenden" 
Objekt getestet --> läuft !! Hast du das auch vorher getestet ? 
(Brauchst
nicht schummeln bei deiner Antwort).

Zum Thema Codesize:
Mit AVR Studio 4.13, Build 528 und -O0 und WinAVR-20070122 komme ich 
immer noch auf 1594 bytes. Aber ich habe schon von Jörg Wunsch mal 
gelesen, dass die WinAVR-20070122 etwas mehr Code erzeugt als seine 
Vorgänger --> aber gleich 50% ??

Vielleicht kommt man diesem Geschwür ja noch auf die Spur.

Vielen Dank für deine vielen nützlichen Tips im Code.

Gruß
Manni

P.S.: Und morgen hab ich die obige #define Anweisung auch verstanden !!!

von Manni (Gast)


Lesenswert?

@Peter

Das Geschür wurde gefunden. Habe nicht beachtet, dass du mit -Os 
arbeitest.

von Peter D. (peda)


Lesenswert?

Manni wrote:

> Ich habe dann natürlich deinen geänderten Code sofort am "lebenden"
> Objekt getestet --> läuft !!

Also mal kein Schusselfehler drin :-)


> Hast du das auch vorher getestet ?

Nein, ich hab diesen Chip nicht.

Aber ich mache vieles seriell (I2C, SPI, 1-Wire, SW-UART, ...), dann 
kann man sowas schon im Schlaf.


Brauchst Du noch die Erklärung für das Macro ?


Peter


P.S.:
Single-Master I2C mache ich grundsätzlich in SW, ist am einfachsten, 
wenig Code, portabel und läuft immer.
Ständig hört man hier und bei AVRfreaks Hilferufe von Leuten, die am 
HW-I2C verzweifeln.

von Manni (Gast)


Lesenswert?

@Peter

Thema Macro: wie gesagt: einmal drüber schlafen und nun habe auch ich es 
kapiert.

Soweit ich mich aber noch erinnere, war das hier ".b##pin" kein K&R 
Standard, deshalb stutze ich erst mal.

Manni

von Marc (Gast)


Lesenswert?

Hallo leute
Habe den Code bei mir auch mal ausprobiert, ( den von Peter )
und es hat nicht auf anhieb funktioniert.
habe in der Funktion ReadByte eine kleine Änderung vorgenommen und nun 
gehts
1
uint8_t RTC_ReadByte (void)
2
{
3
  uint8_t    i;
4
  uint8_t    val=0;
5
6
  for( i = 8; i; i--){
7
    RTC_Clock = 1;
8
    if( RTC_Data_in )
9
      val |= 0x80;   // MSB last
10
    RTC_Clock = 0;
11
    val >>= 1; 
12
  
13
  }
14
  return val;
15
}

  

von Peter D. (peda)


Lesenswert?

@Marc,

der RTC4513 ist ja relativ gemächlich (Daten erst gültig 250ns nach 
Clock 0-1-Flanke).

Wenn Du zu den Geschwindigkeitsfetischisten gehörst, die ihren AVR immer 
mit 16MHz betreiben müssen, könnts knapp werden und Du liest die Daten 
mit 1Bit Versatz ein.

Dann mach aber lieber noch ein NOP rein, anstatt das MSB wegzuschmeißen.


Peter

von Marc (Gast)


Lesenswert?

@Peter

mein AVR läuft eigentlich auf 8 MHz. mit dem internen Clock.
den externen Quarz mit 16 Mhz. habe ich noch garnicht Konfiguriert :-).
vllt liegt es auch daran das ich einen anderen chip verwende ( 
atmega2560 ).
Wie meinste das MBS weggeschmissen ?
habe nur die zeile "val >>= 1; " verschoben

vorher:
1
uint8_t RTC_ReadByte (void)
2
{
3
  uint8_t    i;
4
  uint8_t    val=0;
5
6
  for( i = 8; i; i--){
7
    val >>= 1; 
8
    RTC_Clock = 1;
9
    if( RTC_Data_in )
10
      val |= 0x80;   // MSB last
11
    RTC_Clock = 0;
12
  
13
  }
14
  return val;
15
}
nachher
1
uint8_t RTC_ReadByte (void)
2
{
3
  uint8_t    i;
4
  uint8_t    val=0;
5
6
  for( i = 8; i; i--){
7
    RTC_Clock = 1;
8
    if( RTC_Data_in )
9
      val |= 0x80;   // MSB last
10
    RTC_Clock = 0;
11
    val >>= 1; 
12
  }
13
  return val;
14
}
bin noch recht frisch in der microcontroller Programmierung.
wenn man von der schuhlerfahrung mit nem 8086 absieht.

von Joe (Gast)


Lesenswert?

Schau dir mal an wann du "clock'st" und wann Peter ;-))

von Manni (Gast)


Lesenswert?

@Marc
Wenn du die Anweisung:

val >>= 1;

als letzte in die for Schleife packst, "schmeisst" du das LSB (hier zu 
verstehen als erstes gelesene Bit) wieder raus. Wenn dein Code damit 
funktioniert, liegt's nur daran, dass du 'gerade' Zahlen empfangen hast.

Das kann also nicht gehen. Der überarbeitete Code von Peter ist schon 
richtig gewesen.

Zum Thema "Timing":
Da ich den code für 8MHz clock geschrieben habe, braucht's keine Timing 
Routinen. Bei mehr als 8 MHz sollte man ins Datenblatt schauen --> siehe 
mein erstes zip file: RealTimeClock_RTC4513.zip

Gruß
Manni

von Irosenhagen (Gast)


Lesenswert?

Hey,
ich hab die Routinen auf einem ATmega 2561 mit 14.75MHz geflasht.
Durch den anderen Takt lese ich jetzt immer die doppelten Werte aus, hat 
jemand nen Tipp wie ich die Routine auf die andere Frequenz anpasse?
Da alles exakt verdoppelt zu sein scheint, ist das doch nur ne 
Bitverschiebung um eine Stelle?

von Irosenhagen (Gast)


Lesenswert?

Moin,

mal ne grundlegende Frage zur Benutzung der Uhr:

Muss ich die RTC bei jedem Start des Controllers neu initialisieren oder 
reicht es die einmal zu initialisieren, die Uhrzeit einzuspeichern und 
dann läuft die weiter?

Es kann ja durchaus sein, dass der Controller längere Zeit aus ist.

von Manni (Gast)


Lesenswert?

@Irosenhagen

Sorry für den Delay :-(

Zum Thema: 14.75MHz
Ich habe die S/W mit 8MHz getestet. Bei höheren Takts solltest du in den 
Routinen RTC_ReadNibble und RTC_WriteNibble entsprechende Delays 
einbauen, da ggf. die spezifizierten Delays aus dem Datenblatt (siehe 
RealTimeClock_RTC4513.zip) nicht mehr eingehalten werden. Vielleicht 
hilft das weiter.

Zum Thema: neu initialisieren
Ganz einfach: Wenn Strom weg, dann auch Datum weg

Gruß
Manni

von AVR (Gast)


Lesenswert?

@Manni,

Hallo Manni,

zuerst vielen Dank, Manni.

Mein RTC4513 ist noch unterwegs, deshalb habe ich den Programmcode noch 
nicht probiert. Nun möchte ich das auch, dass die Rechtzeituhr von DCF77 
synchronisiert werden kann. Ich habe DCF77 mit Interrupt schon 
programmiert und es funzt super. Nun ist die Schwierigkeit 
vorzuschweben, wie RTC4513 durch DCF77 zu synchronisieren. Sollte man 
nur einpaar Parameter (Day, Month, Year...) von DCF77-Program als 
Funktionsparameter von RTC-Programm einsetzen, oder? Wie kannst du jede 
Stunde einmal synchrnisieren?
Es wäre schon, wenn du mir einpaar vorschläge geben, oder den Sourcecode 
zur Synchronisation mit DCF77 anhängen kannst.
Respekt und Danke!

AVR

von Manni (Gast)


Lesenswert?

@ AVR (Gast) oder Juan

Wo ist das Problem ?

Geht z.B. mit folgendem Code, wenn du die in 
RealTimeClock_RTC4513_Ver2.zip implementierte Funktion 
RTC_SetTimeDateDoW (&RTC_Time) verwendest. Annahme ist, dass du die DCF 
Zeit im struct DCF_Time hast.

Gruß
Manni

uint8_t ReadDCF_SetRTC (void)
  {
  uint8_t      i;
  DCF77_Time_typ  DCF_Time;
  RTC_Para_typ  RTC_Time;
/*
** Update RTC, when full hour from DCF77
*/
  if (DCF_Time.Minute == 0 && DCF_Time.Second == 0)
    {
/*
** Set the Real Time Clock
*/
    RTC_Time.Second  = 0;
    RTC_Time.Minute  = DCF_Time.Minute;
    RTC_Time.Hour  = DCF_Time.Hour;
    RTC_Time.Day  = DCF_Time.Day;
    RTC_Time.Month  = DCF_Time.Month;
    RTC_Time.Year  = DCF_Time.Year;
    RTC_Time.DayOfWeek  = DCF_Time.WeekDay;

    RTC_SetTimeDateDoW (&RTC_Time);
    }

  return 0;
  }

von Juan (Gast)


Lesenswert?

Hallo Manni,

für die Beratung schon erstmal Danke.

Guß
Juan

von Anton A. (bingo_)


Lesenswert?

Ich überlege mir auch den Einsatz dieser Uhr.
Läuft diese jetzt über SPI Bus oder nimmt man ganz normale IO Pins?
Falls SPI weiß ich nicht was ich mit STD.P und DATA machen soll.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.