Forum: Mikrocontroller und Digitale Elektronik [Gelöst] fprintf()/fputs() liefert nur das erste Zeichen, printf() geht (ATMega328PB)


von Sebastian R. (sebir90)


Lesenswert?

Hallo wertes kollektives Wissen!

Ich wende mich an euch, da ich bei einem kleinen Projekt ein Problem 
habe und mir keine plausible Begründung einfällt, woran es liegen 
könnte.

Ausgangssituation:
Ich verwende einen ATMega328PB mit zwei UARTs. Auf einem UART möchte ich 
einen Sensor auslesen, den anderen möchte ich dazu nutzen, den Messwert 
umgewandelt an ein Funkmodul zu übertragen. Ich nutze Atmel Studio 
7.0.1645 mit der Atmel Toolchain 7.0.895.

Als UART-Library nutze ich jene von Peter Fleury, die ich um den 
ATMega328PB erweitert habe. Darüber hinaus habe ich die Funktionen 
uart_putc und _puts um einen weiteren Parameter, nämlich "FILE *stream" 
ergänzt, um ein paar Compiler-Warnungen zu verhindern. Genutzt wird der 
Parameter nicht. Und die entsprechenden Funktionen sind nun nicht mehr 
void, sondern geben 0 zurück, wenn alles okay ist. Beides waren schon 
(kosmetische) Maßnahmen, um mein Problem zu beheben. Ohne Erfolg.

Aus Gründen der Bequemlichkeit und der Formatierung möchte ich die UARTs 
mit fprintf() ansprechen.

Anlegen der Streams der UARTs für ftprintf():
1
FILE uart0_stream = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW);
2
FILE uart1_stream = FDEV_SETUP_STREAM(uart1_putc, uart1_getc, _FDEV_SETUP_RW);

Um testweise mit dem "normalen" printf() zu arbeiten, habe ich stdout 
und -in auch noch auf den entsprechenden Stream eines UARTs umgeleitet:
1
stdout = &uart0_stream;
2
stdin = &uart0_stream;

Folgende Funktionen liefern wider Erwarten am UART nur das erste Zeichen 
des Strings (uart0 und uart1 sind dabei gleichermaßen betroffen):
1
fprintf(&uart0_stream, "Hallo");
2
fprintf(&uart0_stream, "%s", "Hallo");
3
fputs("Hallo", &uart0_stream);

Folgende Funktionen funktionieren problemlos:
1
printf( "Hallo");
2
fprintf(&uart0_stream, "H%s", "allo");
3
puts("Hallo"); //Allerdings mit LF

Basierend auf den Beobachtungen kann ich folgende Annahmen treffen:
- Die "Bitpopelei auf Fußpilzebene", also meine uart_putc-Funktionen 
funktionieren einwandfrei
- printf() funktioniert
- fprintf() funktioniert eigentlich auch
- fptintf() nutzt unter gewissen Bedingungen fputs()?
- Der Optimizer scheint für fprintf() entweder fputs() zu nutzen oder 
nicht, je nachdem, ob ein String während der Laufzeit zusammengesetzt 
werden muss oder nicht.
- fputs() scheint ne Macke zu haben.


Da ich beide UARTs nicht parallel benötige, könnte ich eine 
Wrapper-Funktion erstellen, die entsprechend dem übergeben Stream dann 
stdout und -in einstellt und intern printf() nutzt, aber das würde auch 
nur die Sympthome und nicht die Ursache beheben.


Habt ihr irgendwelche Vorschläge, an welchen Stellen ich nach der 
Ursache für das Problem suchen kann?
Habe ich einen Bug in fputs() gefunden? Aber ich bin ja nicht der erste, 
der die Funktion verwendet....


Vielen Dank!

Sebastian

von Stefan F. (Gast)


Lesenswert?

Ich vermute einen Bug in der Funktion uart_putc. Bei meinen Programmen 
(http://stefanfrings.de/avr_hello_world/index.html) funktioniert dieses 
Konstrukt nämlich ohne Probleme.

von Jim M. (turboj)


Lesenswert?

Vorsicht: Einige Libs können printf() Funktionen puffern, und senden nur 
wenn der Puffer voll oder ein \n im String ist.

von Sebastian R. (sebir90)


Lesenswert?

Hallo Stefan,

Danke für deine Antwort. In deinem von dir verlinkten Beispiel nutzt du 
jedoch puts() und nicht fputs().

Wie ich geschrieben habe, funktionieren bei mir sowohl puts() als auch 
printf() problemlos, weshalb ich davon ausgehe, dass in dem uart_putc() 
eben nicht der Fehler liegt.

von Stefan F. (Gast)


Lesenswert?

> Einige Libs können printf() Funktionen puffern

Stimmt, die "normale" avr-libc tut das allerdings nicht.

> In deinem von dir verlinkten Beispiel nutzt du
> jedoch puts() und nicht fputs().

ja, das sollte ja ein einfaches Beispiel sein. Ich hatte es aber auch 
mit fprintf() getestet. Dazu musst du die Variable "serialport" 
allerdings sichtbar machen, also das Schlüsselwort "static" entfernen 
und ein den anderen Quelltexten mit "extern FILE serialPort" zugreifbar 
machen.

probiere es mal aus. Wenn das bei Dir auch funktioniert, dann muss 
irgendwas in deinem Quelltext falsch sein. Das wirst du dann durch 
direkten vergleich sicher schnell finden.

von Sebastian R. (sebir90)


Lesenswert?

Okay. Asche auf mein Haupt.

Ich habe den Fehler gefunden. Er schreibt gerade diese Antwort.

Und ja, der Fehler lag in meiner uart_putc().

Voller Überzeugung schrieb ich ja, dass diese schon 0 zurück gibt und 
kein void mehr ist. Allerdings hatte ich den Rückgabewert als uint8_t 
ausgeführt, weil die Null da ja bequem reinpasst und auch beim Casten 
eine NUll bleiben sollte. Aufgrund der ganzen Callback-Struktur war dem 
wohl leider nicht so.

Der Rückgabewert der Funktion ist nun ein normaler signed Integer und 
alles ist gut.

Trotzdem vielen Dank an alle!

Und mein Problem ist doch nicht so übernatürlich und mysteriös, wie 
befürchtet.


Sebastian

von Bernd E. (niro)


Lesenswert?

Hallo Sebastian,

wäre sehr nett, wenn du mal sagen könntest, wie du den 328PB mit Peter 
Fleurys Library zum Laufen gebracht hast.
Ich kämpfe damit auch schon eine ganze Weile.
Beim 328P lief bei mir alles noch einwandfrei.

Ich bräuchte auch nur UART0 und auch keine Zusatzfunktionen....

Vielen Dank!!
niro

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.