Forum: Mikrocontroller und Digitale Elektronik Timer funktioniert nicht 16-Bit CTC


von Flo S. (tuxianer)


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.

von Falk B. (falk)


Lesenswert?

Wo ist sei(); ?

MFG
Falk

von Flo S. (tuxianer)


Lesenswert?

sorry hab ich hier nicht gepostet, ist aber drin!

von Karl H. (kbuchegg)


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.

von Flo S. (tuxianer)


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.

von Johannes M. (johnny-m)


Lesenswert?

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.

von Flo S. (tuxianer)


Lesenswert?

Also der Mega162 läuft ganz sicher mit Ext. Oszi! Beim Mega32 bin ich 
mir auch ziemlich sicher! (Alle CKSEL gesetzt)!

von Flo S. (tuxianer)


Lesenswert?

oder habe ich mich nur verrechnet?

Beim 16 Mhz:

160000/16000000=0.01
   |
160000/8=20000

von Jörg X. (Gast)


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

von Flo S. (tuxianer)


Lesenswert?

Sind ne ms nicht 10^-3 Sekunden?

von Marian (Gast)


Lesenswert?

Nein, ne Millisekunde sind 10e-4 Sekunden, also 1/1000. 1e-3 ist auch 
eine Millisekunde^^ :)

von Flo S. (tuxianer)


Lesenswert?

Stimmt ihr habt natürlich recht blöder Fehler vielen Dank!

von Johannes M. (johnny-m)


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.

von Flo S. (tuxianer)


Lesenswert?

daraus resultiert aber ein neues Problem!...ich komme für eine ms nicht
mehr auf einen ganzzahligen ctc wert.

von Karl H. (kbuchegg)


Lesenswert?

Florentin S. wrote:
> daraus resultiert aber ein neues Problem!...ich komme für eine ms nicht
> mehr auf einen ganzzahligen ctc wert.

Jetzt bist du reif für das hier:
http://www.mikrocontroller.net/articles/AVR_-_Die_genaue_Sekunde_/_RTC

von Flo S. (tuxianer)


Lesenswert?

könnte ich es auch nicht so machen:

7372800/1000/64=115.2

Also sind es alle 5ms eine zuenig...also zähle ich alle 5 eine dazu.

von Flo S. (tuxianer)


Lesenswert?

ne es ist eine zu viel

von AVRFan (Gast)


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.

von Flo S. (tuxianer)


Lesenswert?

bei den 36864 sind da die -1 schon inbegriffen?

von AVRFan (Gast)


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

von Johannes M. (johnny-m)


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

von Flo S. (tuxianer)


Lesenswert?

Naja ist halt ne rein serielle Anwendung.

von Johannes M. (johnny-m)


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

von AVRFan (Gast)


Lesenswert?

>Naja ist halt ne rein serielle Anwendung.

Auch wenn eine Echtzeituhr drin ist? Scherzkeks! :-)

von Flo S. (tuxianer)


Lesenswert?

na die Echtzeit Uhr ist für einen Timeout zuständig und ersetzt die 
Softwarewaits, so das Programm nebenbei noch andere Dinge tun kann.

von AVRFan (Gast)


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.

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.