Forum: Mikrocontroller und Digitale Elektronik ATmega8 INT0 mit AVR Studio Simulation


von wulf (Gast)


Lesenswert?

Hallo!

Hab gerade angefangen den INT0 des ATMega8 auszuprobieren.
Dazu verwende ich folgenden Code:
1
#include <avr/io.h>
2
#include <stdint.h>
3
#include <avr/interrupt.h>
4
 
5
ISR(_VECTOR(1)) { // INT0
6
cli(); // Interrupts abschalten
7
PORTB |= (1<<PB1); // PB.1 setzen
8
9
}
10
11
int main(void)
12
{
13
14
DDRB = 0b00000011; // 0-1: Ausgang
15
DDRD = 0x00; // Eingänge
16
GIMSK |= (1<<INT0); // INT0 aktivieren
17
MCUCR |= ((1<<ISC01) | (1<<ISC00)); // bei steigender Flanke
18
19
sei(); // Interrupts aktivieren
20
 
21
while (1) {
22
PORTB ^= (1<<PB0); // PB.0 toggeln
23
}
24
25
}
Den PB.0 toggle ich, um zu sehen dass das Programm rennt. Wenn ich dann 
denn Pin D.2 auf high setze, wird auch die richtige Funktion aufgerufen 
aber es passiert dort nichts. Den PB1 kann ich nicht auf high setzen und 
eigentlich sollten ja die Interrups dann golbal deaktiviert sein, oder?
Wenn ich dann aber den INT0 Pin wieder auf 0 und dann auf 1 setze, wird 
der Interrupt erneut aufgerufen und es passiert nichts.

Was mache ich falsch?

Danke schonmal,
wulf

von wulf (Gast)


Lesenswert?

OK. Warum ich an PB.1 nichts ändern kann, ist mir mittlerweile klar.
ABer warum hat cli() in der Interruptroutine keine Auswirkungen?

von Sonic (Gast)


Lesenswert?

Versuch' mal die ISR so aufzurufen:

SIGNAL (SIG_INTERRUPT0)
{

}

Das CLI kannst du dir sparen, da das beim Aufruf der ISR sowieso 
passiert. Der globale INT wird beim Verlassen der ISR 'SIGNAL' wieder 
gesetzt, wenn du 'INTERRUPT' statt dessen verwendest musst du das 
Globale 'I'-Flag von Hand wieder setzen. Siehe AVR-LibC.

von wulf (Gast)


Lesenswert?

Danke für die Antwort!
Hab nun SIG_INTERRUPT0 probiert und es geht wieder nicht, wie ich will.

Das Programm soll keine besondere Funktion haben, nur Versuche.
Ich hätte gerne, dass der INT0 ein einziges mal aufgerufen wird; dort 
ALLE Interrupts deaktiviert werden und somit von selbst nie wieder 
auftreten.

von wulf (Gast)


Lesenswert?

Mittlerweile wieder selbst ein bisschen experimentiert:
wenn ich einfach den INT0 Interrupt abdrehe (in der INT0-Routine), dann 
wird beim nächsten Ansteigen des Signals nur das entsprechende Flag 
gesetzt, aber die Routine wird nicht mehr aufgerufen.

Aber wieso kann ich mit cli() nicht einfach alles abdrehen?

von Sonic (Gast)


Lesenswert?

Du brauchst nur den INT0 deaktivieren, das Register heißt übrigens GICR, 
nicht GIMSK. Ist vermutlich auch der Fehler.

SIGNAL (SIG_INTERRUPT0)
{
    GICR &= ~(1<<INT0);
    PORTB |= (1<<PB1);    // PB.1 setzen
}

von wulf (Gast)


Lesenswert?

Wie schon oben geschrieben; das hat funktioniert

GIMSK = General Interrupt Mask Register (aus dem AVRGCC Tutorial) zwar 
nicht für den Atmega 8, aber der Compiler übersetzt es richtig auf GICR

von Sonic (Gast)


Lesenswert?

Upps.. Zeitüberschneidung.
Wenn die ISR wieder verlassen wird wird der Globale INT ('I'-Flag) 
wieder gesetzt, hab' ich oben schon geschrieben. Mit INTERRUPT statt 
SIGNAL als ISR kannst du auch das 'I'-Flag löschen.

von Sonic (Gast)


Lesenswert?

Ach so, um's mal mit Assembler zu vergleichen:

SIGNAL verlässt die ISR mit 'reti'
INTERRUPT verlässt sie mit 'ret'

alles klar?

von wulf (Gast)


Lesenswert?

> Mit INTERRUPT statt SIGNAL als ISR kannst du auch das 'I'-Flag löschen.
Also INTERRUPT(SIG_INTERRUPT0) {} ?
Da tut sich bei mir nichts.
ISR(SIG...) schaltet nichts aus und SIGNAL(SIG...) auch nicht.

Aber es geht eh mit GICR &= ~(1<<INT0);
Den PB.1 konnte ich nicht setzen, da ich ja in der main() als 
Endlosscheife mit diesem Port arbeite; jetzt wird in der main() die ISR 
aufgerufen und beim Rückkehren schreibt es halt den 
zwischengespeicherten Registerwert auf den Port, so dass meine 
Änderungen in der ISR verloren gehen. Das hab ich aber mittlerweile eh 
schon gelöst

Danke nochmal!

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.