Forum: Mikrocontroller und Digitale Elektronik Bekomme den Teimer1 nicht ans laufen


von Max (Gast)


Lesenswert?

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.

von Johannes M. (johnny-m)


Lesenswert?

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.

von Max (Gast)


Lesenswert?

meinst du so???

ISR (TIMER1_COMP1_vect)
{
....
}

von AVRFan (Gast)


Lesenswert?

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.

von Max (Gast)


Lesenswert?

Habe es gerade ausprobiert, geht aber nicht.

von Thilo M. (Gast)


Lesenswert?

Probier's mal so:
1
SIGNAL (SIG_OUTPUT_COMPARE1A)
2
{
3
 ...
4
}

von Thilo M. (Gast)


Lesenswert?

Ach ja..
1
#include <avr/Interrupt.h>
nicht vergessen einzubinden. ;)

von Karl H. (kbuchegg)


Lesenswert?

Thilo M. wrote:
> Probier's mal so:
>
1
> SIGNAL (SIG_OUTPUT_COMPARE1A)
2
> {
3
>  ...
4
> }
5
>


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.

von Max (Gast)


Lesenswert?

>ISR (TIMER1_OVF_vect)

wie jetzt, das ist doch nicht richtig oder??

Das ist doch der Überlauf....

von Thilo M. (Gast)


Lesenswert?

@  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?

von Karl H. (kbuchegg)


Lesenswert?

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 )
{
  ...
}

von Max (Gast)


Lesenswert?

der Vorschlag hat jetzt funktioniert.
>SIGNAL (SIG_OUTPUT_COMPARE1A)
>{
> ...
>}

Wie ist es jetzt richtig?
Wenn "Signal" veraltet ist?

von Karl H. (kbuchegg)


Lesenswert?

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

von AVRFan (Gast)


Lesenswert?

ISR( TIMER1_COMPA_vect )
{
  ...
}

ist richtig.

von Thilo M. (Gast)


Lesenswert?

Macht Sinn! ;)
Habe schon länger nicht mehr im Tutorial gestöbert.

von Max (Gast)


Lesenswert?

>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???

von Karl H. (kbuchegg)


Lesenswert?

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.

von Niels H. (monarch35)


Lesenswert?

> 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.

von Thilo M. (Gast)


Lesenswert?

@ 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.

von Niels H. (monarch35)


Lesenswert?

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.

von AVRFan (Gast)


Lesenswert?

>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.

von Thilo M. (Gast)


Lesenswert?

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.

von AVRFan (Gast)


Lesenswert?

>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).

von Max (Gast)


Lesenswert?

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

von Thilo M. (Gast)


Lesenswert?

>Kann ich dem Timer auch sagen ab wann er anfangen soll

Na klar.
Da steht dir Tür und Tor offen.

von Niels H. (monarch35)


Lesenswert?

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.  :)

von Karl H. (kbuchegg)


Lesenswert?

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.

von Der Dude (Gast)


Lesenswert?

>Mit dieser Methode erreicht man Ganggenauigkeiten, die etwa eine Sekunde
>pro Jahr deutlich unterschreiten.

Da träumst Du aber, junger Freund.

von Karl H. (kbuchegg)


Lesenswert?

@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

von Niels H. (monarch35)


Lesenswert?

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.

von Max (Gast)


Lesenswert?

>http://www.mikrocontroller.net/articles/AVR_-_Die_...

OK, danke werde es mir morgen durchlesen

Jetzt gehts aber ins Bett, morgen geht es wieder in die Schule.

Nochmal DANKE an ALLE für die Hilfe.

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
Noch kein Account? Hier anmelden.