Forum: Mikrocontroller und Digitale Elektronik float to string mit ftoa - komische Ausgabe


von Michael D. (sirs)


Lesenswert?

Hallo zusammen!

Für meine Ausgabe über UART hab ich mir eine funktion programmiert, die 
zwei Teile Text und eine float-Zahl übergeben bekommt. Zum testen zieht 
eine Schleife einfach immer 0.1 von n=3.141592 ab. Allerdings 
funktioniert die Ausgabe nur manchmal richtig:

Ausgabe:
1
float 3.14159                                                                
2
float 3.04159                                                               
3
float 2.28623                                                              
4
float 2.18623                                                              
5
float 2.08623                                                              
6
float 2.0/-))                                                              
7
float 2.//-))                                                              
8
float 2../-))                                                              
9
float 2.-/-))                                                             
10
float 2.24159                                                            
11
float 2.14159                                                               
12
float 2.04159                                                               
13
float 1.28623                                                            
14
float 1.18623                                                                
15
float 1.08623                                                                
16
float 1.0/-))                                                                
17
float 1.//-))                                                                
18
float 1../-))                                                               
19
float 1.-/-))                                                               
20
float 1.24159

Fast die gleiche Funktion hab ich mir schon mal gebaut, um einfache Int 
mit Text anzuzeigen, da verwende ich itoa statt ftoa. Die läuft auch 
einwandfrei. Aber was stimmt an dem Code hier nicht?? Braucht ftoa 
irgendwas besonderes um den String richtig zu kreieren?

1
uint8_t Send_UART_FloatWithText(char* textbefore, float number, char* textafter){
2
3
  char* numsend = "0.00000";
4
  ftoa(number, numsend, 5); //value, string, resolution, 5 Nachkommastellen fest
5
  uint8_t textlength = strlen(textbefore)+strlen(numsend)+strlen(textafter);
6
  
7
  if(textlength<=UART_MAXSTRLEN){
8
    char buffer[UART_MAXSTRLEN];
9
    snprintf(buffer, UART_MAXSTRLEN, "%s%s%s", textbefore, numsend, textafter); //print to buffer
10
    Send_UART(buffer);
11
  }else{
12
    Send_UART("ERROR: Text too long!");
13
  }
14
  return textlength;
15
}

Bin grad überfragt, drum frag ich euch ;)

Edit: läuft auf einem Xmega-Baustein, nuf falls wer fragt

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Michael D. schrieb:
> char* numsend = "0.00000";
>   ftoa(number, numsend, 5); //value, string, resolution, 5 Nachkommastellen fest

String-Literale (hier "0.00000") dürfen nicht überschrieben werden.
Definiere numsend stattdessen so:

1
  char numsend[8];

Edit:

Auch die ftoa-Funktion erscheint mir verdächtig. Woher kommt die? In der
AVR-Libc ist die m.W. nicht enthalten.

: Bearbeitet durch Moderator
von Michael D. (sirs)


Lesenswert?

Danke für die schnelle Antwort. Geht mit der Variante leider immer noch 
nicht. Selbes Ergebnis.

Warum ollte das so sein? Ein String ist doch auch nur ein Array aus 
Chars, oder?

Edit: ftoa war in einer lib drin, die ich eingebunden habe, genau wie 
das itoa, also irgendeine davon:

#include <stdint.h>
#include <stddef.h>
#include <avr/io.h>
#include <errno.h> //für Umwandlung str to int
#include <limits.h> //Maxima/Minima der Int,...
#include <string.h>
#include <ctype.h>  //zum Testen auf alphanumerische Zeichen und Co
#include <math.h>

: Bearbeitet durch User
von Georg G. (df2au)


Lesenswert?

Michael D. schrieb:
> ftoa war in einer lib drin

GCC kennt kein ftoa. Kann es sein, dass dein ftoa buggy ist?

von wendelsberg (Gast)


Lesenswert?

Michael D. schrieb:
1
snprintf(buffer, UART_MAXSTRLEN, "%s%s%s", textbefore, numsend, textafter);
 //print to buffer

Bau das doch mal so um, da siehst Du woher welce Zeichen kommen.
1
 snprintf(buffer, UART_MAXSTRLEN, "%s#%s#%s", textbefore, numsend,  textafter);
 //print to buffer

