Forum: Mikrocontroller und Digitale Elektronik wie startet man einen interrupt?


von Markus S. (Gast)


Lesenswert?

Hallo zusammen,
hier mal wieder eine dusselige Fragen eines Jungprogrammierers.
Ich möchte mit einem MSP430149F über den I2C Bus mehrere Temperatufühler 
(LM75)auslesen. Das meiste von dem Programmierablauf habe ich so weit 
verstanden. Aber ich weiss nicht was ich schreiben muß um eine Interrupt 
Routine zu starten, die dann arbeitet wenn der MSP vom Fühler Daten 
empfangen hat.
Es gibt im Interrupt Flag Register das Bit RXRDYIFG  und in Interrupt 
Enable Register das Bit RXRDYIE das man wohl benutzen muß. Aber ich 
weiss nicht ganau wie.
Weiterhin kann ich mit den Zeilen z.B.:

#pragma vector=USART0TX_VECTOR
__interrupt void I2C_ISR(void)

nichts anfangen.

Ich weiss, dass damit die Interrupt Routine gestartet wird, aber was muß 
ich für mein Problem in diese beiden Zeilen schreiben und warum?
Ich hoffe ihr könnt mir helfen.

Vielen Dank
Markus

von Werner (Gast)


Lesenswert?

Also,

durch die 2 Zeilen wird dem Compiler klar gemacht, daß die folgende 
Funktion eine Inerrupt-Routine ist. Diese wird somit im Programmspeicher 
an die Adresse des Interrupteinsprungs gelegt. Hier mußt du dann 
programmieren was geschehen soll, wenn ein Interrupt ausgelöst wurde, in 
deinem Fall vermutlich Einlesen und verarbeiten der Daten von I²C.

Das Bit RXRDYIFG wird gesetzt wenn ein Interrupt von I²C ausgelöst 
wurde. Wennn das Bit RXRDYIE gesetzt ist springt der Prozessor 
automatisch in die Interruptroutine.

Möglicherweise gibt es bei dem Prozessor noch ein General Interrupt 
enable Bit, das muß auch gesetzt sein.

Allerdings scheint mir bei der Zeile
#pragma vector=USART0TX_VECTOR
etwas nicht zu stimmen, das sieht eher nach einem UART Interrupt aus.

Werner

von Markus S. (Gast)


Lesenswert?

Hallo Werner,
erst mal danke für deine Hilfe.

>durch die 2 Zeilen wird dem Compiler klar gemacht, daß die folgende
>Funktion eine Inerrupt-Routine ist. Diese wird somit im Programmspeicher
>an die Adresse des Interrupteinsprungs gelegt. Hier mußt du dann
>programmieren was geschehen soll, wenn ein Interrupt ausgelöst wurde, in
>deinem Fall vermutlich Einlesen und verarbeiten der Daten von I²C.
Ok, ist klar.

>Das Bit RXRDYIFG wird gesetzt wenn ein Interrupt von I²C ausgelöst
>wurde. Wennn das Bit RXRDYIE gesetzt ist springt der Prozessor
>automatisch in die Interruptroutine.
Ok, was schreibe ich dann in die beiden Zeilen die die Routine starten, 
damit er auch weiss welche Routine er starten soll.


>Allerdings scheint mir bei der Zeile
>#pragma vector=USART0TX_VECTOR
>etwas nicht zu stimmen, das sieht eher nach einem UART Interrupt aus.
Das war nur ein Beispiel aus einem MSP Buch um mein Problem besser 
beschreiben zu können.
Aber wie oben schon gesagt ist das mein Hauptproblem. Wie muss ich diese 
Zeilen schreiben damit der Prozessor in diese Routine springt wenn das 
RXRDYIE gesetzte ist.

Es ist nicht ganz einfach die Frage zu formulieren.
Ich hoffe du verstehst was ich meine.
Danke
Markus

von Düsendieb (Gast)


Lesenswert?

Werner schrieb:
> Diese wird somit im Programmspeicher
> an die Adresse des Interrupteinsprungs gelegt.

Du braust gar nicht besonderes machen, wenn der Interrupt kommt (und 
freigegeben ist) springt das Programm von alleine an die Stelle und 
arbeitet diesen Programmteil ab.


