Forum: Mikrocontroller und Digitale Elektronik Timer im Compare Mode läuft nicht sauber


von Munchos (Gast)


Lesenswert?

Hallo,

ich habe ein kleines Programm geschrieben, welches prinzipiell später in 
ein größeres eingefügt wird.
Das Programm soll folgendes machen:
Atmega 8, Timer1 16-bit im Compare Match Mode (nicht CTC möglich, da ich 
den Timer später durchlaufen lassen muss, entfällt diese Möglichkeit).
Das Programm soll alle 1024 Timerticks ein Compare Match auslösen und 
eine LED damit toggeln. Hierzu lade ich OCR1A mit TCNT+1024 vor, also 
dem aktuellen Zählerstand + die 1024 Timerticks.
Nun leider toggelt die LED unregelmäßig, sie blinkt etwa 3x in gleicher 
Frequenz, dann 1x eine andere, dann wieder 3x gleich, eigentlich soweit 
ich beurteilen kann periodisch.
Dennoch sollte die LED ja in einem konsanten Takt blinken und nicht ein 
Ausreißer dazwischen.
Zunächst dachte ich, dass es evtl. daran liegt, dass OCR1A und TCNT1 das 
gleiche temp Register verwenden zum Auslesen. Deshalb habe ich eine 
Variable eingefügt, die als temp Register dient, das funktionierte aber 
auch nicht.
Wo ist mein Denkfehler in dem Programm oder der Programmierfehler?
Hier ist der Sourcecode:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#ifndef F_CPU
6
#define F_CPU           8000000UL                   // Prozessortakt
7
#endif
8
9
#define LED      PB1    // Pin LED active low
10
  
11
ISR (TIMER1_COMPA_vect){
12
  PORTB ^= (1 << LED);      // LED teoggeln
13
  OCR1A = TCNT1+1024;        // Compare Match 1024 Timerticks später
14
  /* auf folgendes geht nicht:
15
  uint16_t temp = TCNT1
16
  temp += 1024;
17
  OCR1A = temp;
18
  */
19
}
20
21
22
// main programm
23
int main()
24
{
25
26
  DDRB = 0x00;                    
27
  DDRB |= (1 << DDB1);         
28
  PORTB |= (1 << LED);
29
  
30
  OCR1A = 1024;      // erstes Compare Match bei 1024 Timerticks, dann alle weitere 1024
31
  TCCR1B = (1 << CS00) | (1 << CS01);  // Prescaler 64
32
  TIMSK |= (1 << OCIE1A);                // Compare Match A enable
33
  sei();  // globales Interrupt enable
34
  
35
  while(1){
36
  // do nothing interruptgesteuert
37
  }
38
}

Desweiteren habe ich noch eine Frage: Welche Werte haben die Register im 
AVR allgemein nach Reset des µC?
Im Datenblatt steht, dass für den normalen Betrieb im Compare Match 
(ohne dass Pin OC1A geschaltet wird) im TCCR1A das Bit COM1A0 und COM1A1 
gelöscht sein muss (0).
Muss man diese vorher explizit löschen?
1
TCCR1A &= ~ ((1 << COM1A0) | (1 << COM1A1))
 oder sind alle Registerbits standardmäßig gelöscht?
Ich habe das auch ausprobiert beim Initialisieren, jedoch auch kein 
Unterschied im Programm.

Bin ratlos, gestern 4h damit verbacht :(

von Hannes L. (hannes)


Lesenswert?

> OCR1A = TCNT1+1024;        // Compare Match 1024 Timerticks später

Ich habe zwar keine Ahnung von C, aber was ich in ASM mache, müsste in C 
so aussehen:

OCR1A = OCR1A+1024;     // nächster Int.-Termin 1024 Timerticks später

Ich lese also die Compare-Register (nicht die Timer-Register) ein, 
addiere das Intervall und schreibe die Summe in die Compare-Register 
zurück. Dies ist jitterfrei, weil mir auch bei verspätetem Int-Aufruf 
der Wert nicht unterm Hintern wegläuft.

...

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.