Forum: Mikrocontroller und Digitale Elektronik CTC-Verständnis: OCR1A scheint (!) ein Eigenleben zu führen


von Malte M. (mmalte)


Lesenswert?

Hallo allerseits,

ich verwende den Timer1 meines ATmega88PA mit CTC, um eine LED mit 180 
bpm (3 Hz) blinken zu lassen. Ohne die Taster zu bedienen dachte ich, 
dass folgendes passieren müsste: Die LED an PB0 ist am Anfang an und 
wechselt dann eben mit 3 Hz zwischen an und aus, weil der Timer immer 
bis 5207 (Inhalt von OCR1A) zählt. Nun geht sie aber nach ner 
Drittelsekunde aus (soweit also richtig), danach wechselt sie aber nur 
noch ungefähr alle vier Sekunden. Zurückgerechnet wäre eine Erklärung 
dafür, dass der Timer einmal bis 5207 zählt, danach aber bis 
65535=0xFFFF, also OCR1A ignoriert oder zurücksetzt.

Was hab ich da falsch verstanden bzw. müsste ich anders machen, damit 
der Timer immer zum gleichen Wert zählt?
1
#define F_CPU  1000000UL // 1 MHz
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
#define LED (1 << PB0)
8
#define D_LED DDRB
9
#define P_LED PORTB
10
#define TASTER1_AUS (PINC & (1 << PC5))
11
#define TASTER2_AUS (PINC & (1 << PC4))
12
13
#define PRESCALER_LOG 6
14
#define PRESCALER_BITS ((1 << CS11) | (1 << CS10))
15
16
volatile int8_t blinken = 1;
17
18
ISR (TIMER1_COMPA_vect) {
19
20
  if (blinken) {
21
    P_LED ^= LED;
22
  } else {
23
    P_LED &= ~LED;
24
  }
25
  
26
}
27
28
// muss das int sein?
29
int main(void) {
30
31
  // Datenrichtungsregister setzen, LED an
32
  D_LED |= LED;
33
  P_LED |= LED;
34
35
  // Timer 1:
36
  // CTC (TOP = OCR1A), Prescaler setzen
37
  TCCR1A |= (1 << WGM12);
38
  TCCR1B |= PRESCALER_BITS;
39
40
  uint16_t bpm = 180;
41
42
  // Rundungsfehler beim Shift, wenn F_CPU nicht durch den Prescaler teilbar ist:
43
  // PRESCALER_LOG =  8 => 6*10^-5
44
  // PRESCALER_LOG = 10 => 6*10^-4
45
  // -1 am Ende, weil ja von 0 gezählt wird (?, TODO: nochmal nachlesen)
46
  OCR1A = 60 * (F_CPU >> PRESCALER_LOG) / bpm - 1;
47
48
  // Compare-Interrupt erlauben
49
  TIMSK1 |= (1 << OCIE1A);
50
  // Global Interrupts aktivieren
51
  sei();
52
53
  int8_t entpr_taster1 = 0;
54
  int8_t entpr_taster2 = 0;
55
56
  while (1) {
57
58
    _delay_ms(10);
59
60
    // TASTER1
61
    if (TASTER1_AUS) {
62
      entpr_taster1 = 0;
63
    } else if (entpr_taster1 < 4) {
64
      entpr_taster1++;
65
    } else if (entpr_taster1 == 4) {
66
      entpr_taster1++;
67
      // AKTION:
68
      blinken = !blinken;
69
    }
70
71
    // TASTER2
72
    if (TASTER2_AUS) {
73
      entpr_taster2 = 0;
74
    } else if (entpr_taster2 < 4) {
75
      entpr_taster2++;
76
    } else if (entpr_taster2 == 4) {
77
      entpr_taster2++;
78
      // AKTION:
79
      bpm += 10;
80
      cli(); // TODO: nötig? Denke schon wg. 16bit.
81
      OCR1A = 60 * (F_CPU >> PRESCALER_LOG) / bpm - 1;
82
      sei();
83
    }
84
85
  }
86
87
  return 0;
88
89
}

von g457 (Gast)


Lesenswert?

> TCCR1A |= (1 << WGM12);
       ^          ^^^^^
WGM12 ist in TCCR1B.

von Malte M. (mmalte)


Lesenswert?

g457 schrieb:
>> TCCR1A |= (1 << WGM12);
>        ^          ^^^^^
> WGM12 ist in TCCR1B.

Vielen Dank! Da wär ich ja nie drauf gekommen … Im Datenblatt stehen 
WGM13:0 alle schön übersichtlich in einer Tabelle im Abschnitt über 
TCCR1A. Und da hab ich den Hinweis überlesen, dass WGM13:2 sich in 
TCCR1B befinden ;)

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.