Forum: Mikrocontroller und Digitale Elektronik ATtiny45: kein Interrupt bei Timer1


von Ben B. (fataldiskerror)


Lesenswert?

Moin liebes Forum,

ich habe mal wieder ein Problem und ich habe schon Stunden mit googlen, 
lesen und testen verbracht - erfolglos.
Eigentlich ganz einfach: ich verwende auf meinem Stk500 einen ATtiny45 @ 
8MHz  (intern, kein Teiler) und würde gerne aufgrund des 4-Bit-Prescale 
mit 16.384 den Timer 1 nutzen. Dazu folgendes Test-Programm im AVR 
Studio 7 zusammengeschrieben:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
volatile int i = 0;
5
6
ISR (TIMER1_OVF_vect)
7
{
8
  i++;
9
  PORTB &= ~(1 << PB0);  // led0 on if ISR is called
10
}
11
12
int main(void)
13
{
14
  DDRB = 0xFF;  // use B as output
15
  PORTB = 0xFF;  // because leds on stk500 are inverted -> turn all off
16
17
  TIMSK = (1 << TOIE1);  // timer overflow interrupt enable
18
  // CS1x: set prescale to 1111 == 16384
19
  TCCR1 = (1 << CS13) | (1 << CS12) | (1 << CS11) | (1 << CS10);
20
  
21
    while (1) 
22
    {
23
    // test if timer1 is running -> led1 starts blinking
24
    if(TCNT1==0){
25
      PORTB |= (1 << PB2);  // led2 off at start (==end) of each cycle
26
    }else if(TCNT1==127){
27
      PORTB &= ~(1 << PB2);  // led2 on at mid of each cycle
28
    }
29
    }
30
}

Was soll ich sagen: PB2 blinkt munter vor sich hin (Timer1 scheint also 
zu laufen), PB0 bleibt dauerhaft dunkel (die ISR scheint also nie 
angesprochen zu werden). Alle LEDs sind heile (sind die auf dem Stk500) 
und es ist nichts weiter angeschlossen.

Fuses (ext, high, low):
0xFF, 0xDF, 0xE2

Ich bin bei meiner Recherche häufiger auf Probleme mit Timer1 beim 
ATtiny45 gestoßen, auch hier im Forum, eine Lösung habe ich jedoch nicht 
gefunden. Z.B.:
Beitrag "ATTiny45 Timer und Interrupt"
Beitrag "Attiny45, timer tut nichts?"
Das bringt mich aber nicht weiter.

Kann mir irgendwer von euch weiterhelfen? Ich bin mit meinem Latein am 
Ende. Vielleicht bin ich auch einfach nur zu blind, aber ich sehe im 
Datenblatt auch keine weitere Info...

Dank & Gruß,
Ben

von Fluppi (Gast)


Lesenswert?

Fehlt für Interrupts nicht noch das "sei()" um Interrupts zu aktivieren?

von Andreas B. (bitverdreher)


Lesenswert?

Hi,
Vielleicht mal mit toggeln des Pins im IRQ versuchen:
(Es weiss ja niemand wie Deine LED angeschlossen ist)

ISR (TIMER1_OVF_vect)
{
  i++;
  PORTB ^= (1 << PB0);  // led0 on if ISR is called
}

oder (bei neueren AVRs)

ISR (TIMER1_OVF_vect)
{
  i++;
  PINB &= (1 << PB0);  // led0 on if ISR is called
}

Gruß
Andreas

von Draco (Gast)


Lesenswert?

Andreas B. schrieb:

> oder (bei neueren AVRs)
>
> ISR (TIMER1_OVF_vect)
> {
>   i++;
>   PINB &= (1 << PB0);  // led0 on if ISR is called
> }


Bei neueren AVRs?! So hab ich das noch nie gesehen. Woher hast du das?

von Andreas B. (bitverdreher)


Lesenswert?

aus der Bibel (Datenblatt) ;-)
z.B. 10.2.2
Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datashee 
t.pdf

sorry, muß auch
PINB |= (1 << PB0);  // led0 on if ISR is called
heißen

: Bearbeitet durch User
von H.Joachim S. (crazyhorse)


Angehängte Dateien:

Lesenswert?

Steht im Datenblatt, und ist manchmal recht nützlich.

