Guten Abend, bin noch nicht so erfahren mit dem Umgang mit
Mikrocontrollern,
zerbreche mir schon seit längerem den Kopf wie ich denn eine Uhr
Software machen könnte, damit ich Datum und Uhrzeit mitzählen lassen
kann, hab mir schon die Timer im Datenblatt des Atmega8L angeschaut und
weis nicht wie ich das realisieren könnte, hat mir jemand nen tipp oder
beispiel code?
gruß Walter
Du musst den Timer so konfigurieren, dass er jede Sekunde einen Impuls
erzeugt und zählst bei dem Impuls einfach die Sekundne um eins hoch.
Nicht schwer!
Eine Sekunde wirst du ev. nicht hinkriegen mittels Takt+Prescaler.
Macht aber nichts. Gehst halt dann auf 1/10 oder 1/100 Sekunde oder
überhaupt auf einen völlig anderen Bruchteil einer Sekunde, sagen
wir mal x.
Für deine ersten Schritte ist es am einfachsten den Overflow
Interrupt dafür zu benutzen. Später wirst du lernen wie
man das besser machen kann.
Also: Du hast deinen Timer so aufgesetzt, dass er x mal in der Sekunde
einen Overflow auslöst.
Also brauchst du eine Variable, die mitzählt, wie oft der Overflow
ausgelöst wurde: Bei jedem Overflow zählst du sie um 1 hoch.
Hat diese Variable den Wert x erreicht, ist eine Sekunde vergangen.
Also erhöhst du eine andere Variable, die die Sekunden in deinem
Programm darstellt und setzt den Overflow-Zähler wieder auf 0.
Hat die Sekunden-Variable den Wert 60 erreicht, setzt du die
Sekunden wieder auf 0 und erhöhst dafür die Minuten. Selbiges
in grün: Nach 60 Minuten ist eine Stunde vergangen und nach 24
Stunden ist ein 1 Tag vergangen. Ab da wird es dann marginal
schwieriger, da die Weiterschaltung der Monate in Abhängigkeit
vom Tag vom Monat selbst abhängt. Hat also der Tagzähler 30 erreicht
und ist gerade zb. April, so ist der nächste Tag der 1. und der Monat
geht um 1 hoch (=Mai). usw.
Konzentrier dich zunächst auf die Stunden:Minuten:Sekunden
Oder noch einfacher: Vergiss Stunden und Minuten fürs erste und zähl
einfach nur die Sekunden hoch. In der Phase kannst du dich voll auf
den Timer konzentrieren ohne dich mit Gedanken über Stunden und Tage
und Monate zu verzetteln.
Also dein 16 Bit Timer zählt bis 65536, dann läuft er über.
Bei 3,684 MHz und nem Vorteiler von 64 zält der Timer in einer Sekunde
auf 57562,5. Du musst nun deinen Timer auf 7973,5 vorladen, dann läuft
der Timer genau einmal pro Sekunde über.
Alle Angaben sind ohne Gewähr ;) Rechne lieber nochmal nach, der
Rechenweg dürfte ja soweit klar sein oder?
> ja nur was muss ich da für einen Vorteiler benutzen damit ich auf eine> Sekunde komme? mein Atmega8 läuft mit 3,684 Mhz
Da wirst du halt ein bischen Rechnen und Probieren müssen :-)
Ein 8-Bit Zähler generiert nach 256 Zählvorgängen einen Overflow
Interrupt. Wenn dein Quarz also 3684000 Schwingungen in der Sekunde
macht und du einen Vorteiler von 1 benutzen würdest, dann würde
der 8-Bit Zähler in einer Sekunde 3684000 / 256 Überläufe produzieren.
Das sind 14390.625 Überläufe pro Sekunde.
Timer1 Prescaler /8, OCR1A auf 4605, dann haste einen
Output-Compare-Interrupt (im CTC-Mode) alle 100dstel Sekunden. Variablen
zählen im INT. Besser wäre es, einen 'geraden' Quarz zu wählen (8 oder
16 MHz), da teilt sich's leichter!
> hm kannst den Rechenweg kurz erklären?
Ist doch simpel:
Der Vorteiler sagt dir wieviele Takte vergehen müssen, damit
der Zähler um 1 hochzählt. Klar?
Also: Wenn dein Quarz 3864000 Takte in der Sekunde generiert,
wie weit zählt der dann in 1 Sekunde mit einem Vorteiler von 64?
Offensichtlich bis 3864000 / 64 -> 57562.5
Ziel ist es wieder sich an den Overflow zu klemmen. Wann tritt
der ein? Na wenn der Zähler überläuft. Und da es sich um einen 16
Bit Zähler handelt, kommt der Überlauf bei 65536.
Also: Bei welchem Wert musst du den Timer loslaufen lassen, damit
nach genau 57562.5 Zählvorgängen der Wert von 65536 erreicht wird?
Der Startwert muss offensichtlich 65536 - 57562.5, also 7973.5
sein. Denn wenn der Timer dann 57562.5 mal getickt hat, ist der
gewünschte Wert von 65536 erreicht und er generiert einen Overflow.
Was für dich heist: 1 Sekunde ist vergangen.
@karl heinz:
ist ja theoretisch richtig, aber wie lässt du den Timer einen halben
Takt zählen? Der Teilerfaktor muss immer ohne Nachkommaanteil passen!
Alles ist zwar ok was hier gesagt wird aber wenn du Dattenblatt genau
studiert hättest dann wärest du wahrscheinlich REAL TIME CKLOCK gesehn.
The clock source for Timer/Counter2 is named clkT2S. clkT2S is by
default connected to
the main system I/O clock clkI/O. By setting the AS2 bit in ASSR,
Timer/Counter2 is
asynchronously clocked from the TOSC1 pin. This enables use of
Timer/Counter2 as a
Real Time Counter (RTC). When AS2 is set, pins TOSC1 and TOSC2 are
disconnected
from Port B. A crystal can then be connected between the TOSC1 and TOSC2
pins to
serve as an independent clock source for Timer/Counter2. The Oscillator
is optimized
for use with a 32.768 kHz crystal. Applying an external clock source to
TOSC1 is not
recommended.
For Timer/Counter2, the possible prescaled selections are: clkT2S/8,
clkT2S/32, clkT2S/64,
clkT2S/128, clkT2S/256, and clkT2S/1024. Additionally, clkT2S as well as
0 (stop) may be
selected.
Ausserdem egal wie erfahren du bist du muss das Datenblatt lesen. Es
giebt keine fertige Lösungen.
Das mit dem externen Uhrenquarz ist wegen ungenauer Quarze mit Vorsicht
zu geniessen! Der produziert natürlich am Timer 2 jede Sekunde einen
Überlauf, aber wie gesagt, hatte damit schon erhebliche Ungenauigkeiten
drin!
ohje klappt noch nicht so wirklich, ist das so richtig:
int sek = 0;
TIMSK |= (1 << 0); // Timer/Counter0 Interrupt Aktivieren
TCCR0 |= (1 << 2);; // Prescaler auf 256 Einstellen
if (bit_is_set(TIFR,0) ) { // Prüfen ob Ein Überlauf Vorliegt
sek++;
PrintInt(sek);
uart_puts("\r\n");
}
so ich bekomme nun schon einen sekunden takt hin, jedoch habe ich
vermutlich einen Fehler im Programm, denn die erste Sec zahl die er mir
ausgibt fängt immer bei rund 600 an, normal müsste doch bei 0 anfangen?
// Timer Initialisieren
if (bit_is_clear(TIMSK,0)) { // Timer/Counter0 Interrupt
TIMSK |= (1 << 0);
}
if (bit_is_clear(TCCR0,2)) { // Prescaler auf 8 Einstellen
TCCR0 |= (1 << 2);
}
int count, sec;
if (bit_is_set(TIFR,0) ) { // Prüfen ob Ein Überlauf Vorliegt
count++;
}
if (count == 14400) {
sec++;
PrintInt(sec);
uart_puts("\r\n");
}
// Uhr Ende
Man Sonic was redes du denn da, Quarz so viel fehler wo hast du denn
Quarz gekauft ich glaube du hast in selber gebastelt. Wenn du den
externen Quarz als ungenau bezwéichnst was sagst du dann zu dem internen
Quarz vergleich mal die Datenblätter befor du hier ein unsinn
verbereitst. Mensch.
Ich denke mal hier geht es in erster Linie nicht darum eine
exakte Uhr zu bauen. Hier geht es in erster Linie darum
programmieren zu lernen bzw. den Umgang mit dem Timer zu
üben.
> denn die erste Sec zahl die er mir> ausgibt fängt immer bei rund 600 an
Verfolg mal nach, was den der Startwert der Variable Sec ist.
Es bringt nichts Programmteile zu posten, die sich,
ausser der Erhöhung von Sec, nicht mit Sec befassen.
> @karl heinz:> ist ja theoretisch richtig, aber wie lässt du den Timer einen halben> Takt zählen? Der Teilerfaktor muss immer ohne Nachkommaanteil passen!
Indem ich ihn abwechseln einmal um 1 zu hoch und das nächste mal
um 1 zu tief zählen lasse. Gemittelt hat er dann einen halben
Takt gezählt :-)
Im übrigen ist der ganze Weg auch theoretisch nicht richtig, da
da einige Takte unter den Tisch fallen. Kein Mensch würde das
bei einer richtigen Uhr mit einem Overflow lösen sondern würde
auf den CTC ausweichen. Aber darum gehts im Moment noch nicht
(zumindest mir nicht). Walter muss jetzt erst mal in die Gänge
kommen.
Karl heinz Buchegger wrote:
> Ich denke mal hier geht es in erster Linie nicht darum eine> exakte Uhr zu bauen. Hier geht es in erster Linie darum> programmieren zu lernen bzw. den Umgang mit dem Timer zu> üben.>>> denn die erste Sec zahl die er mir>> ausgibt fängt immer bei rund 600 an>> Verfolg mal nach, was den der Startwert der Variable Sec ist.> Es bringt nichts Programmteile zu posten, die sich,> ausser der Erhöhung von Sec, nicht mit Sec befassen.
Sorry. Hab ich übersehen. Da haben wirs ja:
if (bit_is_clear(TCCR0,2)) { // Prescaler auf 8 Einstellen
TCCR0 |= (1 << 2);
}
int count, sec;
Wenn eine Variable zur Welt kommt, hat sie irgendeinen Wert,
der muss noch nicht mal gültig sein (zb. im Falle von double).
Dein sec enthält also irgendwas zufälliges. Wenn du willst, dass
das mit 0 loslegst, musst du sec schon initialisieren:
int cout, sec = 0;
Wenn alle ihr uhrenprogramm hier reinstellen, dann werd ichs auch mal
machen! G
Ist in bascom, rechnet wochentage, schaltjahre etc, berechnung erfolgt
im hauptprogramm, wen ein status-bit gesetzt wurde. bis jetzt noch nicht
in reeller hardware getestet, allerdings.
zum berechnen der timer benutze ich das programm RNAVR (einfach mal
googlen).da gibst du einfach taktfrequenz und interrupt frequenz an, und
du bekommst die werte angezeigt. genau das richtige für den faulen,
grins
@ GISMO:
diese Erkenntnisse habe ich aus der Praxis! Ein mehrfach geteilter
(MHz-Bereich)-Quarz ist entsprechend genauer und temperaturstabiler,
wegen der Masse des Quarzes als ein kHz-Quarz, der nicht geteilt wird.
Probier doch einfach mal ein paar aus, nicht nur drauf verlassen was im
Datenblatt steht!
Was soll ich Probieren, nichts ist Perfekt. Ausserdem ich benutze ein
Real Time Counter seit 2000, wenn du ganz genauers nehmen willst dann
nehm doch eine Atomuhr, geht auch ebenfalls falsch. Vielleicht solte man
auch ein Atomuhr Temperatur kompensation verpassen.
ist denn der aufwand ewig mit quarzen rumzuspielen gerechtfertigt?
also im zeitalter von dcf kann man doch einmal am tag, oder pro woche
einfach abgleichen, oder?
> Wenn du den externen Quarz als ungenau bezwéichnst
Externe Quarze sind natürlich genauso ungenau. Auch ein Uhrenquarz
ist nicht absolut genau. Deswegen verbaut man unter anderem ja
auch Kondensatoren um den Quarz in seiner Frequenz noch ziehen
zu können. Jeder Uhrmacher gleicht den Quarz einer Uhr auf die
Sollfrequenz ab.
> was sagst du dann zu dem internen Quarz
Welcher interner Quarz?
In einem AVR ist kein 'interner Quarz' eingebaut. Das sind ganz
normale R-C Schwingkreise.
Sebastian Heyn wrote:
> zum berechnen der timer benutze ich das programm RNAVR (einfach mal> googlen).da gibst du einfach taktfrequenz und interrupt frequenz an, und> du bekommst die werte angezeigt. genau das richtige für den faulen,> grins
Dann mußt Du aber noch die Werte ins Programm eintippen, wäre mir viel
zuviel Arbeit.
Ich bin noch fauler, ich trag einfach die Formel ein und laß das Rechnen
den Präprozessor machen.
Bei einem anderen Quarz, schreib ich dann nur die neue Quarzfrequenz
hin, laß es neu compilieren und gut is.
Peter
so jetzt zählt er mir die Überläufe, jedoch viel zu langsam, nach ein
paar minuten habe ich 1000 überläufe das kann doch nicht sein, was mach
ich denn blos Falsch?
// Timer Initialisieren
if (bit_is_clear(TIMSK,0)) { // Timer/Counter0 Interrupt
TIMSK |= (1 << 0);
}
if (bit_is_clear(TCCR0,2)) { // Prescaler auf 8 Einstellen
TCCR0 |= (1 << 2);
}
if (bit_is_set(TIFR,0) ) { // Prüfen ob Ein Überlauf Vorliegt
sek++;
}
uart_puts("Count:");
PrintInt(count);
uart_puts("\r\n");
uart_puts("Sec:");
PrintInt(sec);
uart_puts("\r\n");
// Uhr Ende
Die Abfragen ob das Bit gelöscht ist um es dann zu setzen
kannst du dir sparen. Es ist wesentlich einfacher das
Bit immer zu setzen, egal ob es schon gesetzt ist oder nicht.
Nun, du aktivierst den Timer-Interrupt hast aber keinen
Interrupt Handler. Den Timer Interrupt zu benutzen ist eine
gute Idee. Was hingegen schlecht ist, ist die Abfrage
ob das Overflow Bit in TIFR gesetzt wird. Ein Interrupt
Handler würde ganz einfach aufgerufen werden und
gut ists.
Das könnte so aussehen:
ähhm
i würde keine timer nehmen. denn wenn du eine sekunde mit dem timer
auszählst und dann das auf nen lcd oder sonstigem anzeigen willst, wirst
du jede sekunde verfälschen um den faktor der lcd ansteuerung.
schreib deinen code für die uhr und dann leg warte schleifen ein damit
du eine sekunde kriegst.
viel genauer und super leicht zu berechnen.
gruss
fubu1000 wrote:
> i würde keine timer nehmen. denn wenn du eine sekunde mit dem timer> auszählst und dann das auf nen lcd oder sonstigem anzeigen willst, wirst> du jede sekunde verfälschen um den faktor der lcd ansteuerung.
Nö !
Das ist ja gerade der Witz an nem Timer, daß er in Hardware läuft.
Irgendwelche Softwareausführunszeiten kümmern ihn in keinster Weise.
Ein Timer ist immer auf den Zyklus genau.
> schreib deinen code für die uhr und dann leg warte schleifen ein damit> du eine sekunde kriegst.
Gratulation !
Das ist die absolut richtige Methode, um total ungenau zu werden.
Warteschleifen sind Software und damit völlig Programm- und
Compilierungsabhängig.
Warum willst Du nen Anfänger verarschen ?
Was hat er Dir getan ?
Peter
Also ich wollte mir auch eine Software Uhr basteln.
Welchen Takt sollte ich denn jetzt dafür verwenden?
Den internen oder ist doch besser meinen 4MHZ Oszillator über XTAL1?
Es gibt ja auch noch die Möglichkeit einen Oszillator zwischen XTAL1 und
XTAL2 zu schalten?
Also, welches ist auf Dauer gesehen die Beste Lösung?
Das Ganze möchte ich unter BASCOM zum Laufen kriegen. Ich verwende
hierfür doch einen Timerinterrupt um mir ein Sekunden Signal zu schaffen
oder?
Es gibt dort ja auch die vorgefertigte WAIT 1-Anweisung. Ist die Genau?
DANKE schon einmal für die ANTWORTEN.
die wait 1 anweisung ist total nutzlos, weil dein programm, also die
zeit berechnen ja auch x zeit benötigt. deshalb wirst du pro sekunde
immer ungenauer. ich hatte oben mal ein bascom beispiel gepostet für
eine uhr. (rtc.bas)
> Also ich wollte mir auch eine Software Uhr basteln.> Welchen Takt sollte ich denn jetzt dafür verwenden?
Der interne ist sehr ungenau und diversen Schwankungen unterworfen
(Versorgungsspannung, Temperatur). Nimm einen normalen Quarz (sonic
meint, spezielle 32kHz Uhrenquarze sind zu ungenau) zw. XTAL1 und XTAL2.
Meine Uhr lief anfangs mit 7,3728MHz und auf 24 Stunden hatte ich eine
Sekunde Abweichung von der normalen Zeit.
Hi nochmal, wenn du Wert auf eine genaue Uhr legst, ist es das Beste
einen 'geraden' Quarz zu verwenden, z.B. 4, 8 oder 16 MHz. Dieser lässt
sich per Output-Compare-Mode (mit CTC-Mode) genau auf 1 Sekunde
runterteilen. Nun hast du einen Interrupt, der genau jede Sekunde
ausgelöst wird, unabhängig vom restlichen Programm. Immer dran denken:
beim µC wird ab 0 gezählt, also ist der Wert für z.B. OCRA1 1999 wenn er
bei Zählerstand 2000 auslösen soll!
Wenn die Baudrate genau sein soll ist natürlich z.B. ein 7,3728MHz -
Quarz besser, die Uhr dafür schwieriger zu realisieren.
> Wenn die Baudrate genau sein soll ist natürlich z.B. ein 7,3728MHz -> Quarz besser, die Uhr dafür schwieriger zu realisieren.
Warum? Prescaler des Timers z. B. auf 8 gesetzt,
Timer-Overflow-Interrupt aktivieren und in der ISR ein (unisgned int)
bei jedem Interrupt hochzählen. Wenn dieser Wert 3600 ist, ist genau
eine Sekunde rum. Oder vertue ich ich da gerade?
Du liegst mit den 3600 richtig, das wären 3600Hz, also 277.77(irgendwas)
µs. Zeit ist 1/Frequenz, unbedingt Berücksichtigen!
Du kannst sehr wohl auf 3600 zählen, Ist aber wie schon gesagt,
Programmäßig schwieriger zu realisieren. Bei einem geraden Quarz kannst
du die Uhr bequem in der Interrupt-Routine unterbringen und hast 1s Zeit
für den Rest des Programmes, wobei bei deiner Version der 'normale'
Programmablauf alle 277...µs unterbrochen wird.
Quarzungenauigkeiten kann man nichr 'rausrechnen, nur messen und
entsprechen kompensieren. Jedenfalls gilt: je höher die Quarzfrequenz
und je größer der Teiler, desto kleiner der Fehler.
> ähhm> i würde keine timer nehmen. denn wenn du eine sekunde mit dem timer> auszählst und dann das auf nen lcd oder sonstigem anzeigen willst, wirst> du jede sekunde verfälschen um den faktor der lcd ansteuerung.
Weist du.
Wenn du dich darüber mokiert hättest, dass das Ganze am Overflow
Interrupt aufsetzt, anstatt am CTC, hätte ich das ja noch verstanden.
Ich hab ihm den Overflow eingeredet, damit er mal anfängt sich mit
Timern zu beschäftigen. Der Overflow Interrupt ist besser als nichts,
aber der CTC ist das Mittel mit dem man das machen würde.
> schreib deinen code für die uhr und dann leg warte schleifen ein damit> du eine sekunde kriegst.> viel genauer und super leicht zu berechnen.
Das allerdings geht genau in die falsche Richtung. Mit Warteschleifen
kriegst du keine halbwegs genaue, langzeitstabile Uhr hin. Selbst
die Uhr mit Overflow-Interrupt ist deinen Warteschleifen haushoch
überlegen.