Hi,
ich habe folgendes Problem: ich möchte den externen Interrupt kurzzeitig
nach dessen Auslösen deaktivieren und nach einer bestimmten Zeit mittels
eines Compare-Interrupts wieder deaktivieren. Sitzt schon ewig dran und
versteh einfach nicht was da falsch läuft. Hier mal der Quellcode kurz
und knapp:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>
#include "lcd.h"
unsigned char counter;
ISR(INT0_vect)
{
cli();
TCNT1H = 0x00; //Timer zurücksetzen
TCNT1L = 0x00;
OCR1AH = 0x05; //Compare nach ca 50ms
OCR1AL = 0xDC;
GICR &= ~(0x40); //INT0 deaktivieren
sei();
char buffer[10];
counter++;
itoa(counter, buffer, 10 );
set_cursor(0,1);
lcd_string(buffer);
}
ISR(TIMER1_COMPA_vect)
{
if(!(GICR | 0x40))
{
cli();
GIFR = 0x40;
GICR |= 0x40; //INT0 aktivieren
sei();
}
}
ISR(TIMER1_OVF_vect)
{
//auf Overflow reagieren
}
int main(void)
{
cli();
GIFR = 0x40;
GICR |= 0x40; //INT0 aktivieren
MCUCR = 0x0f; //auf steigende Flanken reagieren
OCR1AH = 0x05; //Compare nach ca 50ms
OCR1AL = 0xDC; //bei Taktung von 1MHz/64
TIMSK |= 0x04; //Overflow-Int aktivieren
TCCR1A = 0x00; //Steigende Flanken, kein clear bei Compare-Match
TCCR1B = 0x03; //Prescaler mit 64; Timer starten
sei();
lcd_init();
set_cursor(0,2);
lcd_string("Hello World!");
while(1)
{
}
return 0;
}
Der Controller reagiert brav auf den ersten Interrupt, wird aber nach
einer gewissen Zeit noch einer angelegt, passiert gar nichts mehr ...
Jemand eine Idee, was da schief läuft ?
Grüße Beni
@ Benedikt Dietrich (metalhead)
>ISR(INT0_vect)>{> cli();
Ist Unsinn, in einer ISR sind die Interrupts automatisch ausgeschaltet.
> sei();
Hat in einer ISR nix zu suchen (jaja, es gint Ausnahmen, aber nicht in
diesem Fall)
>ISR(TIMER1_COMPA_vect)>{> if(!(GICR | 0x40))> {> cli();> GIFR = 0x40;> GICR |= 0x40; //INT0 aktivieren> sei();
Das selbe hier, kein cli() und sei(), ist sinnlos und gefährlich.
>int main(void)>{> cli();
Hat du Paranoia? Beim Start von main() sind die Interrupts inaktiv.
>Der Controller reagiert brav auf den ersten Interrupt, wird aber nach>einer gewissen Zeit noch einer angelegt, passiert gar nichts mehr ...>Jemand eine Idee, was da schief läuft ?>ISR(TIMER1_COMPA_vect)>{> if(!(GICR | 0x40))
Das muss so heissen
> if(!(GICR & 0x40))
Siehe Bitmanipulation.
MFG
Falk
Danke für die Antwort. Die Paranoia haben mich überfallen nachdem es
nach ewigem Suchen nicht ging.
Der Fehler bei der Bitmanipulation ist peinlich, aber ändert nichts in
diesem Fall. Das Ganze funktioniert nach wie vor nicht :-( Der Interrupt
wird nur einmal ausgelöst
Benedikt Dietrich wrote:
> Der Interrupt> wird nur einmal ausgelöst
Kein Wunder, wenn du diese Zeile in der Interruptroutine (in beiden)
hast:
GICR &= ~(0x40); //INT0 deaktivieren
Anmerkung:
Diesen aufwändigen Kram
char buffer[10];
counter++;
itoa(counter, buffer, 10 );
set_cursor(0,1);
lcd_string(buffer);
macht man nicht im Interrupthandler sondern im Hauptprogramm. Im
Interrupthandler schafft man nru die Daten zur Seite auf die das
Hauptprogramm (oder eine vom Hauotprogramm aufgerufene Funktion)
auswertet und weiterverarbeitet.
@ Benedikt Dietrich (metalhead)
>Der Fehler bei der Bitmanipulation ist peinlich, aber ändert nichts in>iesem Fall. Das Ganze funktioniert nach wie vor nicht :-( Der Interrupt>wird nur einmal ausgelöst
Nimm mla die Deaktivierung aus der ISR und prüfe, ob dann die ISR
mehrfach ausgelöst wird.
MfG
Falk
@ Stefan "stefb" B. (stefan) Benutzerseite
>Kein Wunder, wenn du diese Zeile in der Interruptroutine (in beiden)>hast:> GICR &= ~(0x40); //INT0 deaktivieren
Augen auf beim Eierkauf. Er hat das schon richtig.
>ISR(TIMER1_COMPA_vect)>{> if(!(GICR | 0x40))> {> cli();> GIFR = 0x40;> GICR |= 0x40; //INT0 aktivieren
ODER, nicht UND.
> sei();> }>}
MfG
Falk
Also ohne die Deaktivierung wird der Interrupt ohne Probleme öfters
aufgerufen.
Der INT0 wird mit nem 10k Widerstand nach GND gezogen. Den Interrupt
erzeuge ich mit nem Reed-Kontakt, der dann INT0 auf 5V zieht, wenn er
durchschaltet
Grüße Beni
Gute Idee Falko!
Jetzt weiss ich dass der Timer läuft (hab mit nem Overflow das Lämpchen
erlöschen lassen), aber die Compare-Match ISR wird nicht angesprungen.
Mal schaun was das Datenblatt sagt...
So ich hab des Rätsels Lösung: habe vergessen im TIMSK das Bit 4 –
OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable - zu
setzen ... doofer Fehler :-)
Danke für die Hilfe Falko - o und Stefan ;-)
Eine eigene Frage?
Dieser Thread ist über 18 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.