Timer funktioniert nicht 16-Bit CTC

OP #758917
hi,
ich probiere gerade einen Timer für ein anderes Projekt zum laufen zu 
bringen. Ich verwende einen Atmega162 mit 7372800 Hz. Nur der Code 
springt nicht in die Interrupt Routine. Hier mal die relevanten stellen:
1
int ms;
2
uint8_t s;
3
uint8_t min;
4

5
//Timer1 Compare Match Interrupt
6
ISR(TIMER1_COMPA_vect)
7
{
8
  //Milli Sekunden um 1 erhöhen
9
  ms++;
10
  //sind 1000 ms um?
11
  if (ms==1000) {
12
    //ms zurücksetzen und Sekunden erhöhen
13
    ms=0;
14
    s++;
15
    //sind 60 Sekunden um?
16
    if (s==60) {
17
      //Sekunden zurück setzen und Minuten erhöhen
18
      s=0;
19
      min++;
20
    }    
21
  }
22
}
23

24
.
25
.
26
.
27

28
//In main():
29
  //CTC Modus & Vorteiler 8
30
  TCCR1B |= (1<<CS11)|(1<<WGM12);
31
  //Interrupt bei Compare Match
32
  TIMSK = (1<<OCIE1A);
33
  //Compare Wert setzen
34
  OCR1A = 9216-1;

der Timer soll jeder ms nen Interrupt auslösen, und die Variable ms 
hochzählen.
Hast du interrupt.h includet?
Woher weist du eigentlich, das der Interrupt nicht
angesprungen wird?
Warum sind s und min nicht volatile? Die werden ja doch wahrscheinlich
von der Hauptschleife her ausgelesen?
usw. usw.

Poste doch bitte das komplette Programm!
Dann  brauchen wir nicht jedes Fitzelchen Code nachzufragen.
Nimm einfach dein *.c und hänge es als Attachment an.
Das ist erstens für dich viel einfacher und zweitens kann
dann keine Information fehlen.
OP
der Code ist hier drin:
http://www.mikrocontroller.net/attachment/highlight/30489

Ich habe den Code auch mal auf einem Mega32 getestet mit 16 Mhz:
1
int main(void) {
2
  
3
  //CTC Modus & Vorteiler 8
4
  TCCR1B |= (1<<CS11)|(1<<WGM12);
5
  //Interrupt bei Compare Match
6
  TIMSK = (1<<OCIE1A);
7
  //Compare Wert setzen
8
  OCR1A = 20000-1;
9
  
10
  sei();

und eine Sekunde ist nach ca. 8 Sekunden um. Also es funktioniert doch. 
Nur zu langsam.
Dann läuft Dein Controller vermutlich nicht mit 7,... MHz sondern mit 1 
MHz. Dann musst Du vermutlich die Fusebits entsprechend ändern, dass 
der Controller auch weiß, dass er mit dem Quarz laufen soll und nicht 
mit dem internen RC-Oszillator.
Gast
Warum lässt du nicht den Compiler rechnen - der kann das ja ganz gut ;) 
:
1
OCR1A = F_CPU /8 /1000;
2
/*                ^- 1ms -> 1kHz
3
               ^- Prescaler
4
        ^- Takt 
5
ODER (exakt dasselbe):
6
OCR1A = F_CPU / 8 * 0.001 // [Hz] / [1] *[s]...
7
*/
8
//...

hth. Jörg

ps.: ja, du hast dich verrechnet, 1 Millisekunde ist 0.001s
Marian wrote:
> Nein, ne Millisekunde sind 10e-4 Sekunden, also 1/1000. 1e-3 ist auch
> eine Millisekunde^^ :)
Doch, eine Millisekunde sind 10^-3 Sekunden, und das sind 0,001 
(Grundschule: Man nehme eine 1 und schiebe das Komma um 3 Stellen nach 
links...). 10^-4 (oder 1e-4 wie manche es lieber schreiben) sind 
logischerweise 0,1 ms...

EDIT: OK, 10e-4 sind natürlich 1e-3... Das ist natürlich ein völliges 
Durcheinander.
Gast
Eine Möglichkeit wäre, den Timer ohne Prescaler laufen zu lassen, und 
den Compare-Match-Wert auf 36864 zu setzen.  Das liefert genau 5 
Interrupts pro ms.  Um von den 0.2 ms zu den ganzen Millisekunden zu 
kommen, schachtelst Du den Code im Interupthandler einfach in einen 
1:5-Software-Frequenzteiler ein, so wie Du es schon bei den ms und s 
praktiziert hast.

Während 0.2 ms kann Dein Controller immer noch soviele Instruktionen 
abarbeiten (ihm stehen ja 36864 Zyklen zur Verfügung), dass Du keine 
Überforderung befürchten musst.
Gast
Ich hab mich mit den Zahlenwerten verhaspelt. Sorry!

Richtig ist:

7372800 Hz / 36864 = 200 Hz --> 5 ms Interruptintervall.

Das ist das kleinstmögliche dezimalsystemkompatible Intervall. Auf 1 ms 
kommst Du nicht (lies: nicht ohne "Tricks"), weil 36864 nicht durch 5 
teilbar ist.  Für 1 ms Compare-Match-Interrupt-Intervall hat Dein Quarz 
mit 7.372800 MHz einen zu krummen Wert.

OCR1A musst Du tatsächlich mit 36863 laden, wenn Du alle 36864 Zyklen 
einen Überlauf wünschst (gilt nur bei Prescaler = 1).
Gibt es überhaupt einen triftigen Grund für die Verwendung eines 
Baudratenquarzes? Das beschriebene Problem ist nämlich der gewaltige 
Nachteil von solchen Quarzen. Die haben nunmal Frequenzen, die ein 
Vielfaches von 300 Hz sind. Und alles mit ner "3" drin ist in solchen 
Fällen etwas problematisch. Wenn es irgendwie geht, nimm lieber nen 
Standardquarz (z.B. 8 MHz, damit lassen sich sehr schön ms-Takte 
erzeugen).
Florentin S. wrote:
> Naja ist halt ne rein serielle Anwendung.
Das sagt erstmal gar nichts. Viele übliche Baudraten lassen sich auch 
mit Standardquarzen mit ausreichender bis sehr guter Genauigkeit 
erzeugen. Baudratenquarze brauchts eigentlich nur dann, wenn man 
entweder auf irgendeine bestimmte Baudrate festgelegt ist, die mit 
Standardquarzen nicht generierbar ist oder wenn man flexibel zwischen 
allen üblichen Baudraten wählen können will. Teilnehmer A und Teilnehmer 
B müssen sich nur auf eine Baudrate einigen. Und wenn beide Teilnehmer 
µCs sind, dann braucht man sich nicht mal an die Standard-Baudraten (mit 
300Hz * 2^n) zu halten...
Gast
Sehr vernünftig.  Aber wenn Du wirklich 9 oder 23 oder 161 ms 
quarzpräzise abzählen können willst, darfst Du halt keinen 
Baudratenquarz verwenden.  Ansonsten musst Du entweder eine kleine 
Ungenauigkeit in Kauf nehmen (mit 7373 für den Compare Match [*] 
bekommst Du 7373 / 7372800 Hz = 1.0000271 ms), oder den Fehler 
softwaremäßig korrigieren (Compare Match Wert jedes n-te Mal auf 7372 
herabsetzen, n passend wählen; genaueres in der Codesammlung unter "Die 
genaue Sekunde"), oder Dich mit dem minimal möglichen exakten Zeitraster 
von 5 ms begnügen.

[*] OCR1A dann mit 7372 laden.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 18 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.