Hallo Leute, ich habe folgendes Problem mit Eclipse und dem gcc-Compiler. Ich möchte gerne printf benutzen um Text und Zahlen über die serielle Schnittstelle meines MSP430 ausgeben. Leider bekomme ich nicht eindeutige Fehlermeldungen: msp430-gcc -mmcu=msp430x149 -otest ./test.o /cygdrive/c/Programme/mspgcc/bin/../lib/gcc-lib/msp430/3.2.3/../../../.. /msp430/lib/msp2/libc.a(printf.o): In function `printf': /f/prog/msp430/sf/packaging/build/msp430-libc/src/stdlib/printf.c:39: undefined reference to `putchar' make: *** [test] Error 1 Da ich bis jetzt immer mit einem 8051 gearbeitet habe, ist mir die Eclipse Umgebung neu. Kann es sein das es printf beim gcc nicht gibt? In der stdio.h taucht aber ein Eintrag auf, den ich aber nicht verstehe: int __attribute__((format (printf, 2, 3))) uprintf(int (*func)(int c ),const char *fmt, ...); int __attribute__((format (printf, 3, 4))) snprintf (char *buf, size_t size, const char *fmt, ...); int __attribute__((format (printf, 2, 3))) sprintf (char *buf, const char *fmt, ...); int __attribute__((format (printf, 1, 2))) printf(const char *string, ...); int vuprintf(int (*func)(int c), const char *fmt0, va_list ap); int vsnprintf(char *dest, size_t maxlen, const char *string, va_list ap); int vsprintf(char *dest, const char *string, va_list ap); int vprintf(const char *string, va_list ap); Über jede Hilfe bin ich sehr dankbar.
Die Fehlermeldung, auf die es ankommt, ist die hier: In function `printf': undefined reference to `putchar' Das bedeutet, daß die von printf benötigte Funktion "putchar" nicht existiert. Die musst Du zur Verfügung stellen. printf etc. ist dem Compiler sehr wohl bekannt, nur müssen die Zeichen ja auch irgendwohin geschickt werden - und dafür ist die putchar-Funktion zuständig. Schreibe eine, die die übergebenen Zeichen auf die serielle Schnittstelle ausgibt (die musst Du natürlich vorher noch irgendwie initialisieren), und die Linkerfehlermeldung verschwindet ... und printf funktioniert.
Hallo Rufus, danke für die schnelle Antwort! Ich dachte das putchar schon implementiert ist, da in der stdio.h schon folgendes steht: int puts(const char *s); int putchar(int c); liege ich da falsch? Danke.
Ja, da liegst du falsch. DU mußt putchar definieren, damit GCC weiß, wohin er deinen Text schicken soll.
Hat vielleicht schon jemand solch eine putchar-Funktion geschrieben? Die serielle Schnittstelle habe ich bereits initialisiert und die funktioniert auch supi. Danke!
Na, wenn sie "supi" funktioniert, dann hast Du schon eine putchar-Funktion, auch wenn die vielleicht noch anders heißt. Den Prototypen hast Du ja schon gefunden, benenne also Deine "gib ein Zeichen auf der seriellen Schnittstelle aus"-Funktion entsprechend um ... und dann funktioniert auch printf "supi".
Das Problem ist nur, dass ich in meiner Funktion nur einzelne Zeichen sende! Was mache ich wenn ich eine float-Zahl habe und diese übertragen will?
Na, Du rufst printf auf - das macht aus Deiner Zahl einen schön formatierten String und ruft für jedes einzelne Zeichen daraus Deine "gib ein Zeichen aus"-Funktion auf. Wo ist das Problem?
Okay, ich schiebe in putchar einfach ein Zeichen in den TXBUF. Ich bekomme aber nur Bruchstücke von meiner Zeichenkette, die ich per printf an die serielle Schnittstelle schicke! Woran liegt das?
> Okay, ich schiebe in putchar einfach ein Zeichen in den TXBUF
Wenn du das wirklich machst, dann überläufst du den TXBUF.
Deine Funktion sollte vielleicht warten, bis dir die Hardware
signalisiert, dass sie bereit ist ein neues Zeichen anzunehmen.
Deine Funktion funktionierte anscheinend doch nicht so supi
(Konnte mir das nicht verkneifen :-)
Daran, daß Du in putchar nicht nach dem "Zeichen in den TX-Buf-Schieben" darauf wartest, daß das Zeichen auch wirklich übertragen wurde. Dazu wirst Du ein Statusbit der UART abfragen müssen. Das könnte TXIFG heißen, aber so firm bin ich beim msp430 nicht, daß ich das mit Sicherheit wüsste.
Okay, ich frage jetzt das Statusbit ab welches meldet das der TX-Puffer leer ist. int putchar(int c) { while(!(UTXIFG0)); TXBUF0 = c; return 0; } Klappt aber immernoch nicht! Es kommen nur Bruchstücke der Zeichenkette im Hyperterm an. Hab ich noch 'nen Denkfehler?
Wieso liest du nicht mal die C-Demos von TI? Da steht doch ganz klar drin, wie man die UART im Polling betreibt: Müsste bei dir dann heißen: int putchar(int c) { while (!(IFG1 & UTXIFG0)); // USART0 TX buffer ready? TXBUF0 = (unsigned char)c; return 0; } Polling ist allerdings ziemlich schlechte Programmierweise, lieber einen Buffer anlegen, das erste Zeichen direkt schicken und alle weiteren per TX-Interrupt abholen lassen. Du kommst aus der PC-Programmier-Ecke, oder? Bei µC linkt man normalerweise nicht einfach mal so nen riesen Brocken von lib wie die stdio dazu. Da ist ja gleich massenhaft an Flash und RAM weg....das kann man selber auch viel kürzer schreiben, wenn man nicht alle Funktionen braucht.
Hallo Christian! Ich komme eher aus der Elektronik-Ecke und brauche das printf "nur" zum debuggen. Leider funktioniert die Funktion so wie Du sie gepostet hast auch nicht! Wie würde ich das denn mit Interrupts lösen?
Wenn das nicht klappt, muss es am printf() liegen. Diese Funktion schickt einfach jedes Zeichen, wenn der Buffer frei ist. Da geht nix verloren. Mit INT? Naja, du musst erst alle Zeichen in einen Buffer einsortieren, dann das erste schicken, und bei jedem TX-Interrupt ein weiteres, bis alle ist. Das ganze kann man natürlich auch mit einem Ringpuffer machen, aber das is bissl aufwendiger.
Das komische ist, wenn ich die selbst geschriebene putchar-Funktion(siehe 3 Threads weiter oben) allein teste, also zum Beispiel: putchar('X'); dann kommt das X nicht auf dem Hyperterminal an! Das ist doch sehr komisch oder!? Hat da noch jemand eine Idee dazu?
Dann ist die Baudrate falsch konfiguriert oder das Kabel kaputt oder sowas. Hast du einen Quarz als Taktquelle dran? Mit dem RC-Oszillator klappt die UART erst nach viel rumspielen mit dem Baudratenteiler. Und dann ist das auch temperatur-abhängig
Ja, ich benutze einen 8MHz Quarz und das Kabel ist in Ordnung! Wenn ich mir nämlich ein char-array fest definiere und dieses per Tastatureingabe und mit Hilfe von Interrupts ausgebe funktioniert es einwandfrei. Ich habe als Referenz das "echo"-Programm von www.mathar.com genommen und auf eclipse+gcc angepasst. Und wie gesagt, das läuft super mit 115200 BAUD! Ich bin am verzweifeln! :-(
Also irgendwie funktioniert die Abfrage: while(!(IFG1 & UTXIFG0)); nicht! Die while-Schleife wird nie verlassen. Warum nicht? Kennt sich nicht irgendjemand damit aus? Das ist doch eine ganz normale Schleife mit Abfrage! Der Compiler macht auch keine Fehler. Gibts da bei eclipse irgendwelche Besonderheiten? Hiermal meine Initialisierung der UART: void initUART(void) { P3SEL = 0x30; // P3.4 und P3.5 als USART0 TXD/RXD ME1 |= UTXE0 + URXE0; // TX- und RX-modul erst mal anschalten UCTL0 |= CHAR; // 8 data bits, 1 stop bit, no parity UTCTL0 |= SSEL0; // ACLK als UCLK festlegen UBR00 = 0x45; // 115200 baud aus 8MHz erzeugen UBR10 = 0x00; UMCTL0 = 0xAA; UCTL0 &= ~SWRST; // USART freigeben IE1 |= URXIE0 +UTXIE0; // TX- und RX-interrupts anschalten IFG1 &= ~UTXIFG0; // interrupt-flag loeschen }
Hmmm, zwei Anmerkungen: ACLK als Taktquelle stimmt wirklich? Wenn der TX Interrupt aktiv ist, wird das UTXIFG0-Flag automatisch (Ack) beim Einsprung in die ISR gelöscht - dein Polling kann niemals ein gesetztes Flag sehen... Schau mal ins User Manual (SLAU49E.pdf), Seite 277. Ahoi, Martin
Mit UTCTL0 |= SSEL1; hast du deinen 8Mhz Clock als Takt. Dann klappts auch mit den 115,2KBaud. Ist im C-Demo von TI falsch. Und wie Martin schon sagte, Polling und Interrupt zusammen wird nicht klappen. Nur, wenn du das erste Zeichen sendest, nach dem ersten, wird die ISR angesprungen und das Flag gelöscht.
Ja, ACLK als Taktquelle stimmt! Kannst Du mir sagen wie ich das lösen kann?
Aus dem ACLK bekommst du doch aber keine 115.200 raus. Da musst du schon vorher den XT2-Oszillator zuschalten und den SMCLK auf die 8MHz vom Quarz legen. Oder den DCO mit dem ACLK füttern, eine passende Frequenz einstellen und daraus die Baudrate generieren. Schau dir mal das C-Demo fet140_uart01_0115k_2.c an.
Mein ACLK läuft auf 8MHz von XT1, damit speise ich den Baudratengenerator der mit 115200 BAUD läuft! Warum sollte das nicht gehen??? Kann mir jemand sagen, wie ich ohne Interrupts zu benutzen, abfragen kann ob der Sende-Puffer schon frei ist?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.