Axel

von U.R. Schmitt (Gast)


Lesenswert?

Ich glaube dein Problem ist das grundlegende Verständnis was ein 
Interrupt ist.
Ein Interrupt ist ein Ereignis, das durch irgendetwas ausgelöst wird. 
Das kann ein Signalpegel oder Flanke an einem Portpin sein, das kann 
sein, daß ein Zähler auf einen bestimmten Wert springt, die serielle 
Schnittstelle ein Byte vollständig empfangen hat oder daß ein AD Wandler 
eine Wandlung beendet hat.
Wenn diese Interrupts auftreten und Du in den Konfigurationsregistern 
diese Interrupts freigegeben hast, dann wird die Interruptfunktion 
angesprungen. Und zwar egal wo dein eigentliches Programm gerade steht.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Markus, du machst es dir für den Anfang ziemlich schwer. Interrupts sind 
(noch) nicht dein Ding und du willst gleich zwei auf einmal 
implementieren...

Einen UART-Interrupt zum Senden (TX) und einen I2C-Interrupt, wenn eine 
I2C-Übertragung abgeschlossen ist?

Steht denn das Grundprogramm und die Hardware in der einfacheren 
Polling-Variante schon? Alles getestet und funktioniert 100%? Wenn es da 
hakt, suchst du dir in einem nebenläufigen Programm 
(Userprogramm/Interrupts) den Wolf!

Erst nach diesem Zwischenschritt würde ich das Programm auf 
Interruptbetrieb umschreiben und zwar wieder mit einem Zwischenschritt:

Z.B. Polling-UART nach Interrupt-UART und I2C-Polling konstant lassen.

Bzw. umgekehrt Polling-UART konstant lassen und I2C-Polling nach 
Interrupt-I2C umstellen.

Danach dann das grande finale.

von Markus S. (Gast)


Lesenswert?

@ Axel

>Du braust gar nicht besonderes machen, wenn der Interrupt kommt (und
>freigegeben ist) springt das Programm von alleine an die Stelle und
>arbeitet diesen Programmteil ab.
Aber irgendwie muß ich dem Programm doch sagen wo es hinspringen soll. 
Wie mache ich das?


@ U. R. Schmitt
>Ich glaube dein Problem ist das grundlegende Verständnis was ein
>Interrupt ist.
>Ein Interrupt ist ein Ereignis, das durch irgendetwas ausgelöst wird.
>Das kann ein Signalpegel oder Flanke an einem Portpin sein...
ich denke was ein Interrupt ist und das er auf verschiedene Weise 
ausgelöst werden kann, habe ich grundsätzlich schon verstanden. Ich habe 
nur mit dem programmieren einProblem.

@ Stefan
>Markus, du machst es dir für den Anfang ziemlich schwer. Interrupts sind
>(noch) nicht dein Ding und du willst gleich zwei auf einmal
>implementieren...

>Einen UART-Interrupt zum Senden (TX) und einen I2C-Interrupt, wenn eine
>I2C-Übertragung abgeschlossen ist?
Warum brauche ich ein UART-Interrupt zum Senden? Ich dachte einen zum 
Empfangen reicht.

>Steht denn das Grundprogramm und die Hardware in der einfacheren
>Polling-Variante schon? Alles getestet und funktioniert 100%? Wenn es da
>hakt, suchst du dir in einem nebenläufigen Programm
>(Userprogramm/Interrupts) den Wolf!
Das Grundprogramm habe ich noch nicht, aber das ist nicht das Problem, 
denn das erste Programm um die Fühler auszulesen wird sehr einfach 
werden.
Was ist eine Pollin-Variante?

>Erst nach diesem Zwischenschritt würde ich das Programm auf
>Interruptbetrieb umschreiben und zwar wieder mit einem Zwischenschritt:
ich bin mir sehr sicher das ich das in dem Tesprogramm auch ohne 
Interrupt hinkriege. Und das würde ich natürlich auch ausprobieren aber 
wenn ich dann auf Interrupt umstellen will, stehe ich an dem gleichen 
Punkt wie jetzt.

