Forum: Mikrocontroller und Digitale Elektronik externer Interrupt (PCINT1) atmega88 - Sprung nach 0x0000


von Felix (Gast)


Lesenswert?

Hi,
ich möchte per externen Interupt eine LED testweise an und ausschalten.

Wenn ich am PCINT1 den pin change Interrupt auslöse, startet der uC
wieder bei 0x0000 ,d.h. die main funktion wird erneut aufgerufen.

Zum einsatz kommt ein ATmega88

Hier mal die Initialisierung und die ISR
1
//Interrupt Routine
2
3
ISR(PCINT1_vect)
4
{
5
  //cli();
6
  if(hallindi==1)
7
    hallindi=0;
8
  else
9
    hallindi=1;
10
  //sei();
11
}
12
13
//Biteinstellungen
14
15
    EICRA = /*(1<<ISC01)|*/(1<<ISC00);
16
    //EIMSK = (1<<INT0);
17
    PCICR = (1<<PCIE0);
18
    PCMSK0 = (1<<PCINT1);




Jemand eine Idee wo hier der Fehler liegt?

Gruß Felix

von the cat (Gast)


Lesenswert?

Nein. Hast Du denn eine Ahnung was das Problem ist?

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Schau nochmal ins Datenblatt, ich vermute, Du verwechselst externen 
Interrupt und Pin-Change-Interrupt. Das sind nämlich unterschiedliche 
Dinge und daher haben sie auch separate Vektoren. Und wenn der falsche 
Vektor aufgerufen wird, wird dies als Fehler behandelt und kann durchaus 
an Adresse 0 (Neustart) enden (so genau kenne ich den GCC nicht, ich 
mach' nix in C).

MfG

von hab noch was (Gast)


Lesenswert?

Kluchscheißender Consulter schrieb:
> Und wenn der falsche
> Vektor aufgerufen wird, wird dies als Fehler behandelt und kann durchaus
> an Adresse 0 (Neustart) enden
"If an unexpected interrupt occurs (interrupt is enabled and no handler 
is installed, which usually indicates a bug), then the default action is 
to reset the device by jumping to the reset vector."
Quelle: 
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

von Frederik K. (n0ll4k)


Lesenswert?

Felix schrieb:
> EICRA = /*(1<<ISC01)|*/(1<<ISC00);
1
  EIMSK |= ( 1<<INT1 ); 
2
  EICRA |= ( 1<<ISC10 );

Das sollte funktionieren, den Rest kannst du weglassen, das wie schon 
erwähnt für Pin Change

von Felix (Gast)


Lesenswert?

Hi,
erstmal danke für die Antworten und nein ich habe keine Ahnung was es 
sein könnte, aber das was

Kluchscheißender Consulter schrieb:
> Du verwechselst externen
> Interrupt und Pin-Change-Interrupt.

Ist en super Tipp, hab mir das mal im Datenblatt angesehn, davon wusste 
ich garnicht. Hab es schon im Programm geändert. Allerdings kann ich es 
erst Montag wieder testen.

Erfolg oder Misserfolg, ich meld mich nochmal.

von Felix (Gast)


Lesenswert?

Problem besteht weiterhin. Um das Problem genauer zu beschreiben, sei 
gesagt das ich über zwei Eingänge einen Interrupt auslösen möchte, das 
hatte ich am Anfang nicht geschrieben. Zum einen über den INT0 auf der 
anderen Seite den PCINT1.

Dieser Teil funktioniert nur für den INT0/INT1
1
EIMSK |= ( 1<<INT1 ); 
2
EICRA |= ( 1<<ISC10 );

was mir fehlt ist ein Lösungsansatz um auch den PCINT1 "Interruptfähig" 
zu machen.

von Justus S. (jussa)


Lesenswert?

Felix schrieb:

>
1
> 
2
> //Interrupt Routine
3
> 
4
> ISR(PCINT1_vect)
5
> {
6
> ...
7
> }
8
> 
9
>     PCICR = (1<<PCIE0);
10
>

das passt ja wohl nicht zusammen...mit PCIE0 setzt du 'Pin Change 
Interrupt Enable 0', hast aber nur eine ISR für 'Pin Change Interrupt 
Enable 1'. Vielleicht schaust du nochmal ins Datenblatt, wie die 
PC-Interrupts im Gegensatz zu den 'normalen' ext. Interrupts 
funktionieren...

von Felix (Gast)


Lesenswert?

Werd aus dem letzten Kommentar nicht ganz schlau, weil mir glaub ich der 
Unterschied immer noch nicht klar ist.
Ich hab im Programm zwei ISR's eine für den INT0 und eine für den PCINT1 
hab jetzt die entsprechenden Stellen im Datenblatt die ich gefunden hab 
durchgelesen.

Hab die zugehörige Routine mit richtigem Vektor und hab soweit alle 
zugehörigen Bit's gesetzt, oder ist da grundlegend was falsch?
1
/*DDRB &= ~(1<<PB1);*/
2
EICRA = /*(1<<ISC01)|*/(1<<ISC00);
3
//EIMSK = (1<<INT0);
4
PCICR = (1<<PCIE0);
5
PCMSK0 = (1<<PCINT1);
6
7
8
/*ISR(INT0_vect)
9
{
10
  cli();
11
  //LED_PORT ^= (1<<LED1);       //LED1 anschalten
12
  sei();
13
}*/
14
15
ISR(PCINT1_vect)
16
{
17
  //cli();
18
  if(hallindi==1)
19
    hallindi=0;
20
  else
21
    hallindi=1;
22
  //sei();
23
}

Wie gesagt es geht mir darum das der Interrupt vom PCINT1 nicht das 
gesamte Program neu startet. Was löst den Fehler für diesen Reset aus?

von Justus S. (jussa)


Lesenswert?

Felix schrieb:
> Hab die zugehörige Routine mit richtigem Vektor und hab soweit alle
> zugehörigen Bit's gesetzt, oder ist da grundlegend was falsch?

ja. Es gibt zwei PCINT1: Zum einen den Pin PCINT1, der eine Bezeichnung 
für PB1 ist. Daneben gibt es noch den Interruptvektor PCINT1_vect, der 
aber für die PinChange-Interrupts PCINT8..15 zuständig ist.

Es gibt drei PinChange-'Blöcke':
PortB mit PCINT0..7
PortC mit PCINT8..15
PortD mit PCINT16..23
PortB ist Block 0, PortC ist 1 und PortD ist 2. Und dementsprechend ist 
auch die Bezeichnung der Register.
Alles mit 0 gehört zu PortB. Und der Pin mit PCINT1 liegt nunmal auf 
PortB und damit gehört dazu die ISR PCINT0_vect.

Und bevor die Frage kommt: Man kann keine verschiedenen ISRs für die 
verschiedenen Pins eines 'Blocks' definieren...

von spess53 (Gast)


Lesenswert?

Hi

>Werd aus dem letzten Kommentar nicht ganz schlau, weil mir glaub ich der
>Unterschied immer noch nicht klar ist.

>Was löst den Fehler für diesen Reset aus?

ISR(PCINT1_vect) ist für PCINT8...PCINT14, nicht für PCINT1, zuständig.

MfG Spess

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

> Und bevor die Frage kommt: Man kann keine verschiedenen ISRs für die
> verschiedenen Pins eines 'Blocks' definieren...

Noch ein Tipp: Es gibt Register, mit denen man die 'Blocks' maskieren 
kann, also festlegen kann, welche Pins (Bits) des Blocks (Bytes) den 
Interrupt auslösen dürfen und welche nicht.

Es lohnt sich also, das entsprechende Kapitel des Datenblatts zu lesen 
(und zu verstehen) anstatt einfach nur per Suchfunktion nach 
Schlagworten zu suchen.

MfG

von Justus S. (jussa)


Lesenswert?

Kluchscheißender Consulter schrieb:
> Noch ein Tipp: Es gibt Register, mit denen man die 'Blocks' maskieren
> kann, also festlegen kann, welche Pins (Bits) des Blocks (Bytes) den
> Interrupt auslösen dürfen und welche nicht.

das hatte er an sich ja gemacht
1
PCMSK0 = (1<<PCINT1);

von Kluchscheißernder N. (kluchscheisser)


Lesenswert?

Gut, dann nehme ich alles zurück und behaupte das Gegenteil. ^^

MfG

von Felix (Gast)


Lesenswert?

Super!!! Klappt alles.

Die Register hab ich gefunden

Kluchscheißender Consulter schrieb:
> Noch ein Tipp: Es gibt Register, mit denen man die 'Blocks' maskieren
>
> kann, also festlegen kann, welche Pins (Bits) des Blocks (Bytes) den
>
> Interrupt auslösen dürfen und welche nicht.


Was ich allerdings nicht wusste, war diese Aufteilung in drei Blöcke.

Justus Skorps schrieb:
> Es gibt drei PinChange-'Blöcke':
>
> PortB mit PCINT0..7
>
> PortC mit PCINT8..15
>
> PortD mit PCINT16..23



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.