von Ben B. (fataldiskerror)


Lesenswert?

Andreas B. schrieb:
> Vielleicht mal mit toggeln des Pins im IRQ versuchen:
> (Es weiss ja niemand wie Deine LED angeschlossen ist)

Wie gesagt, das ist die LED vom Stk500, die sind einfach nur invertiert 
angeschlossen. Habe trotzdem mal das toggle mit eingebaut und es ändert 
sich nichts...

von Ben B. (fataldiskerror)


Lesenswert?

Fluppi schrieb:
> Fehlt für Interrupts nicht noch das "sei()" um Interrupts zu aktivieren?

Unglaublich, das war es... Kopf->Tisch, Kopf->Tisch, Kopf->Tisch
Ich bin mir so sicher im Forum gelesen zu haben, die sein automatisch 
an... Muss die Stelle nochmal suchen. (Um ehrlich zu sein dachte ich mir 
schon "*seufz*, der Kommentar wird mir nicht weiterhelfen"... Riesen 
Irrtum meinerseits :-) Nur gut das ich es trotzdem probiert habe!)

Super vielen Dank!
Ben

von Ben B. (fataldiskerror)


Lesenswert?

Andreas B. schrieb:
> PINB &= (1 << PB0);  // led0 on if ISR is called

Nur am Rande: dann gehen alle anderen PBx von HIGH auf LOW (und damit 
die LED an) ;-) Habe es ausprobiert und es erscheint mir auch logisch...
Toggeln kann man meines Erachtens so nicht...

Grüße,
Ben

von Ben B. (fataldiskerror)


Lesenswert?

Eine Frage habe ich leider noch. Das Datenblatt besagt zum TCCR1:

> TCCR1 – Timer/Counter1 Control Register
> - Bit 7 – CTC1 : Clear Timer/Counter on Compare Match
>   When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00 in
>   the CPU clock cycle after a compare match with OCR1C register value. If the
>   control bit is cleared, Timer/Counter1 continues counting and is unaffected
>   by a compare match.

Es wird hier eindeutig vom OCR1C gesprochen, es gibt aber nur 
Compare-ISRs für OCR1A und *OCR1B*:
1
TIMER1_COMPA_vect
 und
1
TIMER1_COMPB_vect
(laut AVR Studio 7)

Zudem ist im TIMSK nur OCIE1A und OCIE1B für Compare-Interrups 
vorhanden, ansonsten nur der TOIE1 für den Overflow-Interrupt. Genau 
so wie im TIFR nur die Compare-Flags OCF1A und OCF1B, sowie TOV1 
als Overflow-Flag sind.

Das klingt für mich schizophren... Ich kann C nutzen um z.B. nur bis 127 
zu zählen, der Zähler wird zurück gesetzt, einen Interrupt kriege ich 
dafür aber nicht?!?
Muss ich zusätzlich dann noch A oder B nutzen um (ebenfalls auf 127) 
einen compare auszuführen?

BTW: ich nutze keine PWM, ich brauchen den Timer nur in Software, 
nicht an einem Außgang.

von H.Joachim S. (crazyhorse)


Lesenswert?

TOV1?

von DB (Gast)


Lesenswert?

Ben B. schrieb:
> Das klingt für mich schizophren... Ich kann C nutzen um z.B. nur bis 127
> zu zählen, der Zähler wird zurück gesetzt, einen Interrupt kriege ich
> dafür aber nicht?!?

Sieht für mich im Datenblatt auch so aus.

> Muss ich zusätzlich dann noch A oder B nutzen um (ebenfalls auf 127)
> einen compare auszuführen?

Ja, zB OCR1A setzen und den entsprechenden Interrupt nutzen. Overflow 
Interrupt wird wohl im Nicht-PWM Mode nicht ausgelöst, wenn der TCNT1 
nicht bis 0xFF läuft

>
> BTW: ich nutze keine PWM, ich brauchen den Timer nur in Software,
> nicht an einem Außgang.

PWM kannst du ja trotzdem einschalten. Schadet doch nichts? Brauchst ja 
nicht auf die Pins durchzuschalten. Dann sollte der Overflow Interrupt 
bei Erreichen von OCR1C auch kleiner 0xFF ausgelöst werden.

