Datum: 18.12.2003 22:55
Sehr oft kommt hier die Frage wie man einen Sekundentakt erzeugen kann oder ob man unbedingt einen Uhrenquarz oder, noch schlimmer, einen extra RTC-Chip braucht. Die Antwort lautet: Nein ! Man kann bequem mit dem Timer aus jeder X-beliebigen Quarzfrequenz auf den Takt genau die Sekunde erzeugen. Und dann, immer wenn 60 Sekunden um sind, ein Minutenregister hochzuzählen, nach 60 Minuten ein Stundenregister und nach 24 Stunden den Tag, das ist ja wohl keine Kunst mehr. In den Beispiel habe ich versucht, den mathematischen Weg aufzuzeigen. Außerdem ist dann noch ein Beispielcode in C und in Assembler mit dabei. Letztendlich übernehmen beide die nötigen Berechnungen vollautomatisch, solange man die beschriebenen Randbedingungen einhält. Man muß also nur seine Quarzfrequenz in den Sourcecode eintragen und ihn compilieren bzw. assemblieren lassen. Peter
Datum: 19.12.2003 09:37
Hallo Peter, wie sieht es denn mit der Ganggenauigkeit über 1Jahr aus? Ist da ein Uhrenquarz nicht genauer und stabiler? Schönen Gruß Tipper
Datum: 19.12.2003 11:18
@Tipper "wie sieht es denn mit der Ganggenauigkeit über 1Jahr aus?" Ich kann nicht klagen. Ich habe schon seit mehreren Jahren eine Uhr mit einem billigen Standard Quarz 11,0592MHz am laufen. Zu Anfang habe ich sie 3 Monate laufen lassen und mit der Videotext Uhr verglichen. Dann die ermittelte Frequenz eingetragen und neu compiliert und geflasht. Der MC ist ein AT89C2051. Zur Zeit geht sie 14s vor, dieses Jahr habe ich sie noch nicht gestellt (Sommerzeitumstellung ist mit einprogrammiert). Es gibt aber auch von Maxim einen neuen Zeitgeber-Chip mit 38kHz, der mindestens um den Faktor 10 besser ist als ein Standard 38kHz Quarz. Prinzipiell sind höherfrequente Quarze immer auch genauer. Früher wurde deshalb für hochgenaue Uhren ein 4,19MHz Quarz verwendet. Wie man aber an Maxim sieht, kann man durch bessere Technologie diesen Unterschied kompensieren. Es könnte aber auch sein, daß in dem Chip ein Temperatursensor mit integriert ist und dann mit einer Korrekturtabelle die Schwankungen ausgeglichen werden. Peter
Datum: 19.12.2003 22:55
junge junge, so langsam glaub ich du bist echt der mikrocontroller gott!! und auch noch ne anleitung dazu. besser gehts ned!! :)
Datum: 21.12.2003 19:02
" junge junge, so langsam glaub ich du bist echt der mikrocontroller gott!! " Geht mir auch so . Ich müsste noch mal auf die Welt kommen , und mit ca. 6 Jahren anfangen mit MC zu spielen ...
Datum: 22.12.2003 00:10
Sehr schöne sache, gefällt mir gut, der code ist ebenfalls recht verständlich aufgebaut und so langsam klappt es auch bei mir mit den ganzen "timer gelumpe" :-) Weiter so! Danke! Mfg Marcel
Datum: 22.12.2003 22:09
Hallo Leute! Noch eine Erfahrung hätte ich beizusteuern:Siet dem 10.Oktober habe ich hier eine Uhr im Gang, die mit At90S2313 und 4MHZ-Quarz arbeitet. Das Ding habe ich seitdem nicht mehr gestellt und es läuft immer noch synchron zum Zeitsignal aus Mainflingen. Man kann generell sagen:Je höher die Quarzfrequenz, desto geringer die Abweichung. MfG Paul
Datum: 29.12.2003 00:41
Hallo, ich nehme trotzdem lieber einme RTC mit Gangreserve, da kann mit dem uC rumspilen und muss nicht ständig die Zeit neu einstellen oder auf DCF-Dekodierung warten. Gruss A. Arndt
Datum: 29.12.2003 10:22
Hi,
Den Code von Peter finde ich ziemlich cool.
Hier sind trotzdem kleine Verbesserungsvorschläge.
Wird im Timer die Option "Clear On Compare Match" verwendet,
so verliert man den Overflow Interrupt.
Oder möchte man nebenher noch eine Zeit mit dem Capture Interrupt
messen, so benötigt man einen durchlaufenden Timer.
Um dies zu erreichen, wird OCR1A nicht fest eingestellt, sondern
bei jedem Aufruf um den gleichen Wert erhöht.
In Peter's Code wurde der Rest auf einmal abgearbeitet. Damit erspart
man sich bei jedem Interrupt einen Vergleich und die Verarbeitungszeit
verkürzt sich in seinem Code. Der Unterschied zwischen kurzem und
langem
Interrupt ist hier der Rest.
Bei den geänderten Codeschnipseln wird der Rest gleichmäßiger
abgearbeitet.
Der Unterschied zwischen kurzem und langem Interrupt beträgt 1 Takt.
mfg
werner
ungetesteter Code für den durchlaufenden Timer:
==================================================
SIGNAL
(SIG_OUTPUT_COMPARE1A) {
/************************************************************************/
/* Insert Key Debouncing Here */
/************************************************************************/
if( --prescaler == 0 ){
prescaler = DEBOUNCE;
second++; // exact one second over
}
if (prescaler <= XTAL % DEBOUNCE) {
OCR1A += XTAL / DEBOUNCE +1; /* um 1 Takt längere Periode um
den Rest abzutragen */
} else {
OCR1A += XTAL / DEBOUNCE; // kurze Periode
}
}
Um im Sonderfall, daß XTAL%DEBOUNCE null ist, keinen unnötigen
Code zu haben, kann man wieder Präprozessoranweisungen verwenden:
SIGNAL
(SIG_OUTPUT_COMPARE1A) {
/************************************************************************/
/* Insert Key Debouncing Here */
/************************************************************************/
if( --prescaler == 0 ){
prescaler = DEBOUNCE;
second++; // exact one second over
}
#if XTAL % DEBOUNCE
if (prescaler <= XTAL % DEBOUNCE) {
OCR1A += XTAL / DEBOUNCE +1; /* um 1 Takt längere Periode um
den Rest abzutragen */
} else {
#endif
OCR1A += XTAL / DEBOUNCE; /* kurze Periode */
#if XTAL % DEBOUNCE
}
#endif
}
Datum: 29.12.2003 18:56
Sehr schön. Es freut mich immmer wieder, wenn jemand meinen Code versteht und darauf aufbauend sogar noch Verbesserungen oder auch andere Meinungen dazu hat. Peter
Datum: 02.01.2004 13:34
Ja, weil Quarze um 5 MHz am stabilsten sind wurden früher (um 1930 - Mitte letztes Jahrhunder) damit die damals geauesten Uhren der Welt gebaut; Uhrenquarze eignen sich eigentlich nur wegen der geringen Frequenz und der daraus folgenden niedrigen Stromaufnahme gut für Uhren. Wenn man es genau machen will, dann kann man noch (Dreh-)Kondensatoren (von den Quarz-Kontakten sowie -Gehäuse zu Masse) und einen Parallel-Widerstand/-Poti anschließen und damit die Frequenz genau einstellen (mit einem 12-stelligen Frequenzzähler). Genauer geht es dann nocht mit der Temperatur-Kennlinie der Schaltung, die man mit Software (u. dem MC-internen Temp.-Sensor) eliminieren kann. Wegen Schaltsekunden u. A. ist aber sowas wie DCF77 oder NTP meist sinnvoller als dieses Feintuning. Mal eine Frage zur Sommer-/Winter-Zeit: Gibt es dafür eine Formel? Gefunden hab ich ja schon Formeln für Schaltjahre, Tage seit dem 1.1.1, Wochentag, Kalenderwoche (nach DIN 1355) auch vor 1500 aber noch keine für Sommer-/Winterzeit.
Datum: 02.01.2004 14:18
Hi Umstellung von Winterzeit auf Sommerzeit: Am letzten Sonntagmorgen im März werden die Uhren von 02:00 auf 03:00 Uhr vorgestellt. Man verliert eine Stunde. Umstellung von Sommerzeit auf Winterzeit: Am letzten Sonntagmorgen im Oktober werden die Uhren von 03:00 auf 02:00 Uhr zurückgestellt. Man gewinnt eine Stunde. Matthias
Datum: 02.01.2004 14:42
In meinem Beispielcode für die RTC DS1994 ist sowas in Assembler mit drin, prüft jeden Sonntag darauf. Funktioniert aber nicht mehr 2100, da das kein Schaltjahr ist, d.h die Sonntagserkennung schlägt fehl. Ich nehme auch ab 2100 gerne sämtliche Beschwerden diesbezüglich entgegen. Peter
Datum: 02.01.2004 20:29
@Matthias: Woher hast Du das? Es muß dafür eine Norm geben, aber welche konnte ich noch nicht finden. Naja, wenn die Sommerzeit so plötzlich abgeschafft wird, wie sie eingeführt wurde, dann hat sich das Problem erledigt. @Peter: In "Das C++ Codebook" steht einiges z. B. mit den Tagen seit dem 01.01.0001, das aktuelle Sternzeichen usw.. Für MCs ist aber eher dies hier interessant (i. W. C mit einigen C++-Resten): // http://home.nordwest.net/hgm/kalender/kal-61.htm // bis http://home.nordwest.net/hgm/kalender/kal-66.htm // http://home.nordwest.net/hgm/kalender/kal-aa.htm Ich habe das angepasst für einen MC, der mit der Zeit seit 1.1.2000 0:0:0 rechnet. Bis auf Schaltsekunden u. Winter-/Sommerzeit stimmt die Zeitrechnung damit (auch mit ALLEN zukünftigen Schaltjahren), aber 2068 läuft der 32-Bit-RTC-Zähler über. Die Wochentage u. Kalenderwochen nach DIN 1355 stimmen mit den Funktionen auch. Fehlen eigentlich nur noch die Mondphasen ...
Datum: 02.01.2004 20:49
Hi von der PTB: http://www.ptb.de/de/wegweiser/infoszurzeit/fragen/11.html Matthias
Datum: 03.01.2004 01:44
Aha, danke :-) Bei meinen Links findest Du eine kompakte u. korrekte Version zur richtigen Berechnung der Schaltjahre. Mit einem 128-Bit-Sekundenzähler gibt´s dann nur das Problem der Schaltsekunden und der Quarz-Ungenauigkeit.
Datum: 08.01.2004 22:04
Kirk an Peter: Wie siehts aus mit der Lösung unseres Jahr-2100-Problems? ;-))) Stefan
Datum: 08.01.2004 22:43
@Stefan "Wie siehts aus mit der Lösung unseres Jahr-2100-Problems?" Ich stelle sie natürlich am 28.02.2100 hier ins Forum. Kannst mich ja am 27.02.2100 nochmal daran erinnern. Peter
Datum: 09.01.2004 20:15
Wo soll 2100 ein Problem sein?
Die Schaltjahr-Berechnung ist doch ganz einfach:
function ist_Schaltjahr(jahr) {
if (jahr % 4 == 0)
if (jahr < 1582)
return 1;
else if (!(0 == jahr % 100))
return 1;
else if (0 == jahr % 400)
return 1;
return 0;
}
http://www.nwn.de/hgm/kalender/kal-61.htm
Die Abfrage mit dem Jahr 1582 kann man im Microcontroller weglassen.
Datum: 10.01.2004 13:52
"Wo soll 2100 ein Problem sein?" Ich dachte, daß meine Bemerkungen dahingehend eindeutig sind: Es macht einfach keinen Sinn, sich schon jetzt damit zu beschäftigen. Keiner weiß doch, ob der Flash-Speicher überhaupt dazu in der Lage ist, 100 Jahre lang einen Programmcode fehlerfrei zu speichern. Peter
Datum: 10.01.2004 17:28
Ich meine ja nur, dass man die Formel zur Schaljahrberechnung in wenigen Sekunden korrigieren kann; das sind ja weniger als 10 kurze Zeilen.
Datum: 25.05.2004 17:23
Hi, Peter! Habe ich den folgenden Satz in deiner Beschreibung richtig verstanden? -------------------------------------------------------------- Deshalb wird jedensmal, wenn der Softwareteiler Null ist und die Sekunde weitergezählt wird, ein anderer Comparewert geladen. Dieser ist dann um den Rest größer. Und beim nächsten Timerinterrupt wird dann wieder der Comparewert geladen, der das Ergebnis der Division war. -------------------------------------------------------------- Heißt das, dass der Comparewert beim ersten mal 43198 + 64 ist, um die fehlenden 64 Zyklen in der Sekunde auszugleichen, und alle anderen Comparewerte in der selben Sekunde sind 43198? Martin
Datum: 31.05.2004 20:12
Hallo Martin, > Heißt das, dass der Comparewert beim ersten mal 43198 + 64 ist, > um die fehlenden 64 Zyklen in der Sekunde auszugleichen, > und alle anderen Comparewerte in der selben Sekunde sind 43198? Ja. Ganz genau das heißt das. Gruß, Markus
Datum: 15.10.2004 11:58
Hallo Peter, bin jetzt auch nochmal auf den DS1994 bzw. DS1904 gestossen, der zählt ja nur Sekunden hoch und ich müsste dann immer in Minuten,, Stunden Tage, Monate und Jahre umrechnen, gibt es kein anderes ibutton der diese Daten wie der Ds1307 ablegt ? Gruss A. Arndt
Datum: 15.10.2004 17:18
Ja, ich finde das auch sehr umständlich. In meinem Tiny12 Beispiel wird einfach beim Einschalten die Uhr hochgezählt, bis der 32Bit-Wert mit dem im DS1994 gleich ist. Das kann dann in 100 Jahren schon ein paar Sekunden dauern. Allerdings ist der DS1994 nicht sehr genau. Bei mir geht er 10min/Jahr vor. Ich müßte also noch den 32Bit-Wert mit 0,99998049 multiplizieren, aber dann wird eng im Tiny12 mit dem Programmspeicher. Peter
Datum: 15.10.2004 17:29
Hi dann zieh doch einfach alle 52560 Sekunden eine Sekunde ab. Matthias
Datum: 15.10.2004 17:48
Naja, wenn da alle x Sekunden korrigiert wird, dann kann das Fehler verursachen, beispielsweise bei Zeitdifferenz-Messungen. Beim Multiplizieren ist es ähnlich, denn die Sekunden werden ja nur ohne Nachkommastellen, also gerundet verwendet; d. h. plötzlich dauert eine angezeigte Sekunde zwei Sekunden oder null Sekunden; das kann auch Fehler verursachen.
Datum: 16.10.2004 09:56
Hi natürlich kann das Probleme machen. Wenn aber nur um eine reine Uhr geht ist das eigentlich keine große Sache. Man zieht die Sekunde natürlich nicht um 12:00 Uhr Mittags ab sondern irgendwann mitten in der Nacht. Matthias
Datum: 15.11.2004 09:58
Hallo Rolf! Habe ich Deinen Beitrag richtig verstanden, dahingehend, dass Du die Uhr auf der Basis des Julianischen Datums programmiert hast? Falls ja und wenn Du es hergeben würdest, würde ich mir das Programm gerne mal ansehen. Grüße aus Berlin tex
Datum: 15.11.2004 19:13
Hallo tex, das Programm macht nichts anderes als einen 32-Bit-Zähler hochzuzählen - jede Sekunde einmal + gelegentlich Minute, Stunde usw. hochzählen. Code ist u. a. von hier: http://home.nordwest.net/hgm/kalender/kal-61.htm bis http://home.nordwest.net/hgm/kalender/kal-66.htm http://home.nordwest.net/hgm/kalender/kal-aa.htm Dabei ist mir wichtig, dass Schaltjahre richtig berechnet werden und leicht berechnet werden kann, ob ein Datum existiert oder nicht, wie z. B. der 31.2.. Mit ein paar kleinen Funktionen ist das kein Problem. Zusätzlich habe ich u. A. noch kleine Funktionen beispielsweise zum Inkrementieren u. Dekrementieren des Datums gemacht.
Datum: 15.11.2004 19:52
Hi Nobody0! Das Geheimnis des Julianischen Datums ist, das es keine falschen Tage gibt, also keinen 31.2. ... Die ganze Bastelei mit den Tagen, Monaten ect. ist total überflüssig, wenn man die Information aus dem JT zieht. Dann kommen alle Gemeinheiten des Kalenders ganz automatisch 31.7 / 31.8. ... Das Julianische Datum hab ich unter Kontrolle ich bin zu blöd den Zähler zu programmieren!
Datum: 16.11.2004 10:12
Das hilft aber nicht, wenn in einem Menü ein User als Geburtsdatum den 31.2.2033 eingeben kann. Bei 99,9 % aller Menüs oder anderer Eingaben kann dies nicht direkt abgefangen werden, weil da immer der Tag 1 bis 31 ausgewählt werden kann und ähnliches für Monat und Jahr gilt. Dass es das obige Datum nicht gibt und selbst die dem nahekommenden Daten (Dekrementieren/Inkrementieren bis ein gültiges Datum erreicht wird) in der Zukunft liegen, sollte mit ein paar kleinen Funktionen erkannt werden. Das Datum muß vor der eigentlichen Verarbeitung erstmal einige Checks bestehen, bevor es akzeptiert werden kann.
Datum: 16.11.2004 11:01
OK! Da haben wir total gegensätzliche Anwendungen. Ich brauche eine genaue Uhrzeit im µC. Da sind abstrakte Usereingaben nur bedingt relevant. Ich habe halt bisher nur absurde Kalendarien gefunden die in gigantischen Arrays definiert wurden um die ganzen Absurditäten unseres Kalenders abzufangen, Sekunden wurden zu Minuten aufaddiert, Minuten zu Stunden ... Ich möchte die Uhr über die serielle Zahl des Julianischen Datums definieren, weil ich so diesen absureden Kram mit Minuten, Sekunden, Stunden, Tagen, Schaltjahren ... los bin. Die Formeln für das Datum habe ich aber bei Interrups, Counterpreloads, ... hörts bei mir auf.
Datum: 16.11.2004 18:09
Das ist doch ganz einfach: Nimm als Zähler die Sekunden seit z. B. 1.1.2000 0:00:00 und rechne ohne Schaltsekunden (d. h. in TAI): blub = counter; blub %= 60; Sekunden = blub; blub %= 60; Minuten = blub; usw. Für Tage im Monat braucht man ein Array und für Tage im Jahr die Schaltjahr-Funktion. In einer Schicht darüber kann man Schaltsekunden berücksichtigen und eine weitere Schicht darüber Sommer-/Winter-Zeit. Darüber wiederum kann man weiteres packen, beispielsweise metrische Zeitrechnung für eine metrische Uhr. Damit man wenig einstellen muß, nehme ich als Startwert den vom Zeitpunkt der Compilierung; dafür gibt's ja _DATE__ und __TIME_.
Datum: 16.11.2004 18:25
Nachtrag: Vor der Minuten-Zeile muss blub /= 60; stehen. Danach hat man die Zeit in Minuten. Dasselbe muß in die Zeile darunter; danach hat man die Zeit in Stunden. So kommt man letztlich zum Jahr.
Datum: 25.12.2004 16:40
Huhu Peter, hab mal ne Frage: Du hast jeweil im main-loop folgendes stehen: ASM: out ddrb, second C: LED_DIR = second (wobei LED_DIR weiter Oben als DDRB deffiniert ist) sollte das nicht jeweils PORTB heißen? Oder versteh ich da den Code net richtig? Ansonsten Danke für den Code funktioniert super. Frohes Fest, Jochen
Datum: 25.12.2004 20:19
hat von euch schon mal jemand versucht vom tv-signal eine referenz-frequenz abzuleiten ?? weil die haben doch ein besseres trift-verhalten als ein normal quarz... und wie schauts eigentlich mit den teilen aus handys aus??? sind die stabil oder werden die durch das signal von den basis stationen stabil gemacht? und dann ist da noch die frage wie stabil sind die 50hz....fragen über fragen ;) 73+55 für 2005 de oe6jwf / hans
Datum: 25.12.2004 20:52
@Jochen, die Ports sind ja nach den Reset auf 0. Daher kann man eine LED einschalten, indem man das Directionbit auf 1 setzt. Peter
Datum: 25.12.2004 23:56
Joo, so stimmt das natürlich auch wieder ;-) Danke für die Antwort Jochen
Datum: 12.01.2005 12:06
Hallo Hans, schau mal bei DK6RX Gruss Kurt
Datum: 05.03.2005 18:21
Hallo... so hab das ganze jetzt mal aufgegriffen, und ein kleines Problem damit: ich hab mal den asm code genommen und kompiliert. Dabei bekam ich in Zeile 71 einen Fehler. ldi prescaler, debounce Das Prog versucht 256 in r18 zu schreiben => geht nich, zu groß die Zahl => out of Range kann es also sein, dass das nicht ldi prescaler, debounce sondern ldi prescaler, debounce-1 heißen muss??? würd mich freuen wenn mir da mal jemand weiter helfen kann... schöne grüße Alex
Datum: 05.03.2005 19:43
Die Zahl 256 ist einfach wieder 0. Damit wird die Sekunde in 256 Unterschritte (Timerinterrupts) aufgeteilt. Die Zahl muß nur so gewählt werden daß Clock/debounce < 0xFFFF ist und debounce selber <= 256 Mit 256 (0) hat Peter die Maximale Anzahl an Unterschritten gewählt. Ich würde eher 250 nehmen, dann vergehen zwischen den Timerinterrupts 4ms. Wenn du die Fehlermeldung entfernen willst kannst du die konstante kapseln z.B. LOW_BYTE(debounce). Ich halte dies aber nicht für empfehlernswert. BTW: hat der assembler eine Warnung oder eine Fehlermeldung ausgegeben? Welchen Assembler hast du verwendet? MfG Werner
Datum: 05.03.2005 19:46
Hallo, ich verwende mom AVRStudio und es war ein Error und keine Warning. soll ich dann einfach 0 statt 256 nehmen? also ldi prescaler, 0 ? schöne Grüße
Datum: 05.03.2005 20:08
Nein, den debounce wird, wie du sicherlich gesehen hast, auch für die Berechnung anderer Register verwendet. Wenn du debounce auf 0 setzt sind diese Werte falsch. Es ist besser du reduzierts debounce ein wenig.
Datum: 05.03.2005 20:11
Ne ich meinte die Konstante gleichlassen, nur in den betroffenen Zeilen halt nicht debounce einzufügen, sondern 0, also halt wie oben ldi prescaler, 0 statt ldi prescaler, debounce die anderen Register würden dadurch doch nicht verändert mfG
Datum: 05.03.2005 20:21
Von der Funktion her kannst du das zwar machen, aber spätestens wenn du den Wert von debounce beim nächsten mal änderst, wirst du die Null vergessen und dein Programm funktioniert nicht mehr richtig. Konstanten sollten im Quelltext alle nur einmal definiert werden. Konstanten im Programm haben, abgesehen von Spezialfällen, nichts im Programmquelltext zu suchen.
Datum: 05.03.2005 20:22
OK ;) hab erst vor was mehr als 2 Wochen angefangen, gut zu wissen mit den Konstanten (leuchtet auch irgendwie ein^^) schönen Abend noch!
Datum: 13.04.2005 12:42
Hallo zusammen, ich habe mich mal so durch die Beiträge gehangelt. Bin momentan an einen Projekt beschäftigt, in dem ein RTC4553 Chip eingesetzt ist. Da sich das Datenblatt über die Ansteuerung nur spärlich auslässt, wollte ich mal anfragen, ob jemand schon mal mit dem Chip gearbeitet hat. Ich kann irgendwie die Zeit nicht vorgeben bzw. auslesen. Keine Ahnung, ob das an der SPI-Übertragung liegt. Im Datenblatt wird alles mit A3..A0,D3..D0 angegeben und für die Übertragung muss man dann die Daten in der Reihenfolge A0..A3,D0..D3 anlegen bzw. auslesen. Kann da jemand weiterhelfen????
Datum: 13.04.2005 16:22
@T. Kirchen Bitte nicht einen Thread hijacken sondern für neue Fragen einen neuen Thread aufmachen ! Hier ging es nämlich gerade NICHT um externe RTC-Chips. Peter
Datum: 24.04.2005 16:24
Dar ich dein code im wiki veröffentlichen?
Datum: 25.04.2005 18:54
Datum: 10.05.2005 18:43
Sorry ich bin blutiger Anfänger und habe mir das Assemblerscript mal egnommen. Allerdings bekomme ich an den 8 LEDs nichts zu sehen wenn ich es programmiere. Ich benutze einen ATMega128. Es sind nur die Kompatibilitätsfuse geändert worden und JTAG ausgeschaltet. Takt ist demnach noch 1MHz (so stehts auch im AVR Studio) Im Code habe ich nur an den beiden Zeilen wo auf ddrb geschrieben wird ddrC genommen. Habe ich etwas vergessen zu konfigurieren im Code oder liegt das an meiner HW?
Datum: 11.05.2005 16:18
Wenn Du DDRB in DDRC änderst, musst Du natürlich auch PORTB in PORTC (und ein eventuell vorhandenes PINB in ein PINC ändern).
Datum: 22.10.2005 14:08
Hi, habe mir gerade mein erstes AVR-Testboard aufgebaut, aber leider
bekomme ich die Uhr nicht zum laufen :/
Benutze einen 90S8515 mit 8Mhz quarz.
Habe #define OCR1A OCR1 auf #define OCR1A OCR1A geändert,
und die KEY_INPUT geschichte sowie unten die whileschleife
auskommentiert in der Hoffnung dass die Uhr dann sofort losläuft.
Leider gehts nicht... kann mir jemand weiterhelfen ?
#include <io.h>
#include <interrupt.h>
#include <signal.h>
#ifndef OCR1A
#define OCR1A OCR1A // 2313 support
#endif
#ifndef WGM12
#define WGM12 CTC1 // 2313 support
#endif
//#ifndef PINC
//#define KEY_INPUT PIND // 2313
//#else
//#define KEY_INPUT PINC // Mega8
//#endif
#define LED_DIR DDRB
//#define XTAL 11059201L // nominal value
#define XTAL 8000000L // after measuring deviation: 1.5s/d
#define DEBOUNCE 256L // debounce clock (256Hz = 4msec)
#define uchar unsigned char
#define uint unsigned int
uchar prescaler;
uchar volatile second; // count seconds
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
/************************************************************************/
/* Insert Key Debouncing Here */
/************************************************************************/
#if XTAL % DEBOUNCE
OCR1A = XTAL / DEBOUNCE - 1; // compare DEBOUNCE - 1 times
#endif
if( --prescaler == 0 ){
prescaler = (uchar)DEBOUNCE;
second++; // exact one second over
#if XTAL % DEBOUNCE // handle remainder
OCR1A = XTAL / DEBOUNCE + XTAL % DEBOUNCE - 1; // compare once per
second
#endif
}
}
int main( void )
{
LED_DIR = 0xFF;
//while( KEY_INPUT & 1 ); // start with key 0 pressed
TCCR1B = 1<<WGM12^1<<CS10; // divide by 1
// clear on compare
OCR1A = XTAL / DEBOUNCE - 1;
TCNT1 = 0;
second = 0;
prescaler = (uchar)DEBOUNCE;
TIMSK = 1<<OCIE1A;
sei();
for(;;){
if( second == 60 )
second = 0;
LED_DIR = second; // display second (binary)
}
}
Datum: 22.10.2005 16:05
Hallo Juel, du hast meine Variante mit der von Peter vermischt ohne die Anpassungen zu machen: 1. DEBOUNCE < 256 Begründung findest du weiter oben 2. Compare Match Interrupt aktivieren 3. Port bei der ausgabe beschreiben, nicht die Richtungsregister MfG Werner Die Init-Section für einen 2313 sieht bei mir so aus: -------------- seg7_init(); /* seg7_test(); */ TCCR1B = _BV(CTC1) | _BV(CS10); /* clear on compare match, prescaler 1 */ OCR1A = UC_CLOCK / SUB_CLOCK - 1; TCNT1 = 0; prescaler = SUB_CLOCK; TIMSK = _BV(OCIE1A); sei(); ---------------- SUB_CLOCK ist bei dir DEBOUNCE
Datum: 22.10.2005 16:17
TssTs. Mein Beitrag von vorher ist falsch, bis auf den Punkt 3. Du mußt den Wert auf den Port ausgeben: PORTD = second.
Datum: 22.10.2005 16:53
Dankeschön, jetzt gehts auch bei mir :) Echt super die schnelle Antwort!!
Datum: 02.01.2006 01:22
Hallo Peter, mit welchem Compiler hast du den Code geschrieben, bzw mit welchem kann man den Code in einen AVR flashen? Gruß Max
Datum: 29.03.2006 15:34
Das ist doch alles voll blöd hier. Da such ich ein Assembler Programm und alles was ich finde ist kein Assembler!
Datum: 29.03.2006 15:37
och du armer ;) weiß zwar nich was du unter nem Assembler Programm verstehst, ich versteh das darunter was im ersten post wunderbar zum download steht^^
Datum: 22.04.2006 17:14
morschen Leute ich habe den original Code von ganz oben verwendet und will damit möglichst genaue Sekunden erreichen. Ausgegeben wird dann Sekunde, Minuten und Stunden per UART, wenn der Timer Interrupt eintritt (jedoch am ende des Interrupts um die vorherige Hochzählung nicht zu stören). Leider scheint es trotzdem zu störungen zu kommen. Nach 1 Stunde habe ich schon eine Sekunde Abweichung. Kann mir jemand sagen warum, und wie ich sonst das kontrollierne kann, wenn nicht per UART?
Datum: 22.04.2006 17:57
Dein Oszillator/Quarz ist wahrscheinlich ungenau. Lass deine Uhr einen Tag laufen, miss den Zeitfehler aus und korrigiere XTAL entsprechend auf 3999....Hz
Datum: 22.04.2006 19:07
@Uffz, wenn die UART nicht mit Interrupt und gepuffert ist, dann darf man sowas lahmarschiges natürlich nicht in einen Interrupt schmeißen. Alles, was Du in den Interrupt reinpackst, muß bis zum nächsten Interrupt beendet sein. Peter
Datum: 22.04.2006 20:05
Ist es so dass die Endlosschleife im main() recht hochfrqeuentiert unterbrochen wird und in den Interrupt springt? Das sieht nämlich so aus . Bei mir ist es wichtig neben dem Counter-Zeug noch Ruhe für andere Sachen zu haben. Also etwa jede Sekunde in einen Interrupt springen wäre OK aber scheller würde mein Programmablauf zerreißen.
Datum: 22.04.2006 21:27
@Uffz, genau das ist ja der Sinn eines Interrupts, das Main zu unterbrechen, ohne daß es gestört wird. Deshalb sollte man ihn eben so kurz wie möglich halten und keine arschlahmen Sachen darin machen. Zerrissen wird dabei nichts. Peter
Datum: 28.01.2007 15:11
Hallo Peter, uchar prescaler; uchar volatile second; // count seconds müsste man prescaler nicht auch als volatile deklarieren? Martin
Datum: 02.04.2007 19:31
Angeregt durch einen anderen Thread habe ich gerade mal die "genaue Sekunde" ausprobiert. Das geht soweit ganz gut. Die erste Sache die man beachten muss ist natürlich: > OCR1A = XTAL / DEBOUNCE - 1; // compare DEBOUNCE - 1 times OCR1A darf nicht größer 65535 werden. Bei den neuen AVR mit 20MHz kommt aber folgendes Problem dazu. DEBOUNCE ist mit 256 zu klein ! Es muss mindestens 306 sein. XTAL / 65536 = 305,7 . prescaler muss dann ein uint sein. So klappt die "genaue Sekunde" wieder ;)
Datum: 24.09.2007 16:20
Ich hab den Code gestern ausprobiert und mich gewundert wieso bei mir die Sekunde ziemlich schnell lief? Den Fehler habe ich dann auch gefunden. prescaler wird mit 256 geladen, das ist doch zu groß, oder?¿? Nach uint geändert und schon läuft die Sekunde.
Datum: 24.09.2007 16:56
manow wrote: > Ich hab den Code gestern ausprobiert und mich gewundert wieso bei mir > die Sekunde ziemlich schnell lief? Den Fehler habe ich dann auch > gefunden. prescaler wird mit 256 geladen, das ist doch zu groß, oder?¿? > Nach uint geändert und schon läuft die Sekunde. Ne, das paßt schon. 256 wird zu 0 und nach 256 mal ist es wieder 0. Man kann also mit einem Byte /256 teilen. Der Fehler ist woanders, kannst ja mal Deinen Code als Anhang senden. Peter
Datum: 24.09.2007 17:31
Hmm, seltsamer weise kann ich den Fehler nicht mehr rekonstruieren. Jetzt funkt. es auch so, im Gegensatz zu heute halb drei in der Früh. Vielleicht war ich etwas langsam...