Forum: Mikrocontroller und Digitale Elektronik ATMega8, Timer1, CTC, ISR wird nur einmal aufgerufen


von Sebastian (Gast)


Lesenswert?

Hallo,

ich möchte gerne an einem ATMEGA8 einen Timer (Timer1, 16 Bit) im CTC 
Modus verwenden. Leider habe ich bei meinem Code das Problem, dass die 
ISR immer nur einmal aufgerufen wird. Ich finde leider den Fehler nicht.
IDE ist Atmel Studio 7 mit gcc Toolchain.
Sieht hier jemand den Fehler? Ich bin wahrscheinlich schon 
betriebsblind. :)

1
 #define F_CPU 8000000
2
3
 #include <avr/io.h>
4
 #include <avr/interrupt.h>
5
 #include <util/delay.h>
6
 #include "lcd-routines.h"
7
 #include "lcd-routines.c"
8
9
static int ISRs = 0;                // Zählvariable
10
11
12
void timer_init( void )
13
{ 
14
  TCCR1B = (1 << WGM12)|(1 << CS11)|(1 << CS10);  // CTC und Prescaler 64
15
  OCR1B = 125;                  // 8.000.000 / 64 / 1000 für 1ms
16
  TIMSK = 1<<OCIE1B;                // Timerinterrupts aktivieren
17
}
18
19
20
ISR( TIMER1_COMPB_vect )             
21
{
22
  ISRs++;          // Zählvariable hochzählen
23
  PORTC |= (1<<PORTC0);  // LED einschalten (Zeigt, dass die ISR einmal abgearbeitet wird)
24
  TIFR |= (1 << OCF1B);  // Muss ich hier OCF1B manuell zurücksetzen? Eigentlich nicht, oder?
25
}
26
27
28
int main( void )
29
{
30
  DDRC |= (1<<DDC0);    // Ausgang für LED
31
  PORTC &= ~(1<<PORTC0);  // LED zu Beginn auschalten
32
  timer_init();      // Timer initialisieren
33
  lcd_init();        // LCD initialisieren
34
  sei();          // Interrupts global aktivieren
35
36
  while(1)
37
  {
38
39
    if (ISRs == 500)
40
    {
41
      cli();              // Interrupts abschalten
42
      lcd_setcursor(0,2);        // LCD-Cursor positionieren
43
      lcd_string("ISR = 500");    // Text ausgeben
44
      _delay_ms(1000);        // Kurz warten
45
      lcd_clear();          // LCD wieder löschen
46
      sei();              // Interrupts wieder aktivieren
47
      ISRs = 0;            // Zählvariable resetten
48
    }
49
    
50
  }
51
  return 0;
52
}

von Falk B. (falk)


Lesenswert?

Es gibt keinen CTC Mode mit OCR1B als Einstellmöglichkeit. Nimm mal 
OCR1A, ebenso für die ISR.

von Falk B. (falk)


Lesenswert?

1
   if (ISRs == 500)
2
    {
3
      cli();              // Interrupts abschalten
4
      lcd_setcursor(0,2);        // LCD-Cursor positionieren
5
      lcd_string("ISR = 500");    // Text ausgeben
6
      _delay_ms(1000);        // Kurz warten
7
      lcd_clear();          // LCD wieder löschen
8
      sei();              // Interrupts wieder aktivieren
9
      ISRs = 0;            // Zählvariable resetten
10
    }


AUA! Interruptsperre für 1s? Hello? NOOOOOO!!!

Siehe Interrupt.

von Karl M. (Gast)


Lesenswert?

Das ist doch sinnfrei die Interrupts zu sperren !
1
cli();              // Interrupts abschalten
2
      lcd_setcursor(0,2);        // LCD-Cursor positionieren
3
      lcd_string("ISR = 500");    // Text ausgeben
4
      _delay_ms(1000);        // Kurz warten
5
      lcd_clear();          // LCD wieder löschen
6
      sei();

von Carl D. (jcw2)


Lesenswert?

1
static volatile int ISRs = 0;     // Zählvariable

Die ISR wird eventuell schon öfter gerufen, aber woran soll main() das 
erkennen? An der Variable die es selbst gerade auf 0 gesetzt hat und die 
nicht als "jederzeit veränderlich markiert" ist?

von Sebastian (Gast)


Lesenswert?

Danke für die Antworten.
Ich habe alle vorgeschlagenen Änderungen eingepflegt, jetzt wird die ISR 
garnicht mehr ausgeführt.
1
 #define F_CPU 8000000
2
3
 #include <avr/io.h>
4
 #include <avr/interrupt.h>
5
 #include <util/delay.h>
6
 #include "lcd-routines.h"
7
 #include "lcd-routines.c"
