Forum: Compiler & IDEs Sekundentakt mit Timer erzeugen


von Klaus (Gast)


Lesenswert?

Hallo!


Ich hab gerade Probleme mit meinem Sekundentakt. Ich hab eine 
Interruptroutine, die eigentlich mit genau 1Hz aufgerufen werden sollte. 
Zum Vergleich, hab ich mittels der _delay_ms Funktion ein Blinken einer 
anderen LED in die Hauptschleife geschrieben.


1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU 1000000UL
5
#include <util/delay.h>
6
7
volatile int second = 0;
8
9
void init_timers()
10
{
11
  //Timer 1 auf Sekunden-Takt einstellen
12
        // 1Mhz/(64*15625) = 1 Hz 
13
  OCR1A= 15625;
14
  TIMSK |= (1<<OCIE1A);
15
  TCCR1A = 0x00;
16
  TCCR1B |= (1<<WGM12)|(1<<CS11)|(1<<CS10); // CTC mode; 64 prescale
17
}
18
19
ISR(TIMER1_COMPA_vect)
20
{  
21
  //toggle led
22
  if( PORTB & (1<<LED_SEC) )
23
  {
24
    LED_SEC_ON;
25
  }
26
  else
27
  {
28
    LED_SEC_OFF;
29
  }
30
31
  second++;
32
}
33
34
35
int main()
36
{
37
  init_timers();
38
39
  sei();
40
41
  while (1)
42
  {
43
    LED_MESSURE_ON
44
    _delay_ms(1000);
45
    LED_MESSURE_OFF
46
    _delay_ms(1000);
47
  }
48
}


Theoretisch sollten die LEDs doch fast gleichschnell blinken. (In der 
Hauptschleife ganz minimal langsamer).

Aber leider blinkt die timergesteuerte LED in einer Minute ca. 29 mal. 
Die LED in der Hauptschleife blinkt (ausreichend genau) 30 mal.

Könnte mit jemand ein Fehler im Code zeigen, oder bestätigen, dass der 
so richtig ist? Der ORC1A Wert is doch richtig berechnet, oder? Danke 
schonmal!

P.S.: Der Einfluss der Ungenauigkeit des internen RC-Oszillators sollte 
sich ja auch beide LEDs gleich auswirken und somit keinen Einfluss auf 
die unterschiedliche Blinkgeschwindigkeit haben.

von Oliver (Gast)


Lesenswert?

>Könnte mit jemand ein Fehler im Code zeigen,

Wenn das der ganze Code wäre, vielleicht. Bei deinem gezeigten Code 
dürfte gar nichts blinken, da kein Pin von PORTB jemals auf Ausgang 
geschaltet wird.

>Der ORC1A Wert is doch richtig berechnet, oder?

1Mhz/(64*15625) = 1 Hz ist richtig.

>Aber leider blinkt die timergesteuerte LED in einer Minute ca. 29 mal.
>Die LED in der Hauptschleife blinkt (ausreichend genau) 30 mal.

Es wäre interessant zu wissen, ob die Timer-LED tatsächlich langsamer 
blinkt, oder ob (z.B. zu Beginn) einmal Blinken fehlt.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

>   // 1Mhz/(64*15625) = 1 Hz
>   OCR1A= 15625;

Das müsste IMHO 15624 sein.
Der Timer soll 15625 unterschiedliche Zustaände einnehmen. Auch 0 ist 
ein Zustand. D.h. wenn der Timer bis 15624 gezählt hat, hat er mit dem 
nächsten Tick bereits bereits 15625 Timerticks abgezählt.

von Oliver (Gast)


Lesenswert?

>In CTC mode the counter is cleared to zero when
>the counter value (TCNT1) matches either the OCR1A (WGM13:0 = 4) or the ICR1 
>(WGM13:0 = 12).

IMHO sind 15625 und 0 ein und derselbe Zustand - daher passt 15625.

Oliver

von Stefan E. (sternst)


Lesenswert?

Oliver schrieb:

> IMHO sind 15625 und 0 ein und derselbe Zustand - daher passt 15625.

