PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : externer Interrupt



Jumptime
24.01.2013, 22:19
Hallo,

ich möchte folgendes ausprobieren: mehrere Endcoderscheiben werden mit je einer Reflexlichtschranke abgetastet - die Signale anschließend mit einem Schmitt-Trigger (HCF 4093) aufbereitet und sollen nun per externem Interrupt ausgewertet werden. Und da entsteht mein Problem.
Leider kann ich mit den Anleitungen zum externen Interrupt nicht so recht viel anfangen.
Es sind 4 Interruptleitungen für den Roboterarm, die ich benötige.
Wie muß die Definition aussehen? Den PIN als Eingang definieren, klar - aber welcher Pin ist welcher Vector gem. "iomxx0_1.h"
Die Anleitung zur Erweiterungsplatine M256 WiFi, spricht von der Interrupt Serice Routine - ISR (INT0_Vector)? :confused:

Das Grundlegende Prinzip eines Interrupt ist mir bekannt.
Ich hatte auch etwas gefunden, dass ungefähr so aussah und keinen Fehler - aber auch keine Reaktion bringt:

DDRB &= ~_BV(5); // PORT B PIN 5 als Eingang

ISR(INT0_6)
{
m5++;
writeString_P_WIFI(" m5: "); writeInteger_WIFI(m5, DEC);
}

Mir fehlt schlicht weg die Zuordnung der möglichen Pins zu den definierten Vectoren. Ist das irgendwo zu finden?

Ich hatte zwar noch eine andere Variante, die muss aber regelmäßig abgefragt oder per StopWatch bearbeitet werden, was keine zufriedenstellenden Ergebnisse brachte.

Ich vergaß: ich benutze den RP6v2 mit Erweiterungsplatine M256 WiFi und möchte dort die externen Interrupt nutzen.

Ich hoffe ihr könt mir helfen.

Mit besten Grüßen, Kai :)

Dirk
25.01.2013, 08:46
Wenn du die Pin change interrupts nehmen willst, wäre die ISR:
ISR(PCINTx_vect) {}
... wobei x dann die Nummer des PCINT ist.
Die PCINT Pins können sogar Ausgang sein und triggern trotzdem.
Die anderen externen ISRs (INTx Pins) haben diesen Aufruf:
ISR(INTx_vect) {}

SlyD
25.01.2013, 13:53
writeString_P_WIFI(" m5: "); writeInteger_WIFI(m5, DEC);

Sowas packt man nicht in ISRs rein.
Das gehört in die Hauptschleife.
ISRs müssen so schnell wie möglich abgearbeitet werden - Ausgaben auf Text Displays (und übers UART) sind aber sehr langsam
weil die Dinger mit sehr niedrigem Takt laufen.
Klar funktionieren sollte es aber kann andere Teile der Software stören...

Zähler inkrementieren in ISR reicht ja in diesem Fall auch schon, den Rest extern machen.

Du musst die ISRs vorher erstmal noch aktivieren in den passenden Registern sonst passiert sowieso nix.
s. ATMEGA2560 Datenblatt bzw. google avr pcint ;-)

MfG,
SlyD

Jumptime
25.01.2013, 16:35
Danke erstmal für die Antworten.


writeString_P_WIFI(" m5: "); writeInteger_WIFI(m5, DEC); klar
Sowas packt man nicht in ISRs rein.

Die Ausgabe ist in dem Beispiel nur zur Kotrolle. In der ISR soll letztendlich nur die Variable (m5) gezählt werden (vorwärts erhöhen / rückwärts verringern), um so die relative Position des Gelenkes zu haben.
Ich habe mitlerweile herausgefunden, dass das Interrupthändling mit dem Befehl sei(), gestartet werden muß und mit cli(), beendet.
Die ISR muß nach dem sie abgearbeitet wurde mit reti abgeschlossen werden.

Du musst die ISRs vorher erstmal noch aktivieren in den passenden Registern sonst passiert sowieso nix.
s. ATMEGA2560 Datenblatt bzw. google avr pcint Und genau damit stelle ich mich zur Zeit etwas blöd an. Mal schauen was sich im Datenblatt findet.

Gruß Kai

Besserwessi
25.01.2013, 16:51
Die Bezeichnung für den Interrupt sieht mir mit INT0_6 zumindest verdächtig aus. Dabei ist GCC recht pingelig - die neuere Version sollte aber wenigstens eine Warnung geben wenn das falsch ist.

Das Ende der ISR mit RTI macht der Compiler schon, darum muss man sich nicht künnern, wenn man es nicht expizit verlangt. Man muss noch daran denken die Zählervariable als volatile zu deklarieren, damit der Compiler nicht zu viel wegoptimiert.

Für einen Incrementalgeber muss man aber schon etwas mehr machen als nur die Interrupts Zählen, denn einen Interrupt gibt es in beide Richtungen. Das mindeste ist eine unterscheidung nach hoch oder runter zählen, je nachdem ob die 2. Lichtschranke zu dem Incrementalgeber H oder L ist, oder notfalls auch noch nach der Polung am Motor.

SlyD
25.01.2013, 16:56
sei()

nein das wird schon in der RP6Lib gemacht das meinte ich nicht - Du musst die passenden Pin Change Interrupts aktivieren!

MfG,
SlyD

Jumptime
30.01.2013, 20:04
Hallo,
ich möcht das von mir begonnene Thema noch beenden. Eure Antworten haben mich zumindest auf den Weg gebracht. Die Lib half mir nicht wirklich weiter, aber der Hinweis zum Pin Change Interrupt und zum Datenblatt (Datenblatt - eher Datenbuch mit 447 Seiten :confused:) brachte den Erfolg. Eigentlich gar nicht schwer. :) Und so hat es geklappt:

Ich habe den PCINT16 an Port PK0 gewählt



DDRK &= ~(1<< PINK0); // PORT K PIN 0 als Eingang
PORTK |= (1<< PINK0); // Pull Up eingeschalten
PCMSK2 = (1<< PCINT16); // Bit 0 im Pin Change Mask Register PCINT16 gesetzt
PCICR = (1<<PCIE2); // Pin Change Interrupt Control Register
// Bit 2 des Pin Change Interrupt Enable gesetzt

ISR(SIG_PIN_CHANGE2) // Interruptroutine
{
if (status_RL ==1)
{
RA_M5++;
}
else if (status_RL ==2)
{
RA_M5--;
}
if ((RA_M5> 20) || (RA_M5< -20))
{
ARM_STOP();
}
//reti();
}

Aber so richtig verstanden habe ich das Ganze noch nicht wirklich, naja wenn's funktioniert.

Mit freundlichen Grüßen, Kai