PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer Interrupt wird nicht mehr ausgelöst



damnit
23.10.2013, 16:24
Hallo zusammen,

habe ein Problem mit folgendem Quellcode:



#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

ISR(TIMER1_COMPA_vect) //Interrupt service routine wenn Vergleichswert erreicht ist
{
static uint16_t vTeiler = 0; //Deklarieren von vTeiler
swTeiler++; //Zählschritt einstellen
if (vTeiler == 2) //Wert bis Interrupt ausgelöst wird
{
vTeiler = 0;
PORTD |= (1<<PD6);
_delay_ms(4000); //Schmierzeit
PORTD &= ~(1<<PD6);
}
}

int main (void)

{


DDRD |= (1<<PD6);



//Timer konfigurieren
TCCR1B |= (1<<WGM12) | (1<<CS12); //CTC-Mode und Vorteiler auswählen
//Tabelle

TIMSK |= (1<<OCIE1A); //Timer1 auswählen
//Interrupt aufrufen, wenn Vergleichswert erreicht ist
//Tabelle

OCR1A = 65499; //Vergleichswert zur bestimmung einer Sekunde
//Interrupts aktivieren

sei();


int i = 0; //Schleifenvariable deklariert
while(i<2) //Zwei mal wird die Schleife durchlaufen
{
i++;
PORTD |= (1<<PD6);
_delay_ms(3000); //Schmierzeit
PORTD &= ~(1<<PD6);
_delay_ms(3000);

}
return (0);



}


Und zwar wird der Timer Interrupt nicht mehr ausgeführt, seitdem ich in die While-Schleife einen Code integriert habe.
Es macht auf mich den Eindruck als würde, das komplette Programm stehen, nachdem die While-Bedingung nicht mehr erfüllt wird.
Sorry für die Anfänger Frage, aber bin blutiger Anfänger, was das Programmieren betrifft.

Gruß
damnit

shedepe
23.10.2013, 16:43
Ich vermute dass der Controller nach beenden der Schleife ins Nirvana springt und somit auch die Interrupts nicht mehr ausgeführt werden. Generell sollte man am Ende der Mainmethode bei einem Mikrocontroller eine endlos Schleife (while(true);) einfügen.

seite5
23.10.2013, 16:48
Hi,
@shedepe: Die Schleife sollte ein guter Compiler selbst "einbauen".
@damnit: Manche Compiler nehmen das "static" nicht sehr ernst, hast Du mal versucht,
vTeiler global zu definieren ?
mfg
Achim

sternst
23.10.2013, 17:04
Das Verlassen von main() ist eine ziemlich deutliche Willensbekundung des Programmierers, dass das Programm enden soll. Und daher macht der exit-Code der AVR-Libc auch genau das. Die Interrupts werden abgeschaltet, gefolgt von einer Endlosschleife, also quasi eine Deaktivierung des Controllers.

- - - Aktualisiert - - -


@damnit: Manche Compiler nehmen das "static" nicht sehr ernst, hast Du mal versucht,
vTeiler global zu definieren ?Sorry, aber was ist das denn für ein Quatsch?
Ein C-Compiler, der das static für eine lokale Variable nicht korrekt implementiert, hätte den Namen "C-Compiler" schlicht nicht verdient. Kannst du auch nur ein konkretes Beispiel für dieses "manche Compiler" nennen?

damnit
24.10.2013, 07:34
Hi @ all,

erstmal danke für eure Unterstützung.
@shedepe: thx, hab die while (1) - Schleife noch mit eingebaut und es funzt einwandfrei.

mfg
damnit

Wsk8
24.10.2013, 10:10
Kleiner Hinweis. Ein delay_ms(4000); in einer ISR ist wirklich sehr sehr sehr sehr sehr sehr sehr sehr sehr schlecht und sollte um jeden Preis vermieden werden!!!! Du blockierst damit einfach alles.

mfg

damnit
24.10.2013, 10:26
@Wsk8, bin mir dessen bewusst.
Der Inhalt in der ISR dient aktuell nur zu Visualisierung (ob Magnetventil komplett durchschaltet).
Kann leider nur Schritt für Schritt programmieren, da ich eben ein Neueinsteiger in diesem Themengebiet bin.

damnit
25.10.2013, 06:45
Hallo,
hab den Rat von Wsk8 beherzigt und habe in die Interrupt-Routine einen weiteren Timer eingebaut (ist das so üblich?).


#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h> //Datei interrupt.h einbinden
#include <util/delay.h>

ISR(TIMER1_COMPA_vect) //Interrupt service routine wenn Vergleichswert erreicht ist
{
static uint16_t swTeiler = 0; //Deklarieren von swTeiler
swTeiler++; //Zählschritt einstellen
if (swTeiler == 30) //Wert bis Interrupt ausgelöst wird
{
swTeiler = 0; //Teiler wieder auf 0 setzen
PORTD |= (1<<PD6); //PortD Strom an
TCCR1B |= (1<<WGM12) | (1<<CS12);
TIMSK |= (1<< OCIE1B);
OCR1B = 3094;
sei();


}
}
ISR (TIMER1_COMPB_vect)
{
static uint8_t vTeiler = 0;
vTeiler++;
if (vTeiler == 4)
{
vTeiler = 0;
PORTD &= ~(1<<PD6);

}
}

int main (void)

{


DDRD |= (1<<PD6); //PD6 als Ausgang deklarieren




//Timer konfigurieren
TCCR1B |= (1<<WGM12) | (1<<CS12); //CTC-Mode und Vorteiler auswählen
//Tabelle

TIMSK |= (1<<OCIE1A); //Timer1 auswählen (Output Compare A Match Interrupt Enable
//Interrupt aufrufen, wenn der Vergleichswert erreicht ist
//Tabelle

OCR1A = 3906; //Vergleichswert zur bestimmung einer Sekunde
//Interrupts aktivieren

sei();


int i = 0; //Schleifenvariable deklariert
while(i<2) //Zwei mal wird die Schleife durchlaufen
{
//Zu beginn des Programmstarts, sollen 2 Schmierungen druchgeführt werden
i++;
PORTD |= (1<<PD6);
_delay_ms(3000); //Schmierzeit
PORTD &= ~(1<<PD6);
_delay_ms(3000); //Untebrechung der Schmierung

}


while(1)
{

}
}

Prinzipiell läuft das Programm, jedoch findet bei jedem zweiten Aufruf der ISR, schon nach ca. einer Sekunde ein Interrupt statt, wodurch PD6 wieder auf Low gesetzt wird.
Sprich bei jedem ungeraden Interrupt findet der Overflow nach 4 Zählschritten statt und bei jedem geraden schon nach einem.
Kann es mir nicht wirklich erklären?

mfg
Damnit