PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Beenden einer ISR erkennen



hacker
10.08.2009, 14:05
Hallo,

folgendes Problem. Ich starte über eine Funktion eine ADC Messung mit einem externen ADC (parallele Anbindung). Dieser teilt mir das Ende seiner Wandlung über einen Interrupt mit. In dessen ISR kann ich nun die Daten mir einlesen.
Nun gut. Jetzt will ich aber, dass die gleiche Funktion, welche die Messung gestartet hat, den gemessen Wert zurückgibt. Jetzt stellt sich die Frage, wie weiß die Funktion, wann die ISR fertig ist (und der Wert somit eingelesen wurde)?

Code sieht ungefähr so aus:

unsigned short adc_read(void)
{
// externe ADC Messung starten
PORTD &= ~(1 << PD4);
PORTD |= (1 << PD4);
}

ISR(INT1_vect)
{
// CS auf low
PORTD &= ~(1 << PD5);
// RD auf low
PORTD &= ~(1 << PD6);
// Daten einlesen
value = (PINB & 0x0F);
value >>= 8;
value += PINC;
// RD wieder auf high
PORTD |= (1 << PD6);
// CS wieder auf high
PORTD |= (1 << PD5);
}

Wie mach ich das elegant? Oder ist das ein ganz falsches Herangehen. Mir fallen noch viele "dumme" Lösungen ein, die aber alles andere als elegant sind.

Grüße,
hacker

sternst
10.08.2009, 14:54
Nun gut. Jetzt will ich aber, dass die gleiche Funktion, welche die Messung gestartet hat, den gemessen Wert zurückgibt.Wozu dann überhaupt der Interrupt? Warte dann doch einfach in der Funktion, bis der ADC fertig ist, und lese auch dort das Ergebnis aus.

Übrigens:

value >>= 8;
Meintest du hier nicht vielleicht eher:

value <<= 8;

hacker
10.08.2009, 15:20
Dann müsste ich aber innerhalb der Funktion die Leitung pollen. Ich dachte mit Interrupt wäre das eleganter.

Das Shiften muss natürlich in die andere Richtung. Da hast du Recht.

/Edit

Ich sehe gerade, das der Impuls, den der ADC aussendet nur ca. 50ns lang ist. Da ist die Gefahr beim Pollen doch recht groß, den nicht mit zu kriegen. Zumal noch jede Menge andere Interrupts eintreten können.

sternst
10.08.2009, 15:29
Dann müsste ich aber innerhalb der Funktion die Leitung pollen. Ich dachte mit Interrupt wäre das eleganter.Sorry, aber ich kann das nicht ganz nachvollziehen. Warum ist das Pollen auf "Interrupt ist fertig" eleganter, als das Pollen auf "Pin hat bestimmten Level"?

hacker
10.08.2009, 15:33
Das stimmt. Aber vielleicht gibt es noch eine andere Lösung als auf das Ende des Interrupts zu pollen?

Und wie ich grad ergänzt habe oben, ist pollen auf einen 50ns Impuls mir bisschen zu riskant.

sternst
10.08.2009, 16:03
Aber vielleicht gibt es noch eine andere Lösung als auf das Ende des Interrupts zu pollen?Aber ich dachte, das ist genau das, was du wolltest, auf das Ende des Interrupts zu warten? Statt zu Pollen (auf ein volatile Flag in dem Fall), gäbe es höchstens noch die Möglichkeit, den Controller schlafen zu legen.

Yossarian
10.08.2009, 16:34
Hallo
Wenn der ADC fertig ist, wird doch ein entsprechendes Flag gesetzt.
Dieses brauchst Du also nur auszuwerten.

Mit freundlichen Grüßen
Benno

sast
10.08.2009, 17:04
Da es ein externer ADC ist, muss er sich das entsprechende Flag selber basteln. Dazu steht schon was in sternst letztem Post.

Ob du nun in der ISR nur das Flag setzt, oder auch gleich den Wert holst, hängt davon ab, ob du mit dem Interrupt auch noch andere Dinge machen willst. Um's Pollen kommst du dann aber nicht herum. Außer du verwendest eine Callback-Funktion ;o)

sast

Yossarian
10.08.2009, 17:20
Hallo

Da es ein externer ADC is

..habe ich doch glatt überlesen.

Mit freundlichen Grüßen
Benno

Ceos
10.08.2009, 17:25
okay mein vorschlag dazu wäre ... eine volatile variable anlegen

diese auf 0 setzen, ext int AUS
strobe für ADC start machen
ext int AN
in der main schleife machst du was du so machst PLUS einmal pro durchluaf die variable kontrollieren

jetzt kommt der strobe vom DAC, deine ISR löst aus ... in der ISR machst den ext int AUS und setzte die variable auf 1

kommt deine main schleife an der variablenabfrage vorbei, startest du den lesevorgang, setzt die variable wieder auf 0 und startest gegebenenfalls wieder die wandlung mit : strobe-> interrupt ein und setzt dein programm fort ...



eventuell soltle man das einschalten des interrupts VOR den strobe setzen, weis ja ncih wie lang eine wandlung bei dir dauert

Besserwessi
10.08.2009, 17:38
Wenn man das ADC fertig Signal an einen Interrupteingang legt der eien Interruptflag setzt, könnte man direkt nach dem Flag pollen. Den Eigentlichen Interrupt braucht man ja gar nicht auslösen. Dazu würde sich z.B. der ICP Eingang anbieten. Ein Signal von nur 50 ns ist aber auch da etwas zu kurz, wenigstens 60 ns sollten es schon sein bei 20 MHz Takt.
Wenn der ADC sehr schnell ist, könnte man auch gleich die passende Zeit warten. Ein externe ADC macht ja hauptsächlich sinn, wenn er schnell ist.
Zum warten müßte man aber eventuell auf Inline ASM zurückgreifen, oder auf Libraryfunktionen.

hacker
12.08.2009, 11:08
Danke für die vielen Vorschläge. Ich hab es jetzt mit normalen Warten gemacht. Den Interrupt vom ADC ignoriere ich einfach.
Da der ADC seine 12 Bit Messung ziemlich flott mir zur Verfügung stellt, verliere ich kaum Zeit.

Das Ganze ist Teil eines digitalen PID Reglers.

Richard
12.08.2009, 18:34
Moin moin.

Irgendwie habe ich bei Deinem Problem ein "Brett vorm Kopf"?
Starte doch einfach mit dem IRQ eine Funktion welche den ADC Wert
in eine Variable e. Am Ende der IRQ Funktion dann ein RTI und dein
normales Prog läuft weiter wo es beim Aufruf der Funktion gestoppt
wurde. Den ADC Wert der Varible kannst Du dann auswerten was es Dir beliebt.

Das hat mit Pollen NIX zu tun! Außer...Du mußt den externen ADC
auch zu einer Wandlung auffordern! Das währe dann eine Art Polling,
dann brauchst Du aber nicht wirklich einen (zwei) IRQ.

Wenn das ständige Pollen zu zeitaufwändig ist, benutze einen Timer
IRQ. Starte in der Timer IRQ den ADC, warte auf den ADC IRQ und dann
wie oben .... RTI. Die beiden IRQ sollten sich aber nicht in die Quere
kommen!

Gruß Richard