ATMega8, Timer1, CTC, ISR wird nur einmal aufgerufen

Gast #4439649
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
}
#4439665
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.
Gast #4439666
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();
Gast #4439689
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
}
Gast #4439756
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.
#4439761
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.
Gast #4439765
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.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.