>Z.B. Polling-UART nach Interrupt-UART und I2C-Polling konstant lassen.
ich habe keine Ahnung was du meinst.

>Bzw. umgekehrt Polling-UART konstant lassen und I2C-Polling nach
>Interrupt-I2C umstellen.
auch das verstehe ich nicht. Was heisst "Polling"?

>Danach dann das grande finale.
so weit ist es leider noch nicht.

Vielen Dank für all Eure Hilfe
Markus

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sorry ich war verwirrt wegen

> #pragma vector=USART0TX_VECTOR
                 ^^^^^ ^^

Das hatte ich als "Markus will mit USART etwas TXen (=Senden)" gelesen.

Polling ist z.B. Artikel Interrupt am Beispiel einer UART erklärt. 
Es ist das laufend wiederholte Abfragen von Registern (Pins, Statusbits) 
der µC-Hardware aus dem Anwenderprogramm heraus.

von Markus (Gast)


Lesenswert?

Markus S. schrieb:
> Aber irgendwie muß ich dem Programm doch sagen wo es hinspringen soll.
> Wie mache ich das?

Eigentlich musst du es dem Programm nicht sagen, das Programm muss nur 
an der richtigen Speicherstelle im Controller liegen und dafür sorgt der 
Compiler, bzw. du teilst dem Compiler mit der Anweisung :

__interrupt void I2C_ISR(void) - (btw. ist von Compiler zu Compiler 
verschieden)

mit was für eine Interruptserviceroutine (ISR) gleich folgt.
Der Compiler legt das dann an die Stelle an welcher der Controller 
springt wenn ein Interrupt ausgelöst wird. Die Stelle im Speicher ist 
dem Controller von Geburt an fest eingespeichert und kann auch nicht 
verändert werden.
Es wird nur meistens so gemacht das dort wo der Controller hin springt 
gerade genug Speicher frei ist für einen weiteren Sprungbefehl zum 
eigentlichen Programm. Aber das sind Dinge um die du dich nicht zu 
kümmern brauchst, das macht der Compiler für dich....schöne neue Welt :)

von Besserwisser (Gast)


Lesenswert?

Ich denke, Du brauchst gar keinen Interrupt, denn Dein Controller ist ja 
Master und kein Slave.
Um einen oder mehrere LM75 auszulesen ist nichts zeitkritisches dabei.
Temperatur ist eh sehr langsam und vor allem über einen oder mehrere 
LM75.
Nimm normale I2C-Routinen und setze es in Deine Main-Schleife - fertig!
Interrupts sollten nur da verwendet werden, wo sie auch Vorteile 
bringen.
Und dazu sollte man verstehen, was ein Interrupt ist.
Bei kurzen Programmen kann sogar die Polling-Variante schneller sein als 
ein Interrupt, denn man muss immer noch die Interrupt-Response-Time 
hinzurechnen, bis ein Interrupt ausgeführt wird. Ist aber eher selten in 
der Praxis.

von oszi (Gast)


Lesenswert?

Besserwisser schrieb:
> Bei kurzen Programmen kann sogar die Polling-Variante schneller sein als
> ein Interrupt, denn man muss immer noch die Interrupt-Response-Time
> hinzurechnen, bis ein Interrupt ausgeführt wird. Ist aber eher selten in
> der Praxis.

Dann bleibt noch die Frage, was die jeweilige Interrupt-Routine so 
angestellt hat und ob der Rücksprung zur rechten Zeit erfolgte. 
Interrupt ist schön wenn man weiß wie es funktioniert.

Viele Wege führen nach Rom. Dieser mit Interrupt ist oft steiniger.

von Markus S. (Gast)


Lesenswert?

@Markus

>Eigentlich musst du es dem Programm nicht sagen, das Programm muss nur
>an der richtigen Speicherstelle im Controller liegen und dafür sorgt der
>Compiler, bzw. du teilst dem Compiler mit der Anweisung :

>__interrupt void I2C_ISR(void) - (btw. ist von Compiler zu Compiler
>verschieden)
Genau das ist mein Problem. Wie muß diese Anweisung lauten? Ich benutze 
den Freeware IAR Compiler von Texas Instruments

