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
Ich seh's, sorry! INT0 kommt => INT0 deaktivieren + Timer Countdown auf 50ms => Timer kommt => INT0 scharf machen (# s.u.) => INT0 kommt => ... #) if(!(GICR | 0x40)) ist falsch if(!(GICR & 0x40)) ist richtig
Dumme Frage. Wie Erzeugst du denn deinen exteren Interrupt? Mit einem taster nach Masse? Hast du da auch einen Pull-Up am Pin? 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
Lass mal in ISR(TIMER1_OVF_vect) Eine LED togglen. Dann sieht man, ob der Timer evt. nicht läuft. Mal dein code aufgeräumt
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <stdlib.h> |
4 | #include <util/delay.h> |
5 | #include "lcd.h" |
6 | |
7 | unsigned char counter; |
8 | |
9 | |
10 | ISR(INT0_vect) |
11 | {
|
12 | TCNT1 = 0x00; //Timer zurücksetzen |
13 | OCR1A = 0x05DC; //Compare nach ca 50ms |
14 | GICR &= ~(0x40); //INT0 deaktivieren |
15 | |
16 | char buffer[10]; |
17 | counter++; |
18 | itoa(counter, buffer, 10 ); |
19 | set_cursor(0,1); |
20 | lcd_string(buffer); |
21 | }
|
22 | |
23 | ISR(TIMER1_COMPA_vect) |
24 | {
|
25 | if(!(GICR & 0x40)) |
26 | {
|
27 | GICR |= 0x40; // INT0 aktivieren |
28 | GIFR = 0x40; // INT0 löschen |
29 | }
|
30 | }
|
31 | |
32 | ISR(TIMER1_OVF_vect) |
33 | {
|
34 | //auf Overflow reagieren
|
35 | // LED hier togglen!
|
36 | }
|
37 | |
38 | int main(void) |
39 | {
|
40 | MCUCR = 0x0f; //auf steigende Flanken reagieren |
41 | GICR |= 0x40; //INT0 aktivieren |
42 | GIFR = 0x40; |
43 | OCR1A = 0x05DC; //Compare nach ca 50ms |
44 | TIMSK |= 0x04; //Overflow-Int aktivieren |
45 | TCCR1A = 0x00; //Steigende Flanken, kein clear bei Compare-Match |
46 | TCCR1B = 0x03; //Prescaler mit 64; Timer starten |
47 | |
48 | sei(); |
49 | |
50 | lcd_init(); |
51 | set_cursor(0,2); |
52 | lcd_string("Hello World!"); |
53 | while(1) { |
54 | }
|
55 | }
|
Mfg Falk
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 ;-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.