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 !!!
@Peter Das Geschür wurde gefunden. Habe nicht beachtet, dass du mit -Os arbeitest.
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
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 | }
|
@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_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.
@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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.