Nein, sind es nicht. Das Datenblatt ist hier ein wenig missverständlich. 
Das Rücksetzen auf Null erfolgt erst im nächsten Takt, nicht 
gleichzeitig mit dem Compare-Match.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Da kannst einfach den Compiler (bzw. Präprozessor) die richtigen Werte 
ausrechnen und auch warnen lassen, falls der Timer ungenau arbeiten 
sollte:
1
#include <avr/io.h>
2
3
// 1 MHz
4
#define F_CPU 1000000
5
6
// IRQs pro Sekunde
7
#define IRQS 1
8
9
#define PRESCALE 64
10
11
#if F_CPU / PRESCALE / IRQS -1 < 1
12
# warning Timer1 arbeitet falsch
13
#endif
14
15
#if F_CPU / PRESCALE / IRQS -1 > 0xffff
16
# warning Timer1 arbeitet falsch
17
#endif
18
19
#if (F_CPU % (PRESCALE * IRQS)) != 0
20
#   warning Timer1 arbeitet ungenau
21
#endif
22
23
void timer1_init (void)
24
{
25
    // CTC-Mode und PRESCALE=64
26
    TCCR1A = 0;
27
    TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
28
29
    // OutputCompare für gewünschte Timer-Frequenz
30
    OCR1A = (unsigned short) ((unsigned long) F_CPU / PRESCALE / IRQS -1);
31
32
    // OutputCompare-Interrupt A für Timer 1
33
    TIMSK |= (1 << OCIE1A);
34
}

von Andreas V. (tico)


Lesenswert?

Karl heinz Buchegger schrieb:
>>   // 1Mhz/(64*15625) = 1 Hz
>>   OCR1A= 15625;
>
> Das müsste IMHO 15624 sein.
> Der Timer soll 15625 unterschiedliche Zustaände einnehmen. Auch 0 ist
> ein Zustand. D.h. wenn der Timer bis 15624 gezählt hat, hat er mit dem
> nächsten Tick bereits bereits 15625 Timerticks abgezählt.

Das ist korrekt.

von Klaus (Gast)


Lesenswert?

so, ich habs nun nochmal nachgemessen, indem ich im Interrupt bis 15 
Minuten gezählt hab, und mit ner Stopuhr verglichen hab. Der Takt stimmt 
tatsächlich.

Die Variante mit _delay_ms(1000) is diejenige, die falsch läuft. Das es 
nicht so genau ist, ist ja klar, aber eine so große Abweichung hätte ich 
nicht erwartet. Möglicherweise die verringerte Auflösung aufgrund der 
großen Zeit? Obwohl in der Doku eigentlich 10 ms Auflösung steht. Und 
die zusätzlichen Befehle zwischen den Delays sollten ja auch keinen so 
großen Einfluss haben. Naja, aber das is jetzt ja auch gar nicht mehr 
wichtig :)


Und danke für den Hinweis, dass ich den Wert eins zu hoch gewählt hatte 
:)

von Simon K. (simon) Benutzerseite


Lesenswert?

Nenenene, Moment mal!

Richtig ist natürlich 15625-1=15624!

Mega16 Datenblatt (10/06) Seite 77:

Das gilt zwar für den OC-Output. Aber da die Frequenz durch zwei 
Timerüberläufe und einem Toggle gemacht wird gilt:

macht bei 15625: 0,99993600409573787277614232689108 Hz.
=> Richtig ist also 15624 als OCR Wert.

PS: Nur um das noch mal zu bestätigen. ;)

Ich würde in dem Falle die Makros von Georg bevorzugen. Mache ich in 
meinen Programmen eigentlich auch so. Da braucht man dann nicht den 
Taschenrechner vorkramen.

von icke (Gast)


Lesenswert?

Klaus schrieb:
>Obwohl in der Doku eigentlich 10 ms Auflösung steht.

10 * 60 = 600

logisch oder

von Klaus (Gast)


Lesenswert?

> Klaus schrieb:
>>Obwohl in der Doku eigentlich 10 ms Auflösung steht.
>
> 10 * 60 = 600
>
> logisch oder

Bitte, was?^^ Logisch ja, aber auf was für eine Frage war das jetzt die 
Antwort? ;)

von Karl H. (kbuchegg)


Lesenswert?

icke schrieb:
> Klaus schrieb:
>>Obwohl in der Doku eigentlich 10 ms Auflösung steht.
>
> 10 * 60 = 600
>
> logisch oder

Schon.
Aber eine Sekunde besteht aus 100 Stück 10ms Abschnitten.
Also nicht 10*60 sondern 10*100 = 1000

Daher ist
  _delay_ms( 1000 )
schon korrekt.

Die Abweichung wird wahrscheinlich 2 Ursachen haben.
* _delay_ms wird auch nicht auf die µs genau die Zeit einhalten
* du machst ja neben dem delay auch noch sonst was drumherum.

Ich denke mal, ersteres wird den größten Einfluss haben. _delay_ms wird 
nicht jeden Taktzyklus zählen, wenn es die Warteschelifen aufsetzt.

von VonNixNeAhnung (Gast)


Lesenswert?

Wurde noch nicht erwähnt, vielleicht könnte das hier 
Beitrag "Die genaue Sekunde / RTC" interessant sein.

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.