Hallo Leute,
habe heute den ganzen So. verbracht mich in den Timer1 einzulesen.
Da ich noch ein Anfänger bin, brauche ich eure Hilfe.
Die Suche habe ich auch bemüht aber zu keinem Ergebnis gekommen.
Arbeite mit einem atmega32 der mit 16 MHz getaktet wird.
Versuche mit C zu programmieren.
Mein Vorhaben ist dass ich eine Uhr programmieren möchte.
Dazu will ich den Timer1 nützen der im CTC- Betrieb läuft.
Soviel zu der Rechnerei: 16000000/1024=15625
so jetzt haben wir 15625 Takte pro Sekunde
Jetzt soll der Timer bis 15624 zählen und dann ein Überlauf auslösen was
ein Interrupt auslöst.
Mein Code:
//Initialisierung von TIMER1
TCCR1B |= (1 << CS12 | 1 << WGM12 | 1 << CS10);
TCCR1A = 0b00000000;
TIMSK |= (1 << OCIE1A);
OCR1A = 15624;
//Globale Interrupts freischalten
sei();
//Timer1 Interrupt
ISR (TIMER1_OVF_vect)
{
if(sek>58)
{
sek=0;
}
else
{
sek = sek + 1;
}
if(sek==0)
{
min = min + 1;
}
if(min>59)
{
st = st + 1;
}
}
Wäre nett wenn mir einer sagt wo mein Denkfehler liegt.
Wenn Du schon im CTC-Modus arbeitest, dann solltest Du auch den
Compare-Interrupt benutzen und nicht den Overflow-Interrupt...
EDIT:
Schau Dir im Datenblatt mal in der Tabelle an, wann das TOV1-Flag (das
den Overflow-Interrupt auslöst) im CTC-Modus gesetzt wird, nämlich beim
Erreichen von MAX (also dem maximalen Zählwert von 65535). Der wird aber
nie erreicht. In diesem Fall geht es also nur mit dem Compare-Interrupt
A.
Dein Timer dürfte - von Dir unbemerkt - wie am Schnürchen laufen. Nur
der Overflow-Interrupt wird nie ausgelöst. Erstens weil Du ihn nicht
enabled hast, zweitens, weil der Zähler in Deiner Konfiguration
(CTC-Modus) nie den Stand 65535 erreicht und dann noch eins weiterzählt.
Schreib also die Zeile
ISR (TIMER1_OVF_vect)
um auf den Output-Compare-A-Interrupt und alles sollte sofort tun wie
gewünscht.
keine gute Idee. Die SIGNAL Schreibweise ist veraltet. In
einer der nächsten Compilerversionen wird sie komplett
aussterben. Es gibt keinen Grund mehr, diese Schreibweise
zu lehren oder vorzuschlagen.
@ Karl heinz:
Wo iss'n eigentlich der Unterschied?
Dachte immer, dass beim Verlassen der Routine das I-Flag mal gesetzt
wird, mal nicht ('ret' und 'reti').
Liege ich da total falsch?
Max wrote:
>>ISR (TIMER1_OVF_vect)>> wie jetzt, das ist doch nicht richtig oder??>> Das ist doch der Überlauf....
Genau. Das ist nicht richtig. Der Timer geht nicht
in einen Überlauf, sondern in einen Compare Match
ABer der Compare Match den du haben willst heist
TIMER1_COMPA_vect
(weil es 2 Compare Einheiten gibt. A und B)
und nicht
TIMER1_COMP1_vect
ISR( TIMER1_COMPA_vect )
{
...
}
Thilo M. wrote:
> @ Karl heinz:> Wo iss'n eigentlich der Unterschied?> Dachte immer, dass beim Verlassen der Routine das I-Flag mal gesetzt> wird, mal nicht ('ret' und 'reti').> Liege ich da total falsch?
Ja.
Prinzipiell besteht funktional kein Unterschied zwischen beiden
Schreibweisen. Es ist nur so, dass bei SIGNAL die Interrupt
Vektoren eigenwillige Namen bekommen haben. Irgendwann hat man
beschlossen, den Vektornamen immer aus dem Namen im Atmel-
Datenblatt mit einem angehängten _vect zu bilden.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Veraltete_Funktionen_zur_Deklaration_von_Interrupt-Routinen
>ISR( TIMER1_COMPA_vect )>{> ...>}
Hat jetzt auch funktioniert, danke für die schnelle Hilfe.
nach 4 Min habe ich noch keine Abweichung.
Wie zuverlässig ist der Externe Quarz???
Kommt mit der Zeit eine Abweichung rein???
Max wrote:
>>ISR( TIMER1_COMPA_vect )>>{>> ...>>}>> Hat jetzt auch funktioniert, danke für die schnelle Hilfe.>> nach 4 Min habe ich noch keine Abweichung.>> Wie zuverlässig ist der Externe Quarz???> Kommt mit der Zeit eine Abweichung rein???
Wahrscheinlich.
Kann aber durchaus sein, dass du erst morgen Abend eine Abweichung
von 1 Sekunde siehst.
Also: Lass mal laufen und sieh in 1 Stunde noch mal nach.
Wenn die Abweichung noch nicht sehr gross ist, dann lass die
Uhr bis morgen abend laufen. Stell die Abweichung in 24 Stunden
fest und rechne daraus die tatsächliche Quarz-Frequenz aus.
> OCR1A = 15624;
Du musst noch ein Zähler deines errechneten Wertes abziehen. Dann ist es
Korrekt. (OCR1A = 15623); Die Uhr wird zwar immernoch nicht 100%ig genau
sein, aber die Abweichung ist minimal.
Es gibt einen Weg, die Ganggenauigkeit zu erhöhen, nämlich in dem man
einen Kondensator im Schwingkreis durch ein Drehko ersetzt und mit einem
Frequenzzähler den Quarz eicht. Allerdings darf man mit der Prüfspitze
des Frequenzzählers nicht direkt am Schwingkreis messen, da dieser
Messstrom das Ergebnis des Schwingkreises verfälschen würde....
Man schreibt ein kleinen "Eichcode", der einfach nur einen Portpin so
schnell wie möglich high-low schaltet; natürlich im Zusammenhang mit
einem Timer, der die Quarzperioden zählt. Mit dem Drehko kann man dann
die Schwingfrequenz des Quarzes leicht ändern. Die Prüfspitze des
Frequenzzählers ist an den Portpin anzulegen und mit Hilfe des Drehkos
auf einen errechneten Wert einzustellen.
Mit dieser Methode erreicht man Ganggenauigkeiten, die etwa eine Sekunde
pro Jahr deutlich unterschreiten.
Bitte beachten: manchmal verändert schon die blosse Berührung der
elektronischen Bauteile die Schwingfrequenz. Daher sind die
Messergebnisse nur dann genau, wenn weder Dreko noch Quarz berührt
werden.
Bei der Wahl der Bauteile kann man noch eine etwas unautodoxe
Daumenregel anwenden: je grösser das Gehäuse, desto höher die
wahrscheinlichkeit, daß sie Temperaturstabiler arbeiten.
@ Niels:
15624 ist schon korrekt! (0 .. 15624 => 15625 Schritte)
Und Eichen tut das Eichamt. ;)
Du meinst 'Justieren', das genaue Messen ist 'Kalibrieren'.
Sorry wegen der Haarspalterei.
Thilo M. wrote:
> @ Niels:> 15624 ist schon korrekt! (0 .. 15624 => 15625 Schritte)
Ich hätte gestern nicht soviel saufen sollen..
Sorry, 15624 ist natürlich korrekt.
>Wie zuverlässig ist der Externe Quarz???>Kommt mit der Zeit eine Abweichung rein???
Schau doch im Datenblatt Deines Quarzes nach. Da stehen die
Genauigkeiten drin. Bei guten Standardquarzen beträgt sie grob 10 ppm =
10^-5 (ppm = parts per million = 10^-6).
Und jetzt rechnen: Ein Tag hat 24 60 60 s = 86400 s. Das
multipliziert mit 10^-5 liefert 0.864 s. Ergebnisa also: Pro Tag kannst
Du eine Abweichung von ungefähr knapp einer Sekunde erwarten.
Oder wie Niels schrieb,
Drehkondensator, um den Quarz auf die exakte Frequenz zu 'ziehen' und
bei konstanter Temperatur betreiben, dann sollte die Abweichung minimal
bleiben.
>und bei konstanter Temperatur betreiben, dann sollte die Abweichung minimal>bleiben.
Dann bleibt nur noch die alterungsbedingte Frequenzdrift des Quarzes
übrig (keine Ahnung wie groß die ist).
OK, ich werde mal sehen wie es läuft...
Habe noch eine Frage zu dem Timer1: der Timer soll jetzt ein Interrupt
bei
15625 Takten auslösen.
Ich lege jetzt im OCR1A die Obergrenze wann es so weit ist.
Kann ich dem Timer auch sagen ab wann er anfangen soll und dann mit dem
Überlauf arbeiten?
Ich könnte mir vorstellen dass man ein Wert im Interrupt in den
Datenregister (TCNT1) rein schreibt ab wann er weiter laufen soll.
Macht man sowas? Oder welche Möglichkeiten gibt es noch?
Gruß
Max
Max wrote:
> Kann ich dem Timer auch sagen ab wann er anfangen soll und dann mit dem> Überlauf arbeiten?
Diese Methode nennt sich "autoreload" und wird von der ATmega-serie
nicht unterstützt. Man kann zwar ein soetwas Softwaremässig nachbilden,
aber das ist dann nicht mehr so genau. Meiner Meinung nach gibt es dafür
aber auch keinen Grund, weil CTC im Prinzip das selbe macht.
Wenn du mit Autoreload arbeiten möchtest, müsstest du in die
80C51-kompatible Welt umsteigen. :)
Max wrote:
> Kann ich dem Timer auch sagen ab wann er anfangen soll und dann mit dem> Überlauf arbeiten?
Im Prinzip kannst du. Allerdings musst du dann in der ISR den
Timer wieder neu setzen. Und genau hier liegt der Haken.
Du kannst nicht mit 100% Sicherheit sagen, wieviele Takte
von der Auslösung des Interrupts bis zum Neusetzen des
Timers vegehen. Hängt ja unter anderem auch davon ab,
bei welchem Befehl der Interrupt auftritt. Der Befehl wird
ja noch in jedem Fall vollständig abgearbeitet. Nun gibt es
aber Befehle die 1 Takt dauern und es gibt Befehle die 2 Takte
dauern.
>> Ich könnte mir vorstellen dass man ein Wert im Interrupt in den> Datenregister (TCNT1) rein schreibt ab wann er weiter laufen soll.>> Macht man sowas? Oder welche Möglichkeiten gibt es noch?
Ja. macht man auch. Aber wenns wirklich auf den einzelnen
Takt genau sein muss, dann ist CTC das Beste was du kriegen
kannst.
@Max
Übrigens wirst du deine Uhr nicht mit maximaler Genauigkeit
einstellen können. Der Grund dafür ist, dass du einen
Vorteiler von 1024 benutzt.
Nehmen wir mal an, du bekommst durch nachmessen heraus, dass
dein Quarz in einem Tag um 512 Schwingungen zuviel macht.
Was tust du?
Benutzt du weiterhin 15624 als Endwert, dann geht deine Uhr
zu schnell. Benutzt du 15625 dann geht die Uhr zu langsam.
http://www.mikrocontroller.net/articles/AVR_-_Die_genaue_Sekunde_/_RTC
Der Dude wrote:
> Da träumst Du aber, junger Freund.
Natürlich spreche ich hier nicht von einem 32.768Khz-Uhrenquarz im 0,2mm
Gehäuse.
Nein, ich hatte mal beruflich mit der Justage von Quarzen zur
Zeitmessung zu tun. Wenn die Schaltung an einem einigermaßen
temperaturstabilen Umgebung gelagert wird und so wenig wie möglich
bewegt wird, funktioniert das!
Es gibt lediglich ein paar oben bereits erwähnte Dinge, die bei der
Justage zu beachten sind. Aber diese Methode hat sich bereits mehrfach
für mich bewährt. Die Ganggenauigkeit, die man mit hochfrequenten
Quarzen erreichen kann ist wirklich sagenhaft.