Hallo zusammen
Ich habe hier ein Problem mit dem abholen der Daten am UART0. Hier mal
der Code. Ich programmiere mit mspgcc und eclipse. Der Code läuft durch
aber das Array nmeabuffer bleibt stehts leeeeeer :o)
unsigned char nmeabuffer[1024];// Empfangsbuffer GPS Daten (NMEA Format)
void init_uart_0(void)
{
WDTCTL = WDTPW + WDTHOLD; // Watchdog aus
P3SEL |= 0x30; // P3.4 und 3.5 als USART0 TXD/RXD
ME1 |= UTXE0 + URXE0; // TX- und RX-Modul einschalten
UCTL0 |= CHAR; // 8 data bits, 1 stop bit, no parity
(8N1)
UTCTL0 |= SSEL0; // UCLK als ACLK festlegen / UCLK =
1MHz
UBR00=0x68; // 9600 Baud aus 1MHz erzeugen
UBR10=0x00;
UMCTL0=0x04;// Modulation der Baudrate durch Korrekturfaktor genau
9606bps
UCTL0 &= ~SWRST; // USART freigeben
IE1|= URXIE0 + UTXIE0; // TX- und RX-interrupts anschalten
IFG1 &= ~UTXIFG0; // Initales interrupt-flag loeschen
}
In meiner while(1) steht dann
init_uart_0();
int i;
for (i = 0; i < 1024; i++)
{
//while (!(IFG1 & URXIFG0));
nmeabuffer[i] = RXBUF0;
}
nmeabuffer[0] = '\0'; // End of File Marker an Pos0 setzen
i = 0;
init_spi_0();
Irgendwie will es einfach nicht so wie ich es möchte. Benutze ein Conrad
CR4 Modul welches ein u-blox LEA 4-H drauf hat. Über Infos wäre ich
dankbar.
Gruss reflection
Du musst die Zeichen die Du empfangen willst in der
Interrupt-Service-Routine einlesen, nicht in einer while-Schleife!
Wozu gibst Du sonst die Interrupts frei?
Sorry, aber ich verstehe gerade nur Bahnhof. Kannst Du mir vielleicht
anhand eines Codeschnipsels zeigen? Zum Thema Interrupt bin ich bis
jetzt noch nicht vorgestossen :o) Bitte um Nachsicht
Gruss reflection
//while (!(IFG1 & URXIFG0));
Ach ja, wenn ich diese Zeile reinstelle (ist ja Kommentar) dann läuft
gar nichts mehr, hat das was mit der Sache zu tun? Das Programm bleibt
dann gleich stehen und es geht nix mehr
Gruss reflection
reflection wrote:
> Sorry, aber ich verstehe gerade nur Bahnhof. Kannst Du mir vielleicht> anhand eines Codeschnipsels zeigen? Zum Thema Interrupt bin ich bis> jetzt noch nicht vorgestossen :o) Bitte um Nachsicht>> Gruss reflection
Weißt Du denn was eine Interrupt-Service-Routine ist?
Wie beim Timer, wenn der überläuft unterbricht das aktuelle Programm und
geht dort hin.
Bei der seriellen Schnittstelle ist es genauso. Kommt ein Zeichen an,
geht das Programm zur ISR und dort musst Du das Zeichen weiter
verarbeiten!
Irgendwie schaffe ich es einfach nicht. Er läuft gar nie in den
Interrupt. Kann mir jemand helfen was ich falsch mache?
Ach ja, signal.h ist includiert
unsigned char nmeabuffer[1024];// Empfangsbuffer GPS Daten (NMEA Format)
void init_uart_0(void)
{
WDTCTL = WDTPW + WDTHOLD;// Watchdog aus
P3SEL |= 0x30; // P3.4 und 3.5 als USART0 TXD/RXD
ME1 |= UTXE0 + URXE0; // TX- und RX-Modul einschalten
UCTL0 |= CHAR; // 8 data bits, 1 stop bit, no parity (8N1)
UTCTL0 |= SSEL0; // UCLK als ACLK festlegen / UCLK = 1MHz
UBR00=0x68; // 9600 Baud aus 1MHz erzeugen
UBR10=0x00;
UMCTL0=0x04; // genau 9606bps
UCTL0 &= ~SWRST; // USART freigeben
IE1|= URXIE0 + UTXIE0; // TX- und RX-interrupts anschalten
IFG1 &= ~UTXIFG0; // Initales interrupt-flag loeschen
}
while(1)
{
init_uart_0();
interrupt (UART0RX_VECTOR) usart0_rx(void)
{
nmeabuffer[i] = RXBUF0;
i += 1;
}
}
Schlussendlich möchte ich einfach das er die Daten die an UART0 RX
ankommen in den nmeabuffer speichert. Wenn nichts kommt soll er andere
Sachen machen, die habe ich aber jetzt nicht im while(1) aufgeführt.
Wäre echt nett wenn mir jemand helfen könnte. Habe nun schon einiges
über Interrupts gelesen, aber es will halt immer noch nicht.
Gruss reflection
Die Interrupt Service Routine gehört ja auch nicht in eine Funktion,
denn sie ist selber eine.
Schreib sie mal in eine extra Datei oder wenigstens außerhalb deiner
main() Funktion.
Habe die Interrupt Routine mal ganz an den Anfang genommen. Nun scheint
er reinzulaufen, aber der Buffer bleibt trotzdem leer. Ist es ein Code
Fehler oder habe ich da vielleicht nen Wurm in der Hardware?
Gruss reflection
Danke nochmal für den wertvollen Tip!
Also was ich neues zu berichten habe:
Ich hab ein Signal am TX Pins des u-Blox Moduls welches ich auf den RX
des uP führe (gemessen)
1 MHZ stimmt, mache auch den anderen UART aus dieser Frequenz und da
klappt es.
i wird abgefragt und wenn der Buffer voll ist wieder 0 gesetzt.
Baudrate, na da bin ich mir langsam auch nicht mehr sicher. Ich habe in
u-Blox Center 9600 baud deklariert. Frage ist halt ob er das auch so
übernimmt. Konnte das mit dem KO irgenwie nicht so recht rausfinden.
gesendet und gespeichert habe ich die Änderungen in u-Center. Wenn ich
den Empfänger wegnehme udn wieder ranmache findet er auch die vorher
abspeicherten Einstellungen.
Kann mir vielleicht jemand sagen ob ich den Buffer korrekt befülle, oder
ob der irgnedwo im Nirvana hängt? Denke langsam aber sicher der schreibt
mir die RX Daten irgendwo hin, nur nicht in den Buffer. Könnte das ein
Prob mit Pointern sein?
Gruss reflection
Muss ich eigentlich wenn ein Interrupt anfällt, diesen nach dessen
Abarbeitung löschen, oder macht er das selber (Flag)?
Muss ich warten bis er die Daten im Buffer vollständig drin hat? Würde
man glaube ich mit dem Befehl
while ((IFG1 & UTXIFG0) == 0);
machen, oder?
Gruss reflection
PS: Wäre toll wenn mir jemand einen Codeschnipsel geben könnte wo Daten
von RX einen Buffer geschrieben werden.
Und noch ne Frage, muss ich GIE irgendwo einschalten? Das mache ich
nämlich nicht. Klappt das mit den Interrupts auch ohne GIE oder liegt
wohl da der Fehler?
Gruss reflection
Der GIE muss natürlich aktiviert werden. Das Flag wird eigentlich beim
Anspringen der ISR automatisch gelöscht. Warten musst du nicht, denn der
Empfangs-Interrupt kommt erst, wenn das Zeichen komplett empfangen ist.
Setz doch mal einen Breakpoint am Anfang der ISR und schau, was im
RXBUF0 steht.
Da steht eben immer 0 drin. Er springt auch in die Interrupt Routine.
Ich erhöhe ja immer i um 1 und das macht er. Er schreibt mir aber wie
gesagt immer nur 0 en in den Buffer. Scheinen auch nur 0en anzukommen.
Wieso muss ich jetzt noch GIE extra aufführen? Er springt doch in die
Interruptroutine? Was deklariere ich genau mit GIE. Mache ich das
vielleicht schon mittels:
IE1|= URXIE0 + UTXIE0; // TX- und RX-interrupts anschalten
Oben steht der komplette Code wie ich ihn im Moment habe. Wie schalte
ich den die GIE genau ein?
Wäre über jede Info dankbar. Wenn es mal läuft schnall ich es auch
meistens, aber so weiss ich langsam echt nicht mehr wo ich suchen soll
Gruss reflection
Oder eben ein anderer LPM. Und da ist das GIE Bit dabei.
Wenn im RXBUF0 nur 0 steht, kam entweder nix, und der Interrupt kam
woanders her, ist aber unwahrscheinlich, oder dem Empfänger, Kabel
sonstwie haben ein Problem und liefern nur 0.
Wieso hast du überhaupt den Sende-Int aktiviert?
Den Sende IR muss ich mal noch abschalten, habe ich einfach der
Vollständigkeit halber drin. Also Daten kommen, das konnte ich mit dem
KO messen, aber es steht nix im RXBuf drin. Habe jetzt auch die Kabel
schon ca. 10 mal kontrolliert, an dem kann es also nicht liegen
Gruss reflection
PS: Das heisst ja dann, das ich so oder so mit LPM arbeiten muss, oder?
Kann es sein das mein Prob in der Initialisierung des UART liegt. Ich
benutze diesen UART eben auch noch als SPI Schnittstelle.
interrupt (UART0RX_VECTOR) usart0_rx(void)
{
nmeabuffer[i] = RXBUF0;
i += 1;
}
void init_spi(void)
{
U0CTL |= SWRST;
P3SEL = 0x0E; // Port 3 fur SPI verwenden
U0CTL = CHAR + SYNC + MM; // SPI-Modus (8-bit, Master)
U0TCTL = CKPL + SSEL0 + STC; // (polarity, ACLK, 3-wire)
U0BR0 = 0x02; // SPICLK = ACLK/2 entspricht
500kHz
U0BR1 = 0x00;
U0MCTL = 0x00;
ME1 |= USPIE0; // Modul aktivieren
U0CTL &= ~SWRST; // SPI aktivieren
}
void init_uart_0(void)
{
WDTCTL = WDTPW + WDTHOLD;// Watchdog aus
P3SEL |= 0x30; // P3.4 und 3.5 als USART0 TXD/RXD
ME1 |= UTXE0 + URXE0; // TX- und RX-Modul einschalten
UCTL0 |= CHAR; // 8 data bits, 1 stop bit, no parity (8N1)
UTCTL0 |= SSEL0; // UCLK als ACLK festlegen / UCLK = 1MHz
UBR00=0x68; // 9600 Baud aus 1MHz erzeugen
UBR10=0x00;
UMCTL0=0x04; // genau 9606bps
UCTL0 &= ~SWRST; // USART freigeben
IE1|= URXIE0 + UTXIE0; // TX- und RX-interrupts anschalten
IFG1 &= ~UTXIFG0; // Initales interrupt-flag loeschen
}
while(1)
{
init_spi
... diverser C-Code
init_uart_0(); Hier soll er die Daten vom UART abholen
init_spi wieder in SPI Mode schalten damit ich die anderen Sensoren
wieder ansprechen kann.
Kann es sein das ich da was vergesse umzustellen? Müsste doch gehen den
UART0 einmal als SPI und einmal als serielle Schnittstelle zu nutzen,
oder?
Gruss reflection
}
Achsoooo...sag das doch gleich. Dann musst du natürlich das UCTL0
Register richtig beschreiben, und nicht einfach bloß |= Char. Denn bei
SPI-Init sind ja noch MM und Sync gesetzt, die werden in deiner
UART-Init nicht gelöscht!!! ALso arbeitet die Schnittstelle dann immer
noch im SPI Mode. Das UTCTL0 Register genauso!
Und wieso schreibst du, er soll die Daten von UART abholen? Du kannst
nur auf Interrupt warten, oder eben eine Polling-Routine schreiben, und
das URXIFG auswerten.
Und was hat der Watchdog in der UART-Init zu suchen? Den musst du
möglichst sofort nach Beginn der main(), oder wenn du große Arrays hast,
wie z.B. dein 1024 Byte großes Char-Array noch VOR der main()
ausschalten. Sonst macht der im besten Fall ständig einen WDT-Reset.
Da ist noch einiges im Argen bei dir.
Achso, bevor du die USART umkonfigurierst musst du natürlich UOCTL |=
SWRST machen, sonst passiert gar nix.
Bitte nicht hauen :o)))) Tut mir leid, aber es sieht schon 1000mal
besser aus als noch vor 3 Monaten :o) Das mit dem WDT habe ich schon
gedacht, mache ich auch ganz am Anfang. Das heisst einmal deaktiviert
muss ich den nie mehr deaktivieren oder?
Öhm, wie passe ich denn die Register nun am besten an? Soll ich zuerst
mittels P3SEL alles auf 0x00 setzen und dann gleich wie oben vorgehen
oder muss ich da jedes einzelne Bit auswerten? Was würdest Du machen?
Ich weiss, es ist eigentlich ein Murks den Port als UART und SPI zu
verwenden, aber geht halt nicht anders :o)) Würde das so klappen wie ich
beschrieben habe, also mit zuerst 0 setzen?
Gruss und Danke!
reflection
Danke Christian
Das werde ich heute Abend gleich ausprobieren. Ich arbeite mit mspgcc.
Wieso löscht Du nicht das initiale Interrupt Flag? Muss man das nicht?
IFG1 &= ~UTXIFG0; // Initales interrupt-flag loeschen
Wenn ich schon am Fragen bin, aber ich will es ja verstehen
P3SEL = 0x30; // P3.4 und 3.5 als USART0 TXD/RXD
UCTL0 = SWRST; // USART aus
Wieso setzt Du zuerst den USART und erst dann machst Du einen SWRST?
Melde mich dann wieder wenn ich mehr weiss und es testen konnte
Gruss reflection
Bei mir war da noch nie ein "initiales Flag". Höchstens das TX-Flag, das
ansagt, dass man Senden darf. Du willst ja aber Empfangen. Das RX-Flag
ist doch gelöscht, wenn man SWRST macht. Hab das auch noch nirgends
gelesen.
Die Pins haben mit der USART-State-Machine nix zu tun. Eventuell musst
du sogar die Richtung des Ports auch noch einstellen, bei manchen
Zweitfunktionen ist das nicht automatisch, wenn man die Zweitfunktion
aktiviert.
Auf jeden Fall muss während des Umkonfigurierens das SWRST Bit stehn,
sonst wird nix umgestellt.
Edit: Was bringt es, das TX-Flag zu löschen? Dasheißt ja, du entziehst
dir selber die Sende-Berechtigung.
Salu zusammen
Ich habe immer noch Probleme. Ich habe den Teil von supachris
übernommen, aber jetzt gehen andere Sachen nicht mehr :o)
Habe einmal mein main.c angehängt, auch wenn ich das vermeiden wollte.
Zerreisst mich bitte nicht in der Luft, wird vermutlich so ziemlich
jedes Verbrechen beinhalten was man sich vorstellen kann. Bin wie
bereits erwähnt blutiger Anfänger, also nicht kloppen :o)
Wenn ich den Uart0 so initialisiere wie supachris es geschrieben hat,
läuft er mir in einen Interrupt wenn ich den Uart1 aufrufe (siehe main,
relativ weit unten dort wo sdbuffer auf 505 geprüft wird), sprich, das
Programm bleibt einfach stehen. Am Uart 1 kommt nichts an, der sendet
nur, sollte er auf alle Fälle.
Weiter wird der Interrupt von UART0 nicht mehr ausgelöst. Habe eine
Breakpoint in die Interruptroutine gesetzt und er hält dort nie an.
Wäre echt toll wenn jemand das Problem finden würde. Ich habe gestern
wieder bis weit in die Nach daran herumgebastelt, aber es will einfach
nicht so wie ich es gerne hätte. Konnte dafür viel lernen wie man den
Debugger einsetzen kann :o)
Gruss reflection
PS: Mein Teil (Initialisierung Uart0 ist noch drin, aber als Kommentar.
So lief er immer in den Interrupt, aber nmeabuffer blieb stets leer
Also bei Uart1 läuft er nicht mehr in einen Interrupt, keine Ahnung was
da falsch war.
Uart0 geht aber immer noch nicht. Er springt gar nie in die Interrupt
Routine, Daten kommen aber sicher an und ich habe jetzt noch einmal die
Pinbelegung angeschaut und sie scheint korrekt zu sein. TX von GPS geht
auf Pin33 (MSP430F149) also RX0
Gruss reflection
Alsooo....dass er bei UART1 Senden eine ISR aufruft, ist ja klar,
schließlich hast du ja den TX-Int aktiviert. Du bekommst also einen
Interrupt, der dir anzeigt, dass der UART zum Senden des nächsten
zeichens bereit ist. Das macht Sinn, wenn man mit einem Sendepuffer und
LPM arbeitet.
Mach erst mal lieber
1
voidinit_uart_1(void)
2
{
3
WDTCTL=WDTPW+WDTHOLD;// Watchdog aus
4
P3SEL|=0xC0;// P3.6 und 3.7 als USART1 TXD/RXD
5
ME2|=UTXE1+URXE1;// TX- und RX-Modul einschalten
6
UCTL1|=CHAR;// 8 data bits, 1 stop bit, no parity (8N1)
7
UTCTL1|=SSEL0;// UCLK als ACLK festlegen / UCLK = 1MHz
8
UBR01=0x08;// 115200 Baud aus 1MHz erzeugen http://mspgcc.sourceforge.net/baudrate.html
9
UBR11=0x00;
10
UMCTL1=0x5B;// Modulation der Baudrate durch Korrekturfaktor genau 114942bps
11
UCTL1&=~SWRST;// USART freigeben
12
IE2|=URXIE1;// TX- und RX-interrupts anschalten
13
}
Da stand übrigens schon wieder der Unsinn, vom initialen Sende-Flag
drin. Wie willst du was senden, wenn du das Flag löscht, was dir ansagt,
dass du Senden darfst???
Genauso bei UART_0 init. Kein Wunder dass du nix senden kannst.
Dann bei SPI_Init:
1
voidinit_spi_0(void)
2
{
3
U0CTL|=SWRST;
4
P3SEL=0x0E;// Port 3 fur SPI verwenden
5
U0CTL=CHAR+SYNC+MM;// SPI-Modus (8-bit, Master)
6
U0TCTL=CKPL+SSEL0+STC;// (polarity, ACLK, 3-wire)
7
U0BR0=0x02;// SPICLK = ACLK/2 entspricht 500kHz
8
U0BR1=0x00;
9
U0MCTL=0x00;
10
ME1|=USPIE0;// Modul aktivieren
11
U0CTL&=~SWRST;// SPI aktivieren
12
}
Zuerst setzt du das SWRST-Bit, OK, das ist richtig. Aber 2 Zeilen weiter
unten löscht du es schon wieder, indemk du die Bits für SPI einfach
setzt, anstatt sie per |= zu aktivieren. Das wird nicht ordentlich
klappen.
Wieso hältst du dich nicht an die Reihenfolge der USART-Init aus dem
User Guide?
Ich komme nicht mehr draus, sorry...
Also UART1 und SPI0 laufen tadellos und machen auch was sie sollen, das
kann ich kontrollieren. Mein Prob liegt bei UART0. Wie gesagt, er läuft
nicht in den Interrupt, weiss nicht wieso auf einmal nicht mehr. Die
Daten werden auf alle Fälle einfach über TX Uart1 auf den PC ausgegeben,
das funktioniert. Auch das mit dem Umstellen auf SPI funktioniert nun
wieder.
Wenn ich das Prog wie oben ausführe macht UART1 keinen Interrupt, das
Prog läuft einfach drauf los und sendet die Daten an die serielle
SChnittstelle, ohne Interrupt
Wenn ich UART0 definiere passiert gar nichts, er springt nie in die
Interrupt Routine.
Nach UART0 konfiguriere ich ja wieder alles im SPI Mode. Das läuft auch,
ich kann auch nach zig Durchläufen durch while(1) Daten via SPI lesen.
Gruss reflection
PS: Das mit dem Flag habe ich noch nicht korrigieren können, aber das
sollte ja nicht so einen Fehler auslösen, oder?
Also was ich inzwischen gemacht habe:
Beim SPI die Bits mittels |= setzen --> funktioniert
Die Zeilen wo ich diese ominösen Flags lösche entfernt. --> funktioniert
Fazit: SPI und UART1 laufen, UART0 weiterhin nicht. Er spring nie in den
Interrupt, auch wenn ich das Flag nicht lösche. Setze ich beim noch
_EINT(); rein, dann kreiert UART1 Sendeinterrupts, aber UART0 kommt nie
in den Interrupt. Der UART0 Interrupt muss zeitlich gesehen sicher vor
UART1 kommen. Die Daten des GPS (UART0) liegen bereits nach dem
Einschalten an. Der Interrupt von UART1 wird erst gesetzt wenn der
sdbuffer voll ist und das braucht ein bisschen Zeit (ca. 2 Sek) Da
müssten schon lange Daten von UART0 kommen.
Ich denke es liegt nicht mehr an viel, aber es läuft halt trotzdem
nicht. Schade, kann evtl. am Weekend wieder mal nach langer Zeit auf ne
Rennstrecke trainieren gehen und hätte da halt gerne das Teil
mitgenommen und getestet, aber das wird wohl nichts...
Gruss
Ich habe mal was anderes Probiert. Habe Hardwareseitig das GPS an UART1
gehängt, damit ich UART0 nicht während des laufens umprogrammieren muss.
Es läuft trotzdem nicht. Scheint also nicht an der Umkonfigurierung des
UART0 zu liegen. Er scheint mit folgendem Code eine Interrupt zu
generieren, aber er springt nicht in meine Interruptroutine rein, das
Prog bleibt am Anfang einfach stehen.
Ich bin kurz davor den ganzen Print aus dem Fenster zu schmeissen und
meine uP Projekte zu verwerfen. Ich komm einfach auf keinen grünen
Zweig. Das kann doch wohl nicht so schwierig sein... Hat mir wirklich
niemand einen Codeteil der genau das macht, Daten von einem UART lesen?
Wäre echt toll!
Ich habe signal.h includiert, muss ich noch was anderes machen?
Muss ich irgendwo _EINT(); setzen? Wenn ja, wo?
Gruss reflection
void init_uart_1(void)
{
WDTCTL = WDTPW + WDTHOLD; // Watchdog aus
P3SEL |= 0xC0; // P3.6 und 3.7 als USART1 TXD/RXD
ME2 |= UTXE1 + URXE1; // TX- und RX-Modul einschalten
UCTL1 |= CHAR; // 8 data bits, 1 stop bit, no parity
(8N1)
UTCTL1 |= SSEL0; // UCLK als ACLK festlegen / UCLK =
1MHz
UBR01=0x68; // 9600 Baud aus 1MHz erzeugen
http://mspgcc.sourceforge.net/baudrate.html
UBR11=0x00;
UMCTL1=0x04;
UCTL1 &= ~SWRST; // USART freigeben
IE2 |= URXIE1; // TX- und RX-interrupts anschalten
}
Hier dann die Interrupt Routine
interrupt (UART1RX_VECTOR) usart1_rx(void)
{
nmeabuffer[i] = RXBUF1;
i += 1;
}
An welchem Anfang bleibt es denn stehn? Ohne EINT() ist der Interrupt
eigentlich gar nicht aktiv, nach dem Reset sollte der aus sein, also
müsstest du halt den auch irgendwann mal freigeben.
Also er bleibt bei der Initialisierung des UART1 stehen
Denke er bekommt einen Interrupt von RX, aber geht nicht in die
Interruptroutine. Muss ich den Namen der Routine noch irgendwo explizit
definieren?
Muss ich irgendwie noch die Richtung der IO's definieren? Also ala
P3SEL oder so? Habe ich nicht gemacht, SPI und UART1 Senden laufen auch
ohne. Denke das mache ich bereits in der Initialisierung, oder?
Gruss
Salu rufus
Hier mein aktuelles main.c
Wäre toll wenn Du mir sagen könntest was schief läuft :o)
Also er bleibt bei der Initialisierung des UART1 stehen
Denke er bekommt einen Interrupt von RX, aber geht nicht in die
Interruptroutine. Muss ich den Namen der Routine noch irgendwo explizit
definieren? Ich will Daten die kontinuierlich an RX1 ankommen in den
nmeabuffer einlesen
Gruss
Dann mach doch VOR der Uminitialisierung der USART ein DINT(); und
nachher wieder EINT();
Damit müsste das erledigt sein. Wenn ein Int kommt, springt er auch in
die entsprechend dem Vektor deklarierte ISR. Wenn er da nicht
reinspringt, kommt kein INT, jedenfalls nicht der, auf den du wartest.
User Guide:
"Setting PxSELx = 1 does not automatically set the pin direction. Other
peripheral module functions may require the PxDIRx bits to be configured
according to the direction needed for the module function. See the pin
schematics in the device-specific datasheet."
Salu Christian
Ich mache es jetzt ohne Uminitialisierung, habe es mal probehalber an
den UART1 gehängt und die Routinen angepasst. Im Post 04.09.2007 14:32
ist nun das neue main.c
Frage: Wo ist die Defintion in den Header Files zu
interrupt (UART1RX_VECTOR) usart1_rx(void)
{
nmeabuffer[i] = RXBUF1;
i += 1;
}
Ist das im signal.h drin? Da steht nämlich überhaupt nichts von UART1RX
Mein Signal.h sieht folgenermassen aus (Attachment)
Danke, die sind da, wenigstens schonmal das...
Ich werde es wohl aufgeben, glaube ich habe einfach zu wenig Ahnung und
wenn ich nicht mal das auf die Reihe kriege, dann lass ich es lieber
ganz bleiben. Schade um die 100te Stunden die ich bereits investiert
habe, aber es nützt nichts, ohne einen Code der läuft komm ich nicht
weiter
Gruss
Was soll das hier?
IFG1 &= ~UTXIFG1; // Initales interrupt-flag loeschen
Das hier in init_uart_1 kann nicht funktionieren:
UBR00=0x68; // 9600 Baud aus 1MHz erzeugen
UBR10=0x00;
UMCTL0=0x04;
... das sind die Register von Uart0.
Warum schaltest Du an zig verschiedenen Stellen den Watchdog wieder und
wieder aus, ein Tritt sollte dem Vieh doch genügen ...
Sach ich ja die ganze Zeit. Er baut an zu vielen Stellen gleichzeitig
und verliert total den Überblick. Lieber erst mal immer eins nach dem
anderen zum Laufen bringen.
Und Aufgeben? Wassn das für ne Einstellung???
Hallo zusammen
Danke dafür das Ihr Euch so viel Zeit für mich nehmt. Ich hatte heute
einen rieeeeese sch..... Tag, und irgendwie fragte ich mich wieso ich
das eigentlich mache. Arbeite 100% also 43h, gehe noch 18h pro Woche zur
Schule und dann habe ich halt auch noch private Projekte. Das soll keine
Ausrede für meine obenstehende Aussage sein, aber es musste halt mal
raus :o)
Wegen dem Wachhund: Ich dachte mir so läuft es und ich wollte zuerst die
UART hin bekommen und danach alles aufräumen. Gibt noch mehrere Sachen
die da anstehen, darum blieb es vorerst drin.
Was ich noch nicht geschnallt habe, auch durch mehrere Berichte die ich
gelesen habe.
Wieso muss ich _EINT(); machen und danach noch explizit den
entsprechenden Interrupt einschalten? Also diese Zeile z.B.
IE2 |= URXIE1; // TX- und RX-interrupts anschalten
Was hat das für einen Sinn? Heisst _EINT(); das ich einfach mal
grundsätzlich Interrupts zulasse und danach läuft noch kein einziger,
wenn er nicht noch explizit gesetzt wurde?
Ein Interrupt ist ja ein Zeiger auf eine bestimmte Adresse wenn ich das
richtig verstanden habe, wie weiss der MSP dann wo er weiterfahren soll?
Wird das über den Interruptnamen gemacht? UART1RX_VECTOR
Ich werde den Code morgen gleich ausprobieren!
Gruss reflection
PS: Werde sonst morgen den Code überarbeiten und mal alle Watchdogs und
IFG1... rausnehmen, vielleicht wird es dann übersichtlicher
> Heisst _EINT(); das ich einfach mal> grundsätzlich Interrupts zulasse
Ja.
> und danach läuft noch kein einziger,> wenn er nicht noch explizit gesetzt wurde?
Ja.
Du musst das so sehen, es gibt Interruptquellen (die verschiedenen
Hardwaremodule) und eine Interrupt"senke", den Prozessor.
Die "Senke" schaltest Du mit _EINT() scharf, die Interruptquellen kannst
Du einzeln aktivieren.
_EINT() ist nur ein Macro, das das Bit GIE im Prozessorstatusregister
setzt.
> Ein Interrupt ist ja ein Zeiger auf eine bestimmte Adresse wenn ich das> richtig verstanden habe,> wie weiss der MSP dann wo er weiterfahren soll?> Wird das über den Interruptnamen gemacht? UART1RX_VECTOR
Nun, der Prozessor hat eine Tabelle, in der (Programm-)Adressen stehen,
die aufgerufen werden, wenn der zugehörige Interrupt ausgelöst wird.
Das sind die sogenannten Interruptvektoren.
Und die werden der Einfachheit halber über ihre Namen angesprochen. Die
sind im Datenblatt/Programmierhandbuch definiert.
Der C-Compiler hat eine (nichtportable) Spracherweiterung beigeschnallt
bekommen, mit dem ihm mitgeteilt werden kann, daß der Code einer
Funktion eine Interruptroutine ist und daß die Startadresse dieser
Funktion in der Interrupttabelle an einer durch den Vektornamen
definierten Stelle einzutragen ist.
Vielen Dank für die ausführliche Info! Jetzt ist es sogar mir klar
(glaube ich im Moment zu mindest...)
Das würde dann aber heissen, das der Speicher "begrenzt" ist für so eine
Interrupt Routine, oder? Wenn ich sagen wir mal rel. viel machen möchte
wenn ein Interrupt auslöst wird, muss ich das dann in eine eigene
Funktion schreiben und beim Interruptaufruf nur diese aufrufen?
Gruss reflection
> Das würde dann aber heissen, das der Speicher "begrenzt" ist für so eine> Interrupt Routine, oder?
Nein. Die Interrupttabelle selbst enthält für jeden möglichen Interrupt
genau einen Eintrag, und der besteht nur aus einer Adresse, dem
sogenannten Interruptvektor.
Auf einem MSP430 sind das exakt zwei Bytes.
Dort bietet die Tabelle Platz für 16 Einträge und liegt im Adressraum
von 0xFFE0 bis 0xFFFF. Sie ist beispielsweise im User's Manual der
1xx-Reihe auf Seite 2-13 beschrieben.
In dieser Tabelle werden die Adressen der Interruptbehandlungsfunktionen
gespeichert, nicht der Code der Funktionen selbst.
Um das Eintragen der Adressen kümmert sich erfreulicherweise der
Compiler, der erzeugt auch die korrekten Aufrufbedingungen für
Interruptfunktionen (Rückkehr mit RETI statt RET, Aufräumen des Stacks
etc.).
> Wenn ich sagen wir mal rel. viel machen möchte> wenn ein Interrupt auslöst wird, muss ich das dann in eine eigene> Funktion schreiben und beim Interruptaufruf nur diese aufrufen?
Nein (s.o.).
Übrigens ist es aus Timinggründen nicht empfehlenswert, besonders viel
Code oder besonders lange Vorgänge in einer Interrupbehandlungsfunktion
auszuführen. So etwas sollte man in die Hauptschleife auslagern und eine
sinnvolle Kommunikation zwischen Interruptbehandlungsfunktion und
Hauptschleife implementieren.
Was nämlich geschieht, wenn der zeitliche Abstand zwischen dem Auslösen
des Interrupts kürzer ist als die Laufzeit der
Interruptbehandlungsfunktion?
Eben. Daher wird eine Uart-RX-Funktion empfangene Daten in einen Puffer
schreiben und ein Flag setzen, daß Daten da sind, eine Auswertung der
Daten oder gar eine Reaktion darauf aber erfolgt in der Hauptschleife.
Also, glaube es läuft! *schonmalfreu!*
void init_uart_1(void)
{
P3SEL |= 0xC0; // P3.6 und 3.7 als USART1 TXD/RXD
UCTL1 |= SWRST;
ME2 |= UTXE1 + URXE1; // TX- und RX-Modul einschalten
UCTL1 |= CHAR; // 8 data bits, 1 stop bit, no parity
(8N1)
UTCTL1 |= SSEL0; // UCLK als ACLK festlegen / UCLK =
1MHz
UBR01=0x68; // 9600 Baud aus 1MHz erzeugen
UBR11=0x00;
UMCTL1=0x04;
UCTL1 &= ~SWRST; // USART freigeben
IE2 |= URXIE1; // RX-interrupts anschalten
_EINT();
}
Hier dann die Interrupt Routine
interrupt (UART1RX_VECTOR) usart1_rx(void)
{
nmeabuffer[i] = RXBUF1;
i += 1;
}
Ich sehe nun das Daten in den nmeabuffer geschrieben werden. Nun zu
meinem nächsten Prob:
Das GPS Modul sendet jede Sekunde einen vollständigen Datensatz. Ich
habe im Moment 9600baud, das kann ich aber auch noch etwas schneller
machen. Wenn ich nun das Prog laufen lasse hat er grundsätzlich immer
Interrupts von RX und mein Prog läuft gar nie weiter, also er ist
nonstop mit diesem Interrupt beschäftigt. Was kann man dagegen tun?
Statt Interrupt, Polling? Wie würde das funktionieren? Das GPS sendet ja
konstant Daten. Ich gehe einfach jedes mal wenn ich while(1) durchlaufe
schauen ob was angekommen ist? Es kann ja dann sein das ich, wenn mein
Prog blöd gesagt 1s durchläufzeit hät, Daten verliere oder Daten doppelt
habe.
Wie würded ihr das Prob lösen?
Gruss und nochmals vielen Dank! Ihr seit die Besten!
reflection
Na wie schon gesagt, du musst dir überlegen, was momentan wichtig ist,
abzuarbeiten. Solange du noch keinen kompletten Datensatz vom GPS
zusammen hast, musst du alle anderen Aufgaben sein lassen und warten,
bis die Daten vollständig sind. Dann musst du diese Daten verarbeiten,
und in dieser Zeit den GPS-UART-Interrupt ausschalten. Erst wenn du
alles andere erledigt hast, den Int wieder einschalten und auf den neuen
Datensatz warten, geht ja immer mit $ los und endet mit CR+LF.
Einsortieren macht ja auch keinen Sinn, wenn du irgendwo in der Mitte
gerade bist, du musst halt erst mal warten bis ein $ kommt, dann den
Zeichenzähler auf Null setzen, und Daten einlesen. Ist die Zeile, die du
haben willst vorbei, wird das Einlesen gestoppt.
Was passiert hier, wenn der Wert i größer wird, als die Anzahl der im
Array nmeabuffer zur Verfügung stehenden Einträge (minus eins)?
Genau, ein "buffer overflow".
eieiei Na da hast Du natürlich recht, ich frage in meiner While(1)
jedes mal i ab und lösche den nmeabuffer wenn er voll ist. Da er aber
nie mehr da rauskommt wird er natürlich auch nicht wieder auf 0 gesetzt.
Ich habe mir das so vorgestellt
while(1) läuft
Interrupt tritt auf
Interruptroutine wird abgearbeitet (also 1Byte geschrieben)
Dann läuft while(1) weiter
der nächste Interrupt kommt
Interruptroutine wird abgearbeitet (also 1Byte geschrieben)
Dann läuft while(1) weiter
So wie es scheint tritt aber sobald der erste Interrupt abgearbeitet ist
bereits der nächste ein...
Die anderen Sachen (Beschleunigungsmessung 3-Achsen, 3x Gyro, serielle
Schnittstelle zu PC, LCD) sollen halt schon rel. hohe Prio haben. Das
GPS muss das nicht haben. Ich habe gelesen das jede Sekunde ein
Datensatz kommt und dieser bei 9600baud ca. 0.8s dauert bis er
übertragen ist. Das is natürlich ein bisschen lang.
Ich denke ich muss mir überlegen die GPS Daten auf einem eigenen uP
einzulesen und zu verarbeiten. Was meint ihr?
Gruss reflection
> So wie es scheint tritt aber sobald der erste Interrupt abgearbeitet ist> bereits der nächste ein...
Das würde bedeuten, daß Du irgendwo massive Probleme mit der
Verarbeitungsgeschwindigkeit hast.
UART-Empfang mit 9600 Baud erzeugt knapp 1000 Interrupts pro Sekunde,
und der Code in Deiner Interruptbehandlungsfunktion ist nicht wirklich
umfangreich.
Wenn da wirklich Interrupt auf Interrupt folgt, würde das bedeuten, daß
Dein msp430 mit einem Systemtakt im kHz-Bereich arbeitet, also nur
wenige Instruktionen pro Millisekunde ausführen kann.
Uhrenquarz? Falsche Initialisierung?
Andererseits scheinst Du ja die korrekte Baudrate zu erzeugen, daher ist
mir das Phänomen schleierhaft.
Also ich habe einen 8MHz Quarz an der Kiste dran. Den Takt habe ich noch
rel. langsam gewählt (1Mhz / SPI 500kHz und UART 9600baud) damit ich da
nicht irgendwelche Probs bekomme (Freiluftverdrahtung /
Lochrasterplatine), den schraube ich schon noch rauf wenn alles läuft.
Ob immer gleich ein Interrupt den anderen folgt weiss ich nicht, aber
wenn ich mit dem Debugger einen Breakpoint in der Interuptroutine setze
sehe ich das er Daten holt und diese in den nmeabuffer schreibt. Wenn
ich einen weiteren Durchlauf mache bleibt er wieder stehen in der
Interruptroutine.
Ich habe noch folgendes rausgefunden:
Wenn ich den MSP starte macht er noch folgendes, aber er löscht das
Display nicht mehr clearLCD(); der Text bleibt einfach immer stehen und
er läuft nicht weiter. Liegt das vielleicht an meinem Delay? Dieses ist
ca. 1.25s. Was passiert genau wenn während eines solchen Delays der
Interrupt auftritt? Ach ja, der UART1 wird natürlich vor diesen Zeilen
initialisiert.
init_LCD(); // LCD initialisieren
ZeilePosition(1,3); // 1. Zeile 3. Position
sendString("reflectionRacing");
ZeilePosition(2,8); // 2. Zeile 8.Position
sendString("G-Sens");
ZeilePosition(4,3); // 4. Zeile 3.Position
sendString("Ver. 0.1.2 Beta");
delay(25000);
clear_LCD();
Gruss reflection
Die Kunst ist, an den passenden Stellen Interrupt-Quellen ein- und
auszuschalten, um verschachtelte Ints, priorisierte Ints oder eben den
richtigen Programmablauf zu erzielen. Da von uns keiner wissen kann, was
genau deine Mimik da machen soll, ist es müßig, dir den Code vorzukauen.
Das musst du selber machen.
Wenn Daten auf dem Display ausgegeben werden sollen, macht es keinen
Sinn, das per While Schleife so schnell es geht zu machen. Da reicht ein
Timer-Interrupt alle 500ms oder sowas. Desweiteren sollte man die NMEA
Daten schon so schnell wie möglich vor-sortieren, macht ja keinen Sinn,
alles zu speichern, wenn man nur die Position braucht....Vielleicht ist
so ein kleiner MSP mit 8MHz bei so vielen Sachen einfach zu
langsam....das musst du aber selbst entscheiden....wenn man alle 10ms
die Beschleunigung messen will, und dann auch noch Float-Werte benutzt,
naja, kein Wunder....
@ reflection (Gast)
>sehe ich das er Daten holt und diese in den nmeabuffer schreibt. Wenn>ich einen weiteren Durchlauf mache bleibt er wieder stehen in der>Interruptroutine.
Ohje. Breakpoints und Interrupts vertragen sich nicht sonderlich. Dein
Debugger kann kaum eine Echtzeitemulation machen.
>Wenn ich den MSP starte macht er noch folgendes, aber er löscht das>Display nicht mehr clearLCD(); der Text bleibt einfach immer stehen und>er läuft nicht weiter. Liegt das vielleicht an meinem Delay? Dieses ist
Das ist keine echte Initialisierung. Die geht anders. Sind dort die
Zeiten eingehalten?
@ Christian Richter (supachris)
>Die Kunst ist, an den passenden Stellen Interrupt-Quellen ein- und>auszuschalten, um verschachtelte Ints, priorisierte Ints oder eben den
Priorisierte Interrupst sind was für Leute die wissen was sie tun. Der
OP gehört (noch) nicht dazu.
>Sinn, das per While Schleife so schnell es geht zu machen. Da reicht ein>Timer-Interrupt alle 500ms oder sowas. Desweiteren sollte man die NMEA
Ja, wobei die Ausgabe NICHT im Interrupt erfolgt, sondern in der
Hauptschleife, getriggert über ein Flag aus dem Interrupt.
>alles zu speichern, wenn man nur die Position braucht....Vielleicht ist>so ein kleiner MSP mit 8MHz bei so vielen Sachen einfach zu
Kaum. Bei halbwegs gescheiter Programmierung langweilt der sich ohne
Ende.
>langsam....das musst du aber selbst entscheiden....wenn man alle 10ms>die Beschleunigung messen will, und dann auch noch Float-Werte benutzt,
Float braucht man selten.
Festkommaarithmetik
MFG
Falk
Ja, sach ich ja, er hat anscheinend kein schlüssiges Software-Konzept
gemacht.Da kann das ja nicht gescheit klappen. Und erst UART Int für
GPS-Daten freischalten, dann die wait() Funktion für´s Display...naja,
ohne Worte.
Hm, da gibts wohl noch sehr viel zu machen! Werde ich auch, aber brauche
halt für alles ein bisschen mehr Zeit :o)
Danke noch einmal an alle die mich tatkräftig unterstützt haben.
Gruss reflection
reflection wrote:
> GPS muss das nicht haben. Ich habe gelesen das jede Sekunde ein> Datensatz kommt und dieser bei 9600baud ca. 0.8s dauert bis er> übertragen ist. Das is natürlich ein bisschen lang.
Das heist aber nicht, dass dein µC ganze 0.8s damit beschäftigt
ist über die UART zu empfangen.
Dazu hast du ja gerade den Interrupt. Wenn ein Zeichen vollständig
ist, kommt der Interrupt, der µC verbraucht ein paar µs darauf
das Zeichen zu verarbeiten und weiter gehts mit anderen Dingen.
Von den 0.8s die die Übertragung eines Datensatzes braucht,
wendet dein µC gerade mal ein paar zig µs (verteilt auf diese
0.8s) darauf auf, die Daten zu empfangen.
> Ich denke ich muss mir überlegen die GPS Daten auf einem eigenen uP> einzulesen und zu verarbeiten. Was meint ihr?
Quatsch.
reflection wrote:
> GPS muss das nicht haben. Ich habe gelesen das jede Sekunde ein> Datensatz kommt und dieser bei 9600baud ca. 0.8s dauert bis er> übertragen ist. Das is natürlich ein bisschen lang.
Das wären ja bei kontinuierlicher Übertragung etwa 768 Byte. Ist das so?
MfG
Falk
>> GPS muss das nicht haben. Ich habe gelesen das jede Sekunde ein>> Datensatz kommt und dieser bei 9600baud ca. 0.8s dauert bis er>> übertragen ist. Das is natürlich ein bisschen lang.>Das wären ja bei kontinuierlicher Übertragung etwa 768 Byte. Ist das so?
Naja, kommt drauf an wie man zaehlt und was man unter "Datensatz"
versteht;)
NMEA-Daten werden in sentences uebertragen, GGA, GSV, RMC usw.
Jeder einzelne NMEA Datensatz kann dabei bis zu 82 Byte lang sein:
At 4800 b/s you can only send 480 characters in one second. Since an
NMEA sentence can be as long as 82 characters you can be limited to less
than 6 different sentences.
Deshalb senden praktisch alle GPS Module und auch die GPS Maeuse nur 4-5
NMEA Datensaetze damit es ueberhaupt innerhalb einer Sekunde update rate
machbar ist bei 4800 Baud.
Bei 9.6 hat man etwas mehr Luft.
Der Trick besteht aber letztlich darin das Modul so zu konfigurieren
dass es genau den einen Datensatz schickt den man braucht statt den erst
spaeter im uC rauszufiltern.
GGA z.B. ist nur 64 Byte gross und enthaelt alle Positionsdaten.
Wenn man dann noch mit 9.6 arbeitet dauert die Uebertragung nur rund 55
Millisekunden.
Noch geschickter ist es gleich auf NMEA zu verzichten und dafuer das
proprietaere Protokoll, in diesem Falle uBX, zu verwenden. Da hat man
fixe Datensatzlaengen. NMEA Datensaetze dagegen haben keine fixe Laenge,
fehlende Daten werden naemlich nicht durch Nullen ersetzt sondern
schlicht ausgelassen. Man muss also immer brav die Kommata zaehlen um
auch sicher bestimmte Daten zu erwischen. Das ist aufwendiger.
Das Pendant zu GGA ist die uBx
juergen
>> GPS muss das nicht haben. Ich habe gelesen das jede Sekunde ein>> Datensatz kommt und dieser bei 9600baud ca. 0.8s dauert bis er>> übertragen ist. Das is natürlich ein bisschen lang.>Das wären ja bei kontinuierlicher Übertragung etwa 768 Byte. Ist das so?
Naja, kommt drauf an wie man zaehlt und was man so unter "Datensatz"
versteht;)
NMEA-Daten werden in sentences uebertragen, GGA, GSV, RMC usw.
Jeder einzelne NMEA Datensatz kann dabei bis zu 82 Byte lang sein:
At 4800 b/s you can only send 480 characters in one second. Since an
NMEA sentence can be as long as 82 characters you can be limited to less
than 6 different sentences.
Deshalb senden praktisch alle GPS Module und auch die GPS Maeuse per
default nur 4-5 NMEA Datensaetze damit es ueberhaupt innerhalb einer
Sekunde update rate machbar ist bei default 4800 Baud.
Bei 9.6 hat man etwas mehr Luft.
Der Trick besteht aber letztlich darin das Modul so zu konfigurieren
dass es genau den einen Datensatz schickt den man braucht, statt erst
alle zu empfangen und den einzigen den man davon braucht erst spaeter im
uC rauszufiltern.
Die entsprechende NMEA Konfiguration macht man bei u-blox mit dem
CFG-MSG command, nachzulesen im ANTARIS Protocol Spec Dokument
GPS.G3-X-03002-D
GGA z.B. ist nur 64 Byte gross und enthaelt alle Positionsdaten.
Wenn man dann noch mit 9.6 arbeitet dauert die Uebertragung dafuer nur
rund 55 Millisekunden.
Noch geschickter ist es, gleich auf NMEA zu verzichten und dafuer das
proprietaere Protokoll, in diesem Falle uBX, zu verwenden. Da hat man
fixe Datensatzlaengen. NMEA Datensaetze dagegen haben keine fixe Laenge,
fehlende Daten werden nicht durch Nullen ersetzt sondern schlicht
ausgelassen. Man muss also immer brav die Kommata zaehlen um auch sicher
bestimmte Daten zu erwischen. Das ist aufwendiger.
Das Pendant zu GGA ist die uBX Message NAV-POSLLH mit gerade mal 28 Byte
fixe Laenge ;)
juergen