@Besserwisser
>Ich denke, Du brauchst gar keinen Interrupt, denn Dein Controller ist ja
>Master und kein Slave.
>Um einen oder mehrere LM75 auszulesen ist nichts zeitkritisches dabei.
>Temperatur ist eh sehr langsam und vor allem über einen oder mehrere
>LM75.
>Nimm normale I2C-Routinen und setze es in Deine Main-Schleife - fertig!
>Interrupts sollten nur da verwendet werden, wo sie auch Vorteile
>bringen.
Gundsätzlich gebe ich dir recht das ich eingenlich gar kein Compiler 
brauche. Zumindest für die ersten Versuche. Aber ich arbeite auf ein 
großes Ziel hin, und das ist eine Steuerung für meine Heizung für die 
ich  mindestens 10 Fühler auslesen will.
Ich hatte mir auch schon eine Ablauf ausgedacht mit dem ich einen Fühler 
mit seiner Adresse anspreche und dann so lange in einer Warteschleife 
warte, bis in dem I2CIV Register einen 10 steht, denn dann sind die 
Daten fertig übertragen. Aber was ist wenn der Fühler kaputt ist oder 
wenn mein Kabel einen Fehler hat dann hängt das Programm an der Stelle 
fest. Natürlich kann man dafür eine maximale Wartezeit programmieren, 
aber irgendwann will ich den Interrupt aber doch verstehen bzw. anwenden 
können.

Habt wieder vielen Dank für Eure Antworten
Markus

von Markus S. (Gast)


Lesenswert?

Hallo noch mal,
bei all euren Antworten (noch mal vielen Dank dafür), fehlt mir leider 
immer noch die Hilfe was ich in den Startbefehl der Interruptroutine 
schreiben muß, wenn im I2C Modus die Routine starten soll wenn das 
RXRDYIFG (Daten empfangen) Bit gesetzt ist.
Denn irgendwie muß ich dem MSP ja mitteilen, dass er ganau diese Routine 
starten soll wenn das I2C den Interrupt auslöst
Also:
#pragma ... ???
__interrupt void ... ???

Die Erklärung von Werner habe ich ja verstanden was die zwei Zeilen 
bewirken. Aber ich weiss leider noch nicht wie man sie jetzt genau 
schreibt.

Danke
Markus

von Karl H. (kbuchegg)


Lesenswert?

Markus S. schrieb:
> Hallo noch mal,
> bei all euren Antworten (noch mal vielen Dank dafür), fehlt mir leider
> immer noch die Hilfe was ich in den Startbefehl der Interruptroutine
> schreiben muß, wenn im I2C Modus die Routine starten soll wenn das
> RXRDYIFG (Daten empfangen) Bit gesetzt ist.
> Denn irgendwie muß ich dem MSP ja mitteilen, dass er ganau diese Routine
> starten soll wenn das I2C den Interrupt auslöst

Die Details dazu stehen in der Doku deines Compilers. Aus der Sicht des 
C-Standards handelt es sich bei solchen Sachen immer um 
Compilererweiterungen, die natürlich jeder Hersteller anders handhabt.
Es ist auch oft recht hilfreich, wenn man das Demo-Verzeichnis das mit 
den meisten Compilern mitinstalliert wird einfach mal durchforstet. Da 
finden sich so einige Schätze, für die man sonst stundenlang Doku 
studieren müsste um den Einstieg zu finden.

von Werner (Gast)


Lesenswert?

Hallo Markus,

Der Text hinter "vector=" ist ein Konstante, wo die Adresse hinterlegt 
ist.
Diese ist im allgemeinen in der Datei "prozessor.H" hinterlegt. Bei IAR 
sind dort alle Interruptvectoren definiert. Wie genau die Header Datei 
für deinen Prozessor heisst weiss ich nicht, da ich nur mit AVR arbeite.

Die Zeilen sollte in etwa so heissen:

#pragma vector=XXXX    // XXX in Header Datei nachsehen
__interrupt void xyf(void)  // der Name der Funktion (hier xyf) ist egal
{

}

Gruß
Werner

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.