wendelsberg

von Dirk B. (dirkb2)


Lesenswert?

Michael D. schrieb:
> Warum isollte das so sein? Ein String ist doch auch nur ein Array aus
> Chars, oder?

Weil der Text (die Zeichen) woanders im Speicher liegt.

Stringliterale sind const char *

von Michael D. (sirs)


Lesenswert?

Dirk B. schrieb:
> Stringliterale sind const char *

Stimmt, die sind ja vorinitialisiert.

Das Problem liegt wohl wirklich in dieser ftoa, woher auch immer mein 
gcc sie kennt (arbeite übrigens nicht mit Atmel studio). Gut sichtbar an 
diesem Versuch von Wendelsberg:
float #1.08623#
float #1.0/-))#
float #1.//-))#
War mir aber auch vor dem Versuch schon klar, weil Text hat immer ohne 
Probleme funktioniert.

Gibt es jemand der eine gute ftoa geschreiben hat? Hab hier nur eine die 
irgendwie komsich ist
https://ucexperiment.wordpress.com/2016/02/23/lean-and-mean-float-to-string-conversion-ftoa/

von Michael D. (sirs)


Lesenswert?

http://www.geeksforgeeks.org/convert-floating-point-number-string/

Hab mal diese ftoa Funktion eingebaut und natürlich in myftoa umbenannt 
um Konflikte zu vermeiden. Kommt interessanterweise genau das gleiche 
Ergebnis raus.

von Georg G. (df2au)


Lesenswert?

Michael D. schrieb:
> Gibt es jemand der eine gute ftoa geschreiben hat?

Im GCC nennt sich die Funktion dtostrf()

von Michael D. (sirs)


Lesenswert?

GEIL, es geht! Danke an alle!

char numsend[8];
dtostrf (number, 3, 5, numsend);

macht die Umwandlung in einen String richtig und die kann ich dann wie 
oben aneinanderhängen. Wo dieses falsche ftoa hergekommen ist das er 
trotzdem geklannt hat? Keine Ahnung...

von Stefan K. (stefan64)


Lesenswert?

Gibt es einen Grund, warum Du nicht gleich alles von snprintf() machen 
lässt?

Viele Grüße, Stefan

von Yalu X. (yalu) (Moderator)


Lesenswert?

Michael D. schrieb:
> http://www.geeksforgeeks.org/convert-floating-point-number-string/

Diese Funktion versagt, wenn die Nachkommastellen nicht als int
darstellbar sind.

Beispiel:

In der dritten Ausgabezeile sollte 2.94159 ausgegeben werden. Die
Nachkommastellen sind 94159. Die Zahl 94159 ist aber nicht als
16-Bit-Integer darstellbar. Die Konvertierung scheint das 17. Bit
einfach abzuschneiden, so dass 94159 - 0x10000 = 28623 übrigbleibt.
Die ausgabe lautet deswegen 2.28623.

In der sechsten Ausgabezeile werden die zu int konvertierten
Nachkommastellen sogar negativ, was zu den seltsamen Symbolen führt.

Wenn du maximal vier Nachkommastellen ausgibst, sollte die Funktion
immer funktionieren.

von Michael D. (sirs)


Lesenswert?

Stefan: snprintf hat mir aus irgendeinem Grund bei %s%f%s statt des 
floats in der Mitte nur ein Fragezeichen geliefert, egal was als Float 
übergeben wurde.

Yalu: Danke für die Erklärung der komischen Zeichen! Sowas sieht man 
nicht auf Anhieb. Und es vervollständigt den Thread :)

von Dirk B. (dirkb2)


Lesenswert?

Michael D. schrieb:
> snprintf hat mir aus irgendeinem Grund bei %s%f%s statt des
> floats in der Mitte nur ein Fragezeichen geliefert, egal was als Float
> übergeben wurde.

Du musst die Floating-Point Version von snprintf nehmen.
Die ist in einer anderen/zusätlichen Library.

von W.S. (Gast)


Lesenswert?

Michael D. schrieb:
> Bin grad überfragt, drum frag ich euch ;)

Tja.

Lade dir die Lernbetty runter und benutze conv.c von dort, das läuft 
auch auf einem AVR und die dortige Float-Konvertierung funktioniert.

W.S.

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.