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
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
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
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
@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
@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 !!!
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.
@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
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
@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
@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_tRTC_ReadByte(void)
2
{
3
uint8_ti;
4
uint8_tval=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
returnval;
15
}
nachher
1
uint8_tRTC_ReadByte(void)
2
{
3
uint8_ti;
4
uint8_tval=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
returnval;
14
}
bin noch recht frisch in der microcontroller Programmierung.
wenn man von der schuhlerfahrung mit nem 8086 absieht.
@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
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?
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.
@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
@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
@ 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;
}
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.