Forum: Mikrocontroller und Digitale Elektronik Attiny13 Timer Overflow interrupt Problem


von Armin W. (wolf01705)


Lesenswert?

Hallo,

folgendes Programm soll eine LED an PB4 mithilfe eines Interrupts 
regelmäßig toggeln.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
ISR(TIM0_OVF_vect)  {
5
    PORTB ^= (1 << PB4); // toggle LED pin
6
}
7
8
int main(void)  {
9
        DDRB |= (1 << DDB4); // set LED pin as OUTPUT
10
        PORTB = 0b00000000; // set all pins to LOW
11
        TCCR0B |= (1 << CS02)|(1 << CS00); // set prescaler to 1024 (CLK=1200000Hz/1024/256=4Hz, 0.25s)
12
        TIMSK0 |= (1 << TOIE0); // enable Timer Overflow interrupt
13
        sei(); // enable global interrupts
14
        while(1)    {
15
        }
16
}

Auf dem Steckbrett jedoch leuchtet die LED, welche von PB4 nach GND 
geschaltet ist, durchgehend schwach, ohne irgendwie zu blinken. Da ich 
ein Einsteiger im Thema AVR-Mikrocontroller bin, wollte ich fragen, ob 
jemand mir mit diesem Problem helfen kann.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Armin W. schrieb:
1
 TCCR0B |= (1 << CS02)|(1 << CS00); // set prescaler to 1024 
2
 (CLK=1200000Hz/1024/256=4Hz, 0.25s)

 Wie kommst du darauf ?

 Es läuft 10x schneller über, also alle 21,845ms.

von Stefan F. (Gast)


Lesenswert?

Ich sehe keinen Fehler.

Wenn eine LED schwach glimmt hat man typischerweise vergessen, den Pin 
als Ausgang zu konfigurieren. Aber das ist hier offenbar nicht der Fall.

Sicher, dass die LED an PB4 hängt und dass dieser Pin nicht defekt ist? 
Ich hoffe, du hast der LED einen Vorwiderstand spendiert.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Marc V. schrieb:
> Es läuft 10x schneller über, also alle 21,845ms.

 Und mit 46Hz siehst du kein flackern, sondern nur schwaches (?)
 leuchten.

 Beim Tiny13 brauchst du übrigens mit PINB weniger code/register
 und bist auch schneller, was in der ISR vorteilhaft sein kann.
1
    PINB = (1 << PB4); // toggle LED pin

von Armin W. (wolf01705)


Lesenswert?

Ich habe nun einen 220 Ohm Vorwiderstand vor die LED geschaltet und den 
Codevorschlag
1
PINB = (1 << PB4); // toggle LED pin
übernommen, aber es tut sich nichts..

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Armin W. schrieb:
> Ich habe nun einen 220 Ohm Vorwiderstand vor die LED geschaltet und den
> Codevorschlag
>
1
> PINB = (1 << PB4); // toggle LED pin
2
>
> übernommen, aber es tut sich nichts..

Marc V. schrieb:
> Marc V. schrieb:
>> Es läuft 10x schneller über, also alle 21,845ms.
>
>  Und mit 46Hz siehst du kein flackern, sondern nur schwaches (?)
>  leuchten.

 Es tut sich schon etwas, nur ist es zu schnell als das man es sehen
 kann.
 Probiere mal folgendes:
====================================================================
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
volatile uint8_t isr_cnt = 0;
5
6
ISR(TIM0_OVF_vect)  {
7
  if(isr_cnt++ > 10) {
8
    PINB = (1 << PB4); // toggle LED pin
9
    isr_cnt = 0;
10
  }
11
}
12
13
int main(void)  {
14
        DDRB |= (1 << DDB4); // set LED pin as OUTPUT
15
        PORTB = 0b00000000; // set all pins to LOW
16
        TCCR0B |= (1 << CS02)|(1 << CS00); // set prescaler to 1024 (CLK=1200000Hz/1024/256=4Hz, 0.25s)
17
        TIMSK0 |= (1 << TOIE0); // enable Timer Overflow interrupt
18
        sei(); // enable global interrupts
19
        while(1)    {
20
        }
21
}
====================================================================

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Marc V. schrieb:
>  Es läuft 10x schneller über, also alle 21,845ms.

