Hallo Softwarefreunde :) Ich habe ein kleines Problem mit dem GCC-Tutorial. Es geht um den Bereich "Uart-String senden". Dort gibt es mehrere Möglichkeiten dies zu realisieren. Den "normalen" Weg mit uart_puts habe ich verstanden und es funktioniert auch bei mir. Nun möchte ich die Printf- Variante testen. Dort steht folgendes dazu: /* verwenden der printf-lib: */ int main(void) { /* initialisieren der UART */ uart_init(); /* stream öffnen */ fdevopen(uart_putc, NULL, 0); /* printf... */ printf("%s: stdout erfolgreich auf UART umgeleitet\n", _FUNCTION_); /* exit... */ return 0; } Nun zu meinem Problem. Mein AVR-Studio meckert rum, dass es diese Library nicht finden kann (die printf-Lib). Im AVR-Ordner konnte ich sie selbst auch nicht finden. Ich brauche sie aber, um die Funktionen fdevopen und printf nutzen zu können. Wie kann ich diese Library nun in meinen Code einbinden? Hoffe ihr habt mein Problem verstanden. Ich danke euch schon einmal für eure Hilfe! Gruß Marian
printf() ist Bestandteil der normalen C-Bibliothek. Wenn dein AVR-Studio sich über irgendwas beklagt, solltest du bitte die Fehlermeldung posten. (Es gibt separate Bibliotheken mit einer aufgerüsteten Version von printf() für Gleitkomma-Ausgaben und mit einer abgerüsteten, um ein bisschen ROM zu sparen, aber die sind hier erstmal nicht relevant.)
Hm...das dachte ich mir auch schon. Is mir schon ganz schön peinlich, ich habe vergessen, die stdio.h einzubinden. Nun erkennt er die Befehle logischerweise. Bin halt noch ein Anfänger :(. Jedenfalls funktioniert es jetzt. Jetzt habe ich aber eine andere Frage. Was macht _FUNCTION_ in der printf-Anweisung? Wenn ich es weglasse, wird nichts mehr gesendet. Das NULL,0 in der fdevopen habe ich auch nicht verstanden. Kannst du mir das bitte mal erklären? Es gibt leider keinerlei Erläuterung dazu. Danke und Gruß Marian
_FUNCTION_ wird durch den Funktionsnamen ersetzt, in der du grad bist. In deinem Fall also mit "main".
> Was macht _FUNCTION_ in der printf-Anweisung? _FUNCTION_ ist eine GCC-Erweiterung zum Standard. Dieser Präprozessor-Makro wird automatisch zu einem String-Literal mit dem Namen der aktuellen Funktion ("main" also in deinem Falle) erweitert, sodass man ihn als Text benutzen kann. Vom Standard offiziell vorgesehen sind _FILE__ und __LINE_ für den Dateinamen und die Zeilennummer, an der sie sich gerade befinden. Du kannst das also auch erweitern zu: printf("Das ist Datei %s, Zeile %d in Funktion %s\n", _FILE_, _LINE_, _FUNCTION_); > Das NULL,0 in der fdevopen habe ich auch > nicht verstanden. Das NULL (ein Makro, der einen Null-Zeiger kennzeichnet) steht als Platzhalter dafür, dass du keine Eingabefunktion mit übergeben hast, sondern nur eine für die Ausgabe. Die abschließende 0 steht für einen dritten Parameter, der für Erweiterungen der Funktionalität vorgesehen war, aber nie benutzt worden ist. Da wir in avr-libc 1.4 das API ohnehin umgebaut haben, haben wir den dritten Parameter dort auch gestrichen.
Nochmals Danke Jörg! Ich habe gerade beim suchen nach einer lösung für ein anderes Problem, den Thread gefunden, wo du das ja schonmal einem Anfänger erklärt hast. Is schon witzig, daß man das findet wonach man gar nicht sucht bzw. wenn man was anderes sucht:).
Hallo, ich habe nochmal eine Frage zu dem printf Befehl. Ich würde damit gerne eine 32 bit integer Zahl als Hex ausgeben. Leider funktioniert das nicht so wie ich es mir dachte. Wenn ich eine Variable unsigned int z übergebe, hat diese (logischerweise???) nur 16 bit. Ich habe nun versucht, eine unsigned long z zu übergeben(ich dachte damit habe ich 32 bit) aber damit kommt der printf Befehl nicht klar. Er möchte halt einen Integer-Wert haben, da ich ja in Hex umwandle(mit %08x). Nun habe ich die Doku durch und die ganzen Makros gefunden (Mit denen man die Datentypen konvergieren kann z.b. Prix8, Prix32 usw.). Leider mag mein AVR-Studio diese Makros nicht und ich komme jetzt nicht mehr weiter. Kann mir jemand helfen? Hier Ausschnitte aus meinem Code : #include <avr/io.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> typedef unsigned long int uint32_t; #define PRIx32 "lx"; int main(void) { /* initialisieren der UART */ UART_Init(); uint32_t z=0; for(;;) { /* stream öffnen */ fdevopen(uart_putc, NULL,0); /* printf... */ printf("S"lx" ms \n\r",z); srand(1); int zufall = rand() % 500; z=z+zufall; } } Diese Fehlermeldung erscheint dann: Timestamp.c:51: warning: passing arg 1 of `fdevopen' from incompatible pointer type Timestamp.c:54: error: parse error before "lx" make: *** [Timestamp.o] Error 1 Build failed with 1 errors and 1 warnings... Langsam verzweifel ich an der 32 bit Ausgabe. Wenn ich es normal mit %08x ausgebe, gibt er mir immer nur 16 bit HEX aus.
Ich würde dir gern helfen, jedoch habe ich das gleiche Problem! Sorry...:(
> Timestamp.c:54: error: parse error before "lx" Wolltest du eventuell printf("S%lx" ms \n\r",z); schreiben? Das wäre dann richtig gewesen. > Timestamp.c:51: warning: passing arg 1 of `fdevopen' from incompatible pointer type Du solltest dein uart_putc() kompatibel zu den Erwartungen von fdevopen() machen...
DAnke Jörg, du warst schon so oft mein Retter ;). Anscheinend habe ich wohl die letzte Variant nicht ausprobiert, alle anderen bzgl." habe ich eigentlich getestet. C is schon komisch :). Das mit fdevopen weiß ich auch, habe auch schon viel Beiträge darüber gefunden aber irgendwie hauen eure Lösungsvorschläge nicht hin. Wenn ich meine uart_putc Routine anpasse, freut sich fdevopen aber dann meckert AVR-Studio mit der uart Funktion rum. Das kommt wenn ich " int uart_putc(char *s) " nehme: Timestamp.c:28: warning: control reaches end of non-void function Das kommt wenn ich " void uart_putc(char*s) " nehme: Timestamp.c:50: warning: passing arg 1 of `fdevopen' from incompatible pointer type Und wenn ich noch FILE* dummy (wie in dem anderen Beitrag erwähnt) eintrage, dann will er gar nicht mehr. ihr habt das ja wikrlich nett erklärt in dem anderen Beitrag aber ich steige dda noch nicht so ganz hinter...sorry.
> Timestamp.c:28: warning: control reaches end of non-void function Du sollst ja auch eine 0 zurückgeben, wenn dein uart_putc() erfolgreich war. RTFM gewissermaßen. Es gibt auch ausreichend Beispiele in der Doku... > Und wenn ich noch FILE* dummy (wie in dem anderen Beitrag erwähnt) > eintrage, dann will er gar nicht mehr. Das ist ein avr-libc 1.4 Feature. Du hast offenbar noch eine 1.2er Version.
Danke nochmals, ich werde jetzt mit den ganzen Fragen aufhören aber ich finde, diese Douks sind echt s..... geschrieben.
> Danke nochmals, ich werde jetzt mit den ganzen Fragen aufhören aber > ich finde, diese Douks sind echt s..... geschrieben. Das hilft leider niemandem. Sag, was besser gemacht werden muss, dann können wir sehen, was sich machen lässt. Alles können wir aber auch nicht ändern, nicht nur aus mangelnder man power, sondern auch, weil wir ein Tool benutzen um die Doku automatisch zu generieren, das uns leider nicht x-beliebige Freiheiten lässt. So heißt eben die Übersichtsseite nicht "Index" sondern "List of modules" oder sowas. Allerdings: bevor du meckerst, nimm bitte aktuelle Versionen. Ich finde persönlich (und habe das auch von einigen Leuten bestätigt bekommen), dass die Doku der avr-libc 1.4 mit ihren Änderungen schon ein Stück übersichtlicher geworden ist, ganz zu schweigen von den seit 1.4.1 verbesserten Demo-Programmen (es gibt jetzt auch ein stdiodemo). Dagegen, dass Leute eine Tendenz haben, mit alter Software und Doku erstmal möglichst lange weiter zu arbeiten, kann nun kein Entwickler was tun...
Ja, das ist richtig Jörg. Ich war gestern nur etwas frustriert und an deiner Antwort habe ich gesehen, daß dich meine Fragen schon ein wenig genervt haben. Zum Thema Doku: Als allererstes muss ich bemeckern, daß diese Dokus sehr unübersichtlich sind (vielleicht gehts auch nur mir so) bezüglich Inhaltsangaben usw. Und der andere Punkt: Das Problem was ich hatte, wurde in der Doku leider anders erklärt. So wie du es mir geschrieben hast, stand es nicht in der Doku drin. Deswegen war ich gestern auch ziemlich verärgert, denn dann hätte ich die 2 h, die ich so ins suchen investiert habe, sinnvoller einsetzen könnnen. Aber naja aus Fehlern lernt man eben. PS: Reicht es aus, einfach das update von Atmel.com zu installieren, um auf die neueste avr-libc upzugraden?
> Das Problem was ich hatte, wurde in der Doku > leider anders erklärt. Das musst du aber bitte erläutern. Ich finde nichts anderes dort (auch nicht in alten Versionen) als das, was ich dir geschrieben habe. Ja, einen ordentlichen Index in der PDF-Datei hätte ich auch gern, ist leider mit Doxygen wohl nicht drin. Wenn wir mal viel Zeit haben :), stellen wir das Dokumentationssytem vielleicht mal auf was anderes um (Docbook vielleicht), dann sollte sich sowas verbessern lassen. Im Moment sind wir froh, dass es zu jedem Release erstmal eine up-to-date Doku gibt, die auch alles abdeckt, was es an offiziell exportierten Interfaces in der Bibliothek gibt. > PS: Reicht es aus, einfach das update von Atmel.com zu installieren, > um auf die neueste avr-libc upzugraden? atmel.com, meinst du damit das AVR Studio? Nein, das hat zwar die Hooks für den AVR-GCC mittlerweile drin, liefert aber selbst keinen Compiler mit. Den muss man sich extern installieren, typischerweise in Form eines WinAVR. Mit dem aktuellen WinAVR hast du allerdings auch die aktuelle avr-libc einschließlich der Doku. Die Verbesserungen der Übersichtlichkeit der Doku beziehen sich übrigens auf die HTML-Version, nicht die PDF-Version. An letzterer kann ich kaum was im Layout ändern.
Hier war mein liegt mein Problem. http://www.nongnu.org/avr-libc/user-manual/group__avr__inttypes.html Und zwar genau in diesem Ausschnitt: printf("The hexadecimal value of smallval is " PRIx8 ", the decimal value of longval is " PRId32 ".\n", smallval, longval); Aufgrund der Anführungszeichen bei den Makros(PRIx8 usw.) dachte ich halt, ich muss diese auch übernehmen, denn in der Doku muss da ja richtig sein ;). Ich habe dann viel rumprobiert (mit und ohne und gemischt) aber nichts aht funktioniert. Als ich dann deine Variante sah, dachte ich: Nicht wirklich oder? Da hätte man die Anführungszeichen in der Doku ja auch mal weglassen können. Oder bin ich der einzige der das so versteht? Weißt jetzt was ich meine? PS: Ok, dann werde ich mal versuchen meine Admin zu überreden, mir das neueste WinAVR zu installieren :). Gruß Marian
Ich begreife allmählich, was du nicht begriffen hast. ;-) Hmm, ich müsste dich jetzt allerdings in den Kurs ,,Grundlagen von ANSI-C (ISO-C 1990)'' zurückschicken, zum Stichwort string literal concetanation. Du versuchst, ohne dass du dieses Feature von C verstanden hast, es mit trial&error zu benutzen. Das geht nicht gut. Sorry, so viel Zeit, das hier komplett zu erklären, habe ich auch gerade nicht (ich werde ja schließlich nicht für meine Antworten bei mikrocontroller.net bezahlt), vielleicht sollte das Thema mal jemand im Tutorial aufnehmen. Alternativ: fang einen eigenen Thread dazu an. Nur kurz: > #define PRIx32 "lx"; Lass das Semikolon weg, dann hat das eine Chance zu funktionieren. > printf("S"lx" ms \n\r",z); Wenn du das Äquivalent dafür richtig geschrieben haben willst: printf("S" "lx" "ms \n\r", z);
... und das geht natürlich nicht, weil das Prozentzeichen fehlt. Nur kurz: > #define PRIx32 "lx"; Lass das Semikolon weg, dann hat das eine Chance zu funktionieren. > printf("S"lx" ms \n\r",z); Wenn du das Äquivalent dafür richtig geschrieben haben willst: printf("S" "lx" "ms \n\r", z); Entweder #define PRIx32 "%lx" oder printf("S%" PRIx32 "ms \n\r", z); Was soll das ganze? Das ist doch ausgesprochen unübersichtlich und -ganz offensichtlich- auch 'ne wunderschöne Fehlerquelle. Tip am Rande: printf("%08lx", z); gibt führende Nullen aus. Das hilft beispielsweise bei tabellarischer Formatierung und ist bei hexadezimalen Zahlen auch sonst nicht unüblich.
HM...also bei mir hat das auch mit dem Semikolon funktioniert. Aber du hast recht, es ist ja keine Anweisung. Das mit printf ist komisch. So wie du das als letztes geschrieben hast, hatte ich es auch (glaube ich) verstanden, was ja aber nicht funktioniert hat und es immernoch nicht tut. Nur diese Variante geht: printf("S%08lx ms \n\r",z); Warum die 08 drin steht muss ich dir ja sicher nicht erklären ;)... Nochmals vielen Danke Jörg für die viele Zeit die du für mich geopfert hast. PS: Also das mit den String-Literalen versteh ich wirklich nicht. Meinst du das mir das jemand erklären würde, wenn ich einen neuen Thread dafür aufmache? Dann heißt es nur wieder: Selber googlen und nachforschen. (Also werde ich das selber tun :))
> Was soll das ganze? Das ist doch ausgesprochen unübersichtlich und > -ganz offensichtlich- auch 'ne wunderschöne Fehlerquelle. C99. Die Makros kommen aus einem Headerfile (<inttypes.h>). Damit wird erreicht, dass man printf()-Formatierungen für benannte Datentypen schreiben kann, ohne wissen zu müssen, ob ein uint32_t nun gerade ein short int, int, oder long int in der Maschinen- repräsentation ist. Ist also eigentlich nur für die Portabilität wichtig. > PS: Also das mit den String-Literalen versteh ich wirklich nicht. > Meinst du das mir das jemand erklären würde, wenn ich einen neuen > Thread dafür aufmache? Ich denke schon. Das Stichwort ist aber "Verkettung von String- Literalen", also das Zusammenziehen von "aa" "bb" zu "aabb".
OK ich habe mich jetzt darüber informiert. Nun verstehe ich auch die Schreibweise. Nur eines ist noch unklar: Bei allem was ich gefunden habe,werden Strings immer mit einem + verkettet. Z.B.: string name= "Peter" s="Der Name lautet" +name+; //"Der Name lautet Peter" Das war in der Doku auch nicht so oder irre ich mich schon wieder? Unübersichtlich finde ich es trotzdem noch :).
Was auch immer Du da gefunden haben magst, C ist das nicht. Strinverkettung mit "+" ist Java/JavaScript oder -je nach Implementierung der Klasse "string"- C++.
Achtung! Laut meiner Sourcen aus dem Arthernet Projekt gab es zumindest mit der alten avr-libc ein Problem bei der minimalistischen printf Variante. Hier ein Auszug aus dem Code:
1 | # if 1
|
2 | /* %0? does not work with minimalistic printf-variant */
|
3 | sprintf(outbuf, "%02X ", *((uint8_t *)(adr + i))); |
4 | # endif
|
5 | |
6 | # if 0
|
7 | /* Workaround for minimalistic printf-variant */
|
8 | if((*((uint8_t *)(adr + i))) >= 0x10) |
9 | sprintf(outbuf, "%X ", *((uint8_t *)(adr + i))); |
10 | else
|
11 | sprintf(outbuf, "0%X ", *((uint8_t *)(adr + i))); |
12 | # endif
|
@Rufus: Oh dann habe ich das wohl übersehen, daß das Java ist. Ich bin halt noch Anfänger aber alle Codes die ich sah, sahen für mich wie C aus. Ich hab die Seite nochmals geprüft und du hattest recht, es war eine Java Seite :(...
> Laut meiner Sourcen aus dem Arthernet Projekt gab es zumindest mit > der alten avr-libc ein Problem bei der minimalistischen printf > Variante. Problem ist gut. ;-) It's a feature. Wenn du die minimalistische printf-Variante haben willst, dann ist halt (dafür ist sie ja eben minimalistisch) genau sowas wie die Feldweite nicht implementiert. Wenn du das nicht magst, dann nimm die Standard-Variante.
Ich weis, das habe ich ja dann auch gelesen. Was ich da nicht ganz verstehe ist %p...
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.