Forum: Mikrocontroller und Digitale Elektronik atmega32 timer2 benutzen


von Eugen T. (der_eugen_thorben)


Lesenswert?

Hi Forum,

ich würde gern den timer2 vom Atmega32 verwenden. Es soll in die 
Interrupt Routine gesprungen werden, nachdem es ein compare match gibt.


Ich würde gern eine 0.01 sec treffen und habe 16 Mhz.

Folgende Einstellung habe ich:
1
TCNT2 =0 ;
2
3
    OCR2 = 100;
4
5
    ASSR |= (0 << AS2);
6
7
    TCCR2 |= (1<< WGM21) | (0 << COM20) | (5 << CS20);

Die ISR Routine sieht so aus:

1
ISR(TIMER2_COMP_vect)
2
{
3
4
  toggle_yellowLED();
5
  
6
}


Leider toggled die LED nicht.

Ich vermute, dass das was in der ISR steht, nicht korrekt ist. Genau 
weiß ich es jedoch nicht.


Vielen Dank :D

von foo (Gast)


Lesenswert?

Output Compare Match Interrupt nicht aktiviert. TIMSK |= (1 << OCIE2)

von hoch (Gast)


Lesenswert?

Eugen Thorben schrieb:
>     TCCR2 |= (1<< WGM21) | (0 << COM20) | (5 << CS20);

Grübel.

von foo (Gast)


Lesenswert?

Eugen Thorben schrieb:
> Ich würde gern eine 0.01 sec treffen und habe 16 Mhz.

Dazu passen deine Einstellungen aber nicht. Du hast CTC Mode (1<<WGM21, 
und WGM20 ist nicht gesetzt) und einen Prescaler von 128 (CS22..20). 
D.h. der Timer rennt mit 125 kHz.

Da OCR2 nun auf 100 steht, wird der Timer alle 100 mal zurückgesetzt und 
ein Interrupt ausgelöst, also bei 1250 Hz. Entspricht 0.0008s.

Das liegt weit unter deinen 0.01s, also musst du den Timer seltener 
zurücksetzen... Da du jetzt weißt, wie du von den Werten zur Frequenz 
kommst, sollte es kein Problem sein, von der richtigen Frequenz (100 Hz) 
zu den nötigen Werten zu kommen.

Wenn noch was klemmt, frag nach.

von strommeister (Gast)


Lesenswert?

Eugen Thorben schrieb:
> ASSR |= (0 << AS2);
>
>     TCCR2 |= (1<< WGM21) | (0 << COM20) | (5 << CS20);

Du solltest dir unbedingt nochmal die Bitmanipulation anschauen und die 
Funktionsweise von Klammern testen.

von OldMan (Gast)


Lesenswert?

Hier mal ein Beispiel.
Auszug aus einer C-Soure von mir. Vielleicht hilft es.
1
#define PRESCALER0      ((1 << CS00) | (1 << CS02))     // CLK/1024
2
#define PRESCALER1    ((1 << CS12)|  (1 << CS10))    // dto.
3
#define PRESCALER2    ((1 << CS20) | (1 << CS21) | (1 << CS22))
4
void Init_Timer(void)
5
{
6
  
7
 /* Init Timer0 - Timer1*/
8
   tick2 = 0;
9
10
   TIMSK  |= (1 << OCIE0)| (1 << OCIE1A) | ( 1 << OCIE2);  // OCIE0 and
11
                              // OCIE1A int
12
                              // OCIE2 int
13
   TCCR0 |= PRESCALER0| (1 << WGM01);  // Prescaler and CTC Mode WGM01 
14
    TCNT0  = 0;         
15
  OCR0 = 4;              // 3,6 => 1 ms
16
// This is the central clock with 1 Hz 
17
  TCCR1B = PRESCALER1 | (1 << WGM12);// Prescaler 1024 and CTC Mode
18
  TCNT1 = 0;                // Set to zero
19
  OCR1A = (F_CPU/1024);        // calculate for 1 second 
20
21
// Timer2 is used to debounce the keys
22
  TCCR2 |= PRESCALER2 | (1 << WGM21); // Prescaler 1024 and CTC Mode
23
  TCNT2 = 0;
24
  OCR2 = (F_CPU/1024)/20;        // 20 ms
25
26
    sei();
27
}

von Christian K. (the_kirsch)


Lesenswert?

Wenn du eine konstante Zeitbasis haben willst, ist ein Timer im 
CTC-Modus genau das richtige.

Der Timer muss im CTC-Modus sein
Der Compare-Match-A-Interrupt muss aktiv sein
Der Prescaler und Compare-Registe-A-Register muss richtig eingestellt 
sein
1
 * Sample for Clear Timer on Compare Match (CTC) mode:
2
 *
3
 *   /- Clock                       /- Timer/Counter Compare Match A
4
 *   |                              |
5
 *   V                              V
6
 * 16 MHz / ( 64 * ( 249 + 1 ) ) = 1 kHz = 1 (ms)^-1
7
 *            ^       ^
8
 *            |       |
9
 * Prescaler -/       \- Compare Register A
10
 *
11
 * 16 MHz / (   64 * (  24 + 1 ) ) =  10 kHz = 0.1 (ms)^-1
12
 * 16 MHz / (   64 * ( 249 + 1 ) ) =   1 kHz = 1   (ms)^-1
13
 * 16 MHz / ( 1024 * ( 124 + 1 ) ) = 125  Hz = 8   (ms)^-1

für einen Interrupt alle 0,001 Sekunden (1ms) also:
1
OCR2 = 249;
2
TCCR2 = ((0 << FOC2) | (0 << WGM20) | (0 << COM21) | (0 << COM20) | (1 << WGM21) | (1 << CS22) | (0 << CS21) | (0 << CS20));
3
TIMSK = ((1 << OCIE2) | (0 << TOIE2) | (0 << TICIE1) | (0 << OCIE1A) | (0 << OCIE1B) | (0 << TOIE1) | (0 << OCIE0) | (0 << TOIE0));//Interrupts für Timer 0, 1 und 2

Genau 0,01 Sekunden ist leider nicht möglich, musst du in der ISR immer 
bis 10 Zählen.

: Bearbeitet durch User
von Eugen T. (der_eugen_thorben)


Lesenswert?

alter man, danke für die unterstützung. ich probier es heute aus und sag 
bescheid :D

von foo (Gast)


Lesenswert?

Christian K. schrieb:
> Genau 0,01 Sekunden ist leider nicht möglich, musst du in der ISR immer
> bis 10 Zählen.

100 Hz gehen damit tatsächlich nicht direkt. Für den Fall, dass 100,16 
Hz noch in der Toleranz sind, könnte man den Prescaler auf 1024 und OCR2 
auf 155 stellen.

von Eugen T. (der_eugen_thorben)


Lesenswert?

Ja, hat alles geklappt, hab es auf 1024 Teiler gestellt und 249 als Wert 
genommen.

Vielen Dank :D

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.