Eindeutig konnte ich das Verhalten im CTC Mode nicht herauslesen. Könnte 
man mal ausprobieren.

von Basti (Gast)


Lesenswert?

Versteh dein Problem nicht...
Wenn du beim Compare den Timer zurück setzt, dann ist doch der Compare 
Interrupt dein Overflow Interrupt.
Ansonsten kannst du mit dem C Register einfach deinem Overflowwert des 
Timer 1 einstellen...

von Ben B. (fataldiskerror)


Lesenswert?

H.Joachim S. schrieb:
> TOV1?

Aus der Doku:
> TIFR – Timer/Counter Interrupt Flag Register
> - Bit 2 – TOV1: Timer/Counter1 Overflow Flag
> In normal mode (PWM1A=0 and PWM1B=0) the bit TOV1 is set (one) when an
> overflow occurs in Timer/Counter1.
> The bit TOV1 is cleared by hardware when executing the corresponding
> interrupt handling vector. Alternatively, TOV1 is cleared, after
> synchronization clock cycle, by writing a logical one to the flag.
> In PWM mode (either PWM1A=1 or PWM1B=1) the bit TOV1 is set (one) when
> compare match occurs between Timer/Counter1 and data value in OCR1C - Output
> Compare Register 1C.
> When the SREG I-bit, and TOIE1 (Timer/Counter1 Overflow Interrupt Enable),
> and TOV1 are set (one), the Timer/Counter1 Overflow interrupt is executed.

von Ben B. (fataldiskerror)


Lesenswert?

Basti schrieb:
> Wenn du beim Compare den Timer zurück setzt, dann ist doch der Compare
> Interrupt dein Overflow Interrupt.
> Ansonsten kannst du mit dem C Register einfach deinem Overflowwert des
> Timer 1 einstellen...

Es geht ja gar nicht um das zurücksetzen - es wird bei OCR1C einfach 
kein Interrupt ausgelöst, habe ich den Eindruck.
Es gibt für OCR1C keinen Compare-Interrupt und wenn ich OCR1C setze 
und dazu noch CTC1 in TCCR1 setze, dann zählt er zwar nur noch bis 
OCR1C, löst aber keinen Overflow-Interrupt mehr aus.
Lasse ich CTC1 auf 0, dann wird der Overflow-Interrupt wieder 
ausgeführt, aber eben erst beim Wechsel von 0xFF zu 0x00. OCR1C wird 
dabei völlig ignoriert.

Viele Grüße,
Ben

von S. Landolt (Gast)


Lesenswert?

Datenblatt 12.3.8 TIFR – Timer/Counter Interrupt Flag Register

In PWM mode (either PWM1A=1 or PWM1B=1) the bit TOV1 is set (one) when 
compare match occurs between Timer/Counter1 and data value in OCR1C - 
Output Compare Register 1C.

von H.Joachim S. (crazyhorse)


Lesenswert?

Ben B. schrieb:
> Das klingt für mich schizophren... Ich kann C nutzen um z.B. nur bis 127
> zu zählen, der Zähler wird zurück gesetzt, einen Interrupt kriege ich
> dafür aber nicht?!?
> Muss ich zusätzlich dann noch A oder B nutzen um (ebenfalls auf 127)
> einen compare auszuführen?
>
> BTW: ich nutze keine PWM, ich brauchen den Timer nur in Software,
> nicht an einem Außgang.

Wo ist denn eigentlich dein Problem? Wenn du OCR1A/B nicht für 
Hardware-PWM brauchst, dann nimm doch OCR1A oder B samt 
compare-Interrupt bzw. im CTC-Mode.

von Ben B. (fataldiskerror)


Lesenswert?

S. Landolt schrieb:
> Datenblatt 12.3.8 TIFR – Timer/Counter Interrupt Flag Register
>
> In PWM mode (either PWM1A=1 or PWM1B=1) the bit TOV1 is set (one) when
> compare match occurs between Timer/Counter1 and data value in OCR1C -
> Output Compare Register 1C.

Oh, das hatte ich nicht gesehen, werde das mal ausprobieren! Danke!

H.Joachim S. schrieb:
> Wo ist denn eigentlich dein Problem?