8
9
static volatile int ISRs = 0;                // Zählvariable
10
11
void timer_init( void )
12
{ 
13
  TCCR1A = (1 << WGM12)|(1 << CS11)|(1 << CS10);  // CTC und Prescaler 64
14
  OCR1A = 125;                  // 8.000.000 / 64 / 1000 für 1ms
15
  TIMSK = 1<<OCIE1A;                // Timerinterrupts aktivieren
16
}
17
18
19
ISR(TIMER1_COMPA_vect)             
20
{
21
  ISRs++;          // Zählvariable hochzählen
22
  PORTC |= (1<<PORTC0);  // LED einschalten (Zeigt, dass die ISR einmal abgearbeitet wird)
23
  TIFR |= (1 << OCF1A);  // Muss ich hier OCF1B manuell zurücksetzen? Eigentlich nicht, oder?
24
}
25
26
27
int main( void )
28
{
29
  DDRC |= (1<<DDC0);    // Ausgang für LED
30
  PORTC &= ~(1<<PORTC0);  // LED zu Beginn auschalten
31
  timer_init();      // Timer initialisieren
32
  lcd_init();        // LCD initialisieren
33
  sei();          // Interrupts global aktivieren
34
35
  while(1)
36
  {
37
38
    if (ISRs == 500)
39
    {
40
      lcd_setcursor(0,2);        // LCD-Cursor positionieren
41
      lcd_string("ISR = 500");    // Text ausgeben
42
      _delay_ms(100);          // Kurz warten
43
      ISRs = 0;            // Zählvariable resetten
44
    }
45
    
46
  }
47
  return 0;
48
}

von Falk B. (falk)


Lesenswert?

@Sebastian (Gast)

>Ich habe alle vorgeschlagenen Änderungen eingepflegt, jetzt wird die ISR
>garnicht mehr ausgeführt.

Ein BISSCHEN Mitdenken wäre vorteilhaft!

Eher so. RTFM!
1
TCCR1B = (1 << WGM12)|(1 << CS11)|(1 << CS10);  // CTC und Prescaler 64

von Sebastian (Gast)


Lesenswert?

Okay, danke, es funktioniert nun. Aber ich verstehe nicht so ganz warum 
ich TCCR1B statt TCCR1A konfigurieren muss. Im Datenblatt finde ich dazu 
auch keinen Hinweis.

Und das mit den Interrupts, wenn ich für diese Zeit keine Interrupts 
haben möchte, kann ich das doch so machen, oder gibt es, technisch 
gesehen, etwas was dagegen spricht?

LG und danke für die Hilfe,
Sebastian

PS: Ich fand den Ton hier auch schonmal freundlicher, auch wenn man vllt 
"blöde" Fragen stellt.

von Falk B. (falk)


Lesenswert?

@Sebastian (Gast)

>Okay, danke, es funktioniert nun. Aber ich verstehe nicht so ganz warum
>ich TCCR1B statt TCCR1A konfigurieren muss. Im Datenblatt finde ich dazu
>auch keinen Hinweis.

Brille putzen!

TCCR1A ist NICHT direkt mit OCR1A verbunden und
TCCR1B ist NICHT direkt mit OCR1B verbunden!

TCCR1A und TCCR1B konfigurieren ZUSAMMEN Timer1!

>Und das mit den Interrupts, wenn ich für diese Zeit keine Interrupts
>haben möchte, kann ich das doch so machen, oder gibt es, technisch
>gesehen, etwas was dagegen spricht?

Ja, siehe Interrupt, gibt es leider noch nicht als Hörbuch ;-)

>PS: Ich fand den Ton hier auch schonmal freundlicher, auch wenn man vllt
>"blöde" Fragen stellt.

https://de.wikipedia.org/wiki/Ironie

Hab dich nicht so mädchenhaft.

von Karl M. (Gast)


Lesenswert?

Sebastian schrieb:
> Okay, danke, es funktioniert nun. Aber ich verstehe nicht so ganz
> warum
> ich TCCR1B statt TCCR1A konfigurieren muss. Im Datenblatt finde ich dazu
> auch keinen Hinweis.
>
> Und das mit den Interrupts, wenn ich für diese Zeit keine Interrupts
> haben möchte, kann ich das doch so machen, oder gibt es, technisch
> gesehen, etwas was dagegen spricht?
>
> LG und danke für die Hilfe,
> Sebastian
>
> PS: Ich fand den Ton hier auch schonmal freundlicher, auch wenn man vllt
> "blöde" Fragen stellt.

Als Tipp, der nett gemeint ist, findest Du das Datenblatt und alle seine 
Register und Text unter:

http://www.atmel.com/images/atmel-2486-8-bit-avr-microcontroller-atmega8_l_datasheet.pdf

Der Timer1 Register sind ab S.96ff beschrieben.

von Karl M. (Gast)


Lesenswert?

Zu der Interrupt-Sperre, wäre es für uns sicherlich interessant das 
Warum zu erfahren.
Wir sehen die Dinge aus langjähriger Erfahrung evtl. anders und können 
Dir einen Ratschlag geben.

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.