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
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
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
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
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.
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.
@ 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
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.
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 :)
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.
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.
@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
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
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.
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