Das Problem eher eine Merkwürdigkeit. Es ist einfach das, dass CTC1 
nur mit OCR1C arbeitet, OCR1C jedoch wiederum keinen 
Compare-Interrupt bietet und (im Normal Modus) keinen Overflow-Interrupt 
triggert.
Eine gangbare Lösung ist z.B. OCR1C und OCR1A (oder B) auf den 
gleichen Wert zu setzen, CTC1 im TCCR1 und OCIE1A (oder B) im 
TIMSK zu setzen, dann wird TIMER1_COMPA_vect (oder B) ausgelöst. 
Einen TIMER1_OVF_vect erhält man trotzdem nicht (natürlich ist TOIE1 
in TIMSK gesetzt).

Siehe hier:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
volatile int i = 0;
5
6
ISR (TIMER1_OVF_vect) // geht nicht
7
{
8
  i++;
9
  PORTB ^= (1 << PB0);  // led0 toggle if ISR is called
10
}
11
12
ISR (TIMER1_COMPA_vect) // geht
13
{
14
  i++;
15
  PORTB ^= (1 << PB1);  // led1 toggle if ISR is called
16
}
17
18
int main(void)
19
{
20
  cli();
21
22
  DDRB = 0xFF;  // use B as output
23
  PORTB = 0xFF;  // because leds on stk500 are inverted -> turn all off
24
25
  // timer compare interrupt a enable
26
  // timer overflow interrupt enable
27
  TIMSK = (1 << OCIE1A) | (1 << TOIE1);
28
29
  OCR1A = 49;
30
  OCR1C = 49;
31
32
  // CS1x: set prescale to 1111 == 16384
33
  TCCR1 = (1 << CTC1) | (1 << CS13) | (1 << CS12) | (1 << CS11) | (1 << CS10);
34
35
  sei();
36
37
    while (1) 
38
    {
39
    }
40
}

Werde nun den Tipp von S. Landolt mit aktivierter PWM testen. 
Grundsätzlich finde ich die Ausführungen im Datenblatt in diesem Falle 
nicht sooo intuitiv... :-) Und mir ist nicht verständlich, warum Atmel 
dem OCR1C nicht auch einen Compare-Interrupt spendiert hat.

Melde mich später zum Thema PWM nochmal ;-)

Dank & Gruß,
Ben

von Ben B. (fataldiskerror)


Lesenswert?

Ben B. schrieb:
> S. Landolt schrieb:
>> Datenblatt 12.3.8 TIFR – Timer/Counter Interrupt Flag Register
>>
>> In PWM mode (either PWM1A=1 or PWM1B=1) the bit TOV1 is set (one) when
>> compare match occurs between Timer/Counter1 and data value in OCR1C -
>> Output Compare Register 1C.
>
> Oh, das hatte ich nicht gesehen, werde das mal ausprobieren! Danke!

Awesome, das funzt! Habe PWM1A in TCCR1 gesetzt und nun wird 
TIMER1_OVF_vect bei OCR1C ausgelöst. Jipiee! Nun habe ich sogar 2 
mögliche Lösungen ;-)

Vielen Dank an alle!
Ben


1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
volatile int i = 0;
5
6
ISR (TIMER1_OVF_vect)
7
{
8
  i++;
9
  PORTB ^= (1 << PB0);  // led0 toggle if ISR is called
10
}
11
12
int main(void)
13
{
14
  cli();
15
16
  DDRB = 0xFF;  // use B as output
17
  PORTB = 0xFF;  // because leds on stk500 are inverted -> turn all off
18
19
  // TOIE1: timer overflow interrupt enable
20
  TIMSK = (1 << TOIE1);
21
22
  OCR1C = 49;
23
24
  // CTC1: clear timer on compare match of OCR1C
25
  // PWM1A: enables PWMA (COM1A0/COM1A1 define output mode)
26
  // CS1x: set prescale to 1111 == 16384
27
  TCCR1 = (1 << CTC1) | (1 << PWM1A) | (1 << CS13) | (1 << CS12) | (1 << CS11) | (1 << CS10);
28
29
  sei();
30
31
    while (1) 
32
    {
33
    }
34
}

von F. F. (foldi)


Lesenswert?

Ben B. schrieb:
> Nur gut das ich es trotzdem probiert habe!)

Hoffentlich denkst du dran, wenn die wieder mal nicht funktionieren.
Kann man nämlich auch mal vergessen.^^

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.