Wie kommst du darauf?

von Armin W. (wolf01705)


Lesenswert?

Marc V. schrieb:
> Probiere mal folgendes:
> ====================================================================#inc lude
> <avr/io.h>
> #include <avr/interrupt.h>
>
> volatile uint8_t isr_cnt = 0;
>
> ISR(TIM0_OVF_vect)  {
>   if(isr_cnt++ > 10) {
>     PINB = (1 << PB4); // toggle LED pin
>     isr_cnt = 0;
>   }
> }
>
> int main(void)  {
>         DDRB |= (1 << DDB4); // set LED pin as OUTPUT
>         PORTB = 0b00000000; // set all pins to LOW
>         TCCR0B |= (1 << CS02)|(1 << CS00); // set prescaler to 1024
> (CLK=1200000Hz/1024/256=4Hz, 0.25s)
>         TIMSK0 |= (1 << TOIE0); // enable Timer Overflow interrupt
>         sei(); // enable global interrupts
>         while(1)    {
>         }
> }
> ====================================================================

Hab ich versucht, ohne Wirkung.
Auch das einsetzen eines anderen Vorwiderstandes (10K) und einer anderen 
LED änderten nichts.
Könnte es daran liegen, das ich die gesamte Schaltung an den VCC/GND 
Pins eines Arduino Unos betreibe?

Beitrag #5575391 wurde vom Autor gelöscht.
Beitrag #5575395 wurde vom Autor gelöscht.
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Stefanus F. schrieb:
> Marc V. schrieb:
>>  Es läuft 10x schneller über, also alle 21,845ms.
>
> Wie kommst du darauf?

 Heute ist nicht mein Tag.
 Ich habe glatt mit 12MHz gerechnet.

 See ya, gehe schlafen, genug Unfug für heute angerichtet.

 P.S.

Armin W. schrieb:
> Könnte es daran liegen, das ich die gesamte Schaltung an den VCC/GND
> Pins eines Arduino Unos betreibe?

 Nein.
 Aber es könnte sehr wohl daran liegen, dass sich der Tiny dauernd
 resetet.

: Bearbeitet durch User
von Georg M. (g_m)


Lesenswert?

Armin W. schrieb:
>
1
>         DDRB |= (1 << DDB4); // set LED pin as OUTPUT
2
>

Funktioniert das?

von Armin W. (wolf01705)


Lesenswert?

Ich habe mal zum Test ein Blink-Programm ohne Timmer-Interrupt mit der 
delay-Funktion geschrieben, was anstandslos funktioniert.
1
#include <avr/io.h>
2
#define F_CPU    10000000UL
3
#include <util/delay.h>
4
5
6
7
int main (void) {
8
    DDRB |= (1 << DDB4); //DDRB |= (1 << PB4); funktioniert auch
9
    while(1)    {
10
        //PORTB = 0b00010000;
11
        PORTB |= (1 << PB4);
12
        _delay_ms(100);
13
        //PORTB = 0b00000000;
14
        PORTB &= ~(1 << PB4);
15
        _delay_ms(100);
16
    }
17
    return 0;                 
18
}

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Armin W. schrieb:
> Ich habe mal zum Test ein Blink-Programm ohne Timmer-Interrupt mit der
> delay-Funktion geschrieben, was anstandslos funktioniert.

 Na und, ich habe das alte Programm (von mir) ausprobiert, es läuft
 ohne Probleme, nur eben in 2,5s Takt.

 Interrupt kann bestimmt nicht daran Schuld sein, aber das dein Tiny
 dauernd in den Reset gesprungen ist, das kann sehr wohl sein.

von Georg M. (g_m)


Lesenswert?

Armin W. schrieb:
> Auf dem Steckbrett …

Da muss man aufpassen: schlechte Kontakte, fehlende Abblockkondensatoren 
usw.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Armin W. schrieb:
> #define F_CPU    10000000UL

Da ist doch was faul. Entweder läuft dein Tiny13 im Auslieferzustand, 
dann sind es 9,6 MHz geteilt durch 8, also 1,2 MHz. Oder du hast an den 
Fuses schon rumgefummelt, dann sind es entweder 9,6 MHz ohne die CKDIV8 
Fuse, oder 4,8 Mhz mit oder ohne CKDIV8 Fuse, das wären 4,8 Mhz resp. 
500 kHz.

10 Mhz hingegen erreichst du nur mit einem externen Oszillator.

von Armin W. (wolf01705)


Lesenswert?

Bei meinem Attiny13 habe ich noch nie was an den Fuses verändert (wie 
kann man die über avrdude auslesen?).
Aber auch bei einem anderen Programm, welches einen externen Interrupt 
nutzt, leuchtet die LED die ganze Zeit schwach.
Könnte es sein, das ich die ganze Zeit ungewollt ein Interrrupt auslöse, 
welcher keine ISR besitzt und deshalb den Attiny13 wie "neustartet"?

von Thomas W. (diddl)


Lesenswert?

Ungenutzte ISR machen kein Problem.
Der Compiler erzeugt eine Sprungtabelle die ungenutzt sauber schliesst.

Zudem muss man Interrupts stets frei schalten in einem Register


Hast du rekursive Funktionsaufrufe oder dynamischer Speicher Management?

von Armin W. (wolf01705)


Lesenswert?

1
#include <avr/io.h>
2
#define F_CPU    10000000UL
3
#include <avr/interrupt.h>
4
5
volatile uint8_t isr_cnt = 0;**
6
7
ISR(TIM0_OVF_vect)  {
8
  if(isr_cnt++ > 10) {
9
    PINB = (1 << PB4); // toggle LED pin
10
    isr_cnt = 0;
11
  }
12
}
13
14
int main(void)  {
15
        DDRB |= (1 << DDB4); // set LED pin as OUTPUT
16
        PORTB = 0b00000000; // set all pins to LOW
17
        TCCR0B |= (1 << CS02)|(1 << CS00); // set prescaler to 1024 (CLK=1200000Hz/1024/256=4Hz, 0.25s)
18
        TIMSK0 |= (1 << TOIE0); // enable Timer Overflow interrupt
19
        sei(); // enable global interrupts
20
        while(1)    {
21
        }
22
}

Nein

Könnte ein fehlerhaftes Fuse-Bit solche Probleme verursachen?
Denn bei Marc V. funktioniert das Programm ja...

: Bearbeitet durch User
Beitrag #5576141 wurde vom Autor gelöscht.
von Marc V. (Firma: Vescomp) (logarithmus)


Angehängte Dateien:

Lesenswert?

Armin W. schrieb:
> Könnte ein fehlerhaftes Fuse-Bit solche Probleme verursachen?
> Denn bei Marc V. funktioniert das Programm ja...

 Nein, aber fehlerhaftes Aufbau schon.
 Screenshot anbei, so geht es bei mir.

von Armin W. (wolf01705)


Lesenswert?

Es könnte am Breadboard liegen, denn auf einem anderen funktioniert die 
Schaltung, wenn auch unzuverlässig (geht nur ab und zu).

Beitrag #5576191 wurde vom Autor gelöscht.
von Purzel H. (hacky)


Lesenswert?

Nee, das Konzept ist falsch.

  PORTB ^= (1 << PB4); // toggle LED pin

bedeutet PORTB lesen, aendern, schreiben.

nun sollte man erstens PINB lesen, nicht PORTB, und dann stimmen die 
Spannungen nicht. Denn nur weil man eine Null schreibt, ist beim 
Ruecklesen nicht unbedingt eine Null dort. Wir haben ja eine Diode.

Also ueber eine globat statische Zwischenvariable gehen.
also

 volatile  int ledstate=0;

 interrupt() {
  ledstate != ledstate;
  portb = ledstate;
  ..
  }

 Den interrupt ueberpruft man am Besten mit einem Oszilloskop.

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Beim Tiny13 reicht es, eine 1 ins PINB Register an die gewünschte Stelle 
zu schreiben, dann toggelt der Pin.
1
PINB = (1 << PB4);
Das ist in Armins letztem Programm schon richtig gemacht.
'isr_cnt' kann auch eine static Variable in der ISR sein, wenn man ihren 
Wert nur innerhalb der ISR benötigt.

Allerdings steht da immer noch
Armin W. schrieb:
> #define F_CPU    10000000UL
was nicht stimmt.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

Jetzt ist G. schrieb:
> nun sollte man erstens PINB lesen, nicht PORTB, und dann stimmen die
> Spannungen nicht. Denn nur weil man eine Null schreibt, ist beim
> Ruecklesen nicht unbedingt eine Null dort. Wir haben ja eine Diode.

Das ist ja nun völliger Unsinn.

Matthias S. schrieb:
> Allerdings steht da immer noch
> Armin W. schrieb:
>> #define F_CPU    10000000UL
> was nicht stimmt.

Spielt erst eine Rolle, wenn der Compiler Berechnungen damit durchführt. 
tut er in diesem Fall aber nicht. Nichtsdestotrotz gehört da natürlich 
1,2MHz hingeschrieben. Denn die Fuses hat er ja nach eigener Aussage 
nicht angefasst.

Andererseits ist die Sache doch schon längst geklärt:

Armin W. schrieb:
> Es könnte am Breadboard liegen, denn auf einem anderen funktioniert die
> Schaltung, wenn auch unzuverlässig (geht nur ab und zu).

Das Breadboard ist Scheiße. Und das zweite auch nicht besonders.

Wurde aber auch schon frühzeitig drauf hingewiesen:

Georg M. schrieb:
> Armin W. schrieb:
>> Auf dem Steckbrett …
>
> Da muss man aufpassen: schlechte Kontakte, fehlende Abblockkondensatoren
> usw.

von Armin W. (wolf01705)


Lesenswert?

Ich habe den Fehler gefunden!
Schuld war weder Breadboard noch sonst was, ich habe bei der 
Kompilierung
mit AVR-GCC als mmcu=t13 angegeben, da ich gelesen hatte, t13 steht für 
den Attiny13.
Das war so wies aussieht jedoch falsch, den mit mmcu=attiny13 läuft es 
tadellos!
Wie markiere ich den Thread als solved?

von spess53 (Gast)


Lesenswert?

Hi

>Wie markiere ich den Thread als solved?

Garnicht. Deklariere lieber die Seite, wo du das gelesen hast, als Müll.

MfG Spess

von Peter D. (peda)


Lesenswert?

Armin W. schrieb:
> mit AVR-GCC als mmcu=t13 angegeben, da ich gelesen hatte, t13 steht für
> den Attiny13.

Dann sollte aber eine Fehlermeldung erfolgen:
main.c:1: error: MCU 't13' supported for assembler only


Armin W. schrieb:
> Wie markiere ich den Thread als solved?

Bearbeite Deinen Eröffnungsbeitrag.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Es gibt da einige Abkürzungen, die ich auch schon öfter gelesen habe. 
Man muss sie nicht benutzen.

Ich benutze immer einfach den richtigen Namen des Mikrocontrollers (so 
wie attiny13a) und genau den selben String benutze ich auch für avrdude.

von M. K. (sylaina)


Lesenswert?

Armin W. schrieb:
> Bei meinem Attiny13 habe ich noch nie was an den Fuses verändert (wie
> kann man die über avrdude auslesen?).

mit
1
avrdude -p attiny13 -c avrispmkii -P usb -v

würde bei einem via USB angeschlossenen AVR ISP MKII der angeschlossene 
Mikrocontroller ausgelesen werden samt Fuses. Ist es kein Attiny13 gibts 
ne Fehlermeldung von avrdude ;)

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.