Forum: Mikrocontroller und Digitale Elektronik Atmega2560 + PCINT


von Anja (Gast)


Lesenswert?

Hallo,

ich habe ein kleines Problem, und zwar ich möchte bei meinem STK600 mit 
Atmega2560 die PCINT Interrupts nutzen. Aber irgendwie funktioniert es 
nicht. Es soll so ablaufen, dass sobald ich einen Taster drücke ein 
Interrupt auslöse und dann z.B. die LEDs angehen.
Hier wäre mein Code:

#include <avr/io.h>
#include <avr/interrupt.h

void ir_int_init(void)

int main(void)
{
   int k = 0;
   DDRJ = 0x00;
   DDRC = 0xff;
   PORTC = 0xff;
   ir_int_init();
   sei();
   for(;;)
      k++;
}

void ir_int_init(void) //Initialize interrupt
{
   PCICR = (1<<PCIE1);
   PCMSK1 = (1<<PCINT9);
}

ISR (PCINT9_vect)
{
   if(PINJ & S0)
   {
      PORTC = 0x00;
   }
}

Das entsprechende Bit in PCICR, PCMSKI und SREG wird korrekt gesetzt - 
aber es tut sich nichts, d.h. es wird nicht mal in die ISR 
reingesprungen.

Vielleicht kann mir ja jemand helfen - wäre lieb.

Viele Grüße,
Anja

von Dirk B. (sharandac)


Lesenswert?

Hallo,

sollte eigentlich funktionieren bist auf die If-Abfrage ... bleibt nur 
noch die frage wozu die If-Abfrage da ist? Schon mal ohne versucht und 
einfach die LED schalten ohne Bedingung? Und wie hast du den Port 
beschalten, Widerstand gegen Masse und Taster gegen Plus ?

CA Dirk

von Johannes M. (johnny-m)


Lesenswert?

Anja wrote:
> ISR (PCINT9_vect)
Den PCINT9_vect gibt es nicht! Der Pin PCINT9 ist dem Vektor PCINT1 
zugeordnet. Du musst zwischen den Vektorbezeichnungen und den Pins 
unterscheiden. Jedem Vektor sind 8 Pins zugeordnet, die bei 
entsprechender Maskierung alle den selben Interrupt auslösen.

Pinchange-Interrupt-Vektoren gibt es beim Mega256x nur drei, nämlich 
PCINT0, 1 und 2. Dein Code oben dürfte eigentlich gar nicht kompilieren, 
weil der Compiler eben PCINT9_vect nicht kennen kann.

von Dirk B. (sharandac)


Lesenswert?

ah ... jetzt bin ich eben auch gerade drauf gekommen :-) Datenblatt 
komplett lesen

von Anja (Gast)


Lesenswert?

Ja die IF Abfrage gehört natürlich raus :-)
Wie muß ich das denn dann machen? Ich checks irgendwie nicht anhand des 
Datenblattes wie das funktioniert mit den PCINT. Wo seh ich denn welchem 
Vector welche 8 Pins zugeordnet sind?
Kompilieren ging das mit dem AVR-GCC eigentlich ohne Probleme.
Also die LEDs sind Low aktiv geschalten.
Kannst dus mir vielleicht ein bisschen erklären wie das funktioniert?

Liebe Grüße,
Anja

von Philipp H. (swissrookie)


Lesenswert?

im Datenblatt unter 15:

"The Pin change interrupt PCI2 will trigger if any enabled PCINT23:16 
pin toggles, Pin change interrupt PCI1 if any enabled PCINT15:8 toggles 
and Pin change interrupts PCI0 will trigger if any enabled PCINT7:0 pin 
toggles. PCMSK2, PCMSK1 and PCMSK0 Registers control which pins 
contribute to the pin change interrupts. Pin change interrupts on 
PCINT23 :0 are detected asynchronously. This implies that these 
interrupts can be used for waking the part also from sleep modes other 
than Idle mode.kursiv"

von Johannes M. (johnny-m)


Lesenswert?

Es gibt drei Vektoren und jedem Vektor sind 8 Portpins zugeordnet, die 
den betreffenden Interrupt auslösen können. Welche Pins ihn tatsächlich 
auslösen, wird in den PCIMSK-Registern eingestellt, in denen jedes Bit 
einem Portpin entspricht. Wenn mehr als ein Pin maskiert ist, muss die 
Anwendungssoftware evtl. im Falle des Auftretens des Interrupts die Pins 
abfragen, um herauszufinden, welcher es war.

von Anja (Gast)


Lesenswert?

Also muß ich das dann praktisch so machen:
#include <avr/io.h>
#include <avr/interrupt.h

void ir_int_init(void)

int main(void)
{
   int k = 0;
   DDRB = 0x00;
   DDRC = 0xff;
   PORTC = 0xff;
   ir_int_init();
   sei();
   for(;;)
      k++;
}

void ir_int_init(void) //Initialize interrupt
{
   PCICR = (1<<PCIE0);
   PCMSK1 = 0xff;
}

ISR (PCI0_vect)
{
   PORTC = 0x00;
}

Und wie kann ich dann sagen lös nur ein Interrupt aus, wenn ein Signal 
an PB6 anliegt?

von Johannes M. (johnny-m)


Lesenswert?

Anja wrote:
>    PCICR = (1<<PCIE0);
>    PCMSK1 = 0xff;
Das PCIMSK1 hat nichts mit PCI0 zu tun! Wenn PCI0 ausgelöst werden soll, 
musst Du auch im richtigen PCIMSK-Register die Pins auswählen.

> Und wie kann ich dann sagen lös nur ein Interrupt aus, wenn ein Signal
> an PB6 anliegt?
Indem Du den entsprechenden Pin im richtigen PCIMSK-Register auswählst 
und den dazugehörigen Interrupt freigibst.

von spess53 (Gast)


Lesenswert?

Hi

>Und wie kann ich dann sagen lös nur ein Interrupt aus, wenn ein Signal
>an PB6 anliegt?

Garnicht. Der Interrupt wird bei einem Pegelwechsel ausgelöst. In der 
ISR musst du den Pegel prüfen und entsprechende Reaktionen einleiten.

MfG Spess

von Johannes M. (johnny-m)


Lesenswert?

spess53 wrote:
> Garnicht. Der Interrupt wird bei einem Pegelwechsel ausgelöst.
Das ist natürlich nicht zu verleugnen...

von Anja (Gast)


Lesenswert?

PCMSK0 = 0xff; //Damit müßte ich ja die komplette Gruppe auswählen
PCICR = (1<<PCIE0);

in der main halt dann sei() und die isr dann ISR(PCINT0_vect) {}

Oder lieg ich jetzt hier wieder falsch?

von Anja (Gast)


Lesenswert?

Sorry in der ISR (PCI0_vect) {}

von Philipp H. (swissrookie)


Lesenswert?

Hier mal ein spezifisches Beispiel für PB6:

Beim Initialisieren den Interrupt aktivieren
1
PCICR |= (1<<PCIE0);
Anschliessend das Bit welches den Interrupt auslösen soll im 
dazugehörigen Register setzen
1
PCMSK0 |= (1<<PCINT6);

ISR wird bei positiver und negativer Flanke an PB6 ausgelöst
1
ISR (PCINT0_vect)
2
{
3
  if(PINB & (1<<PB6))   //positive Triggerflanke PB6
4
  {
5
       //
6
  }
7
8
}

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.