Timer funktioniert nicht 16-Bit CTC

#758917
Lesenswert?

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.
#758940
Lesenswert?

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.
#758956
Lesenswert?

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.
Gast #759006
Lesenswert?

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
#759026
Lesenswert?

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 #759107
Lesenswert?

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 #759208
Lesenswert?

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).
#759216
Lesenswert?

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).
#759322
Lesenswert?

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 #759362
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren