liefert auf der Console:
00 54 65 6D 70 65 72 61 74 75 72 3A 20 00 00 00 00 B7 36 00 09 0A
54 65 6D 70 65 72 61 74 75 72 3A 20 ist korrekt "Temperatur: " Aber
der Rest sind Steuer und Sonderzeichen.
Also Uart und Text funktioniert. Aber die Zahl funktioniert nicht. Im
Internet konnte ich keine Lösung oder Alternative für STM32 finden. Bei
Atmel habe ich "dtostrf" benutzt, was hier aber nicht funktioniert.
Programmiert wird mit SW4STM32.
evtl schrieb:> evtl. liegt es daran> float --> %4.2f> double -> %4.2lf
Nein. %f ist schon double. Wenn man einen float an printf übergibt, wird
der immer erst automatisch nach double konvertiert. Deshalb passt %f
sowohl für float, als auch für double.
evtl schrieb:> evtl. liegt es daran> float --> %4.2f> double -> %4.2lf
Was für ein Schwachsinn. Lies Dir nochmal die Manpage für printf()
durch.
Der OP verwendet vermutlich newlib und gcc, da geht %f in *printf nur
mit reichlich heap für malloc(). Was auf µC in der Regel nicht
ausreichend vorhanden ist.
Im obigen Falle könnte man das Ergebis aber klassisch mit Integern
berechnen. Die funktionieren in *printf().
Heinz M. schrieb:> Aber der Rest sind Steuer und Sonderzeichen.
Du gibst ja auch mehr Zeichen aus, als der String enthält. Statt "len"
auf den konstanten Wert 20 zu setzen, solltest Du vorher die Stringlänge
bestimmen - das geht z.B. mit strlen. Dein String ist nämlich nach dem
auf den Doppelpunkt folgenden Leerzeichen zuende - da steht in Deinem
Hexdump 00.
Und spätestens dann kannst Du erkennen, daß Dein sprintf Dir keine
float-/double-Zahl ausgibt.
Um den Code kleinzuhalten, wird auf Microcontrollern oft mit reduzierten
printf-Varianten gearbeitet, die beispielsweise keine
float-/double-Unterstützung haben. Das ist aber in der Dokumentation des
verwendeten Compilers beschrieben, da wird auf die unterschiedlich
umfangreichen printf-Varianten eingegangen.
Der Hinweis mit dem Compiler war gut, weil die Konvertierung
standardmäßig abgeschalten ist:
http://www.openstm32.org/forumthread2108
"Check your linker flags (project properties > C/C++ Build > Setings >
Tool Settings (TAB) > MCU GCC Linker > Miscellaneous > Linker flags),
if you are using nanolib "-specs=nano.specs" you need to add "-u
_printf_float" to enable float printf." (TarekB)
Speicherverbrauch ist nicht ohne.
Sprintf ~10KB
Floatkonvertierung ~10KB
Zum Testen reicht es und später kann ich es als uint übertragen.
Die Konstante Länge war nur zum Testen. Optimiert sieht es jetzt so aus:
Heinz M. schrieb:> Kann man dazu auch ein paar Sätze schreiben?
Ist es zuviel verlangt, einmal einen Blick in die Doku von sprintf zu
werfen?
> Mir sagt das jetzt ich soll das Array "Out" in die Variable "length"> packen. Wozu auch immmer.
Dann hast du offenbar eine (falsche) Annahme darüber getroffen, was
sprintf zurückliefert.
Boah, mit einem Tiny und etwas Festkomma liefert man
Temperaturen von (je nach Sensor) -77,77 °C bis 555,55 °C
nach Berücksichtigung der Sensor-Parameter und Ausreizung
der vorgegebenen Genauigkeit mit < 0,5 KB Code an die
SW-UART.
Und hier bekommt man das nicht mit 5...50 KB sprintf-Lib
+ 50...500 KB Math-Lib hin...
Wie wäre es denn mit einem LESE-Lernkurs?
Jacko schrieb:> Und hier bekommt man das nicht mit 5...50 KB sprintf-Lib> + 50...500 KB Math-Lib hin...
So entstehen Märchen, die wohl vor dem bösen "Float" warnen sollen!
Früher war es der Wolf ;-)
Ich habe hier bei einem kleinen Programm für STM32Fxxx nachgesehen,
wieviel Code für sprintf() benötigt wird: weniger als 4 KB. Der Rest des
Programmes inkl. Verarbeitung von ein paar double-Werten ist 5 KB groß.
Auf einem STM32 mit Festkomma zu rechnen, insbesondere für langsame
Temperaturwerte, ist Steinzeit Codierung.
Auf einem Tiny in C mit float programmiert paßt der Code locker in einen
ATtiny45. Auch hier ist Festkomma fehl am Platz, es sei denn, die
verwendeten Compiler taugen nicht die Bohne.
Rufus Τ. F. schrieb:> Um den Code kleinzuhalten, wird auf Microcontrollern oft mit reduzierten> printf-Varianten gearbeitet...
Aber sowas machen eben nur Leute, die zu doof sind, irgend eine simple
Konvertierung sich selbst zu schreiben.
Herrje, ein einziger Blick in die mittlerweile steinalte Lernbetty
hätte genügt, um eine formatierte Float-Ausgabe zu haben, die keinen
Heap braucht, mit herzlich wenig Flash auskommt und auf diversen
Architekturen läuft (ARM, Fujitsu, NEC, AVR).
Gerade Ein- und Ausgabekonvertierungen für Zahlen sind Basis-Themen, die
eigentlich jeder anständige Programmierer aus dem Ärmel schütteln können
sollte. Was sind das bloß für Leute, die ihr Handwerkszeug so schlecht
beherrschen?
W.S.
@Rolf Magnus: Ich habe etliche Seiten durchstöbert, bevor ich den Thread
eröffnet habe. Programmierung soll immer selbsterklärend und logisch
sein wurde mir immer gesagt. Die Funktion sprintf dient zur Umwandlung
von Werten in ein String/Char Format. Dass diese Funktion die Länge
zurückgibt ist für mich unlogisch. Und genau da ist das Problem, wenn
man sich neu einarbeitet. Überall wird es anders gemacht und jeder meint
seine Lösung wäre die Lösung überhaupt. Im 6. Post wird empfohlen strlen
zu benutzen und im 8. Post den Rückgabewert zu benutzen.
@Jacko: Dann besuche bitte diesen Lesekurs. In diesem Thread geht es
weder um die Speicherplatzgröße, noch um die Genauigkeit.
@m.n.: Eben. Der µC hat 64KB Flash, 2 Temperatur-/Feuchtesensoren, I2C
LED Anzeige, UART und bissl GPIOs.
Über STM32CubeMX und SW4STM32 sind das 27KB. Was bringt es mir wenn von
den 64KB 63,5KB unbenutzt sind statt 37KB? Richtig, nichts.
@W.S.: Steht da auch drin, dass die Float Konvertierung in SW4STM32
standardmäßig abgeschalten ist? (ironische Frage)
Ich bin kein Programmierer und daher kann ich es auch nicht so einfach
aus dem Ärmel schütteln.
Wer bei C printf/scanf benutzt, sollte wissen was er tut.
Diese Funktionen sind prinzipiell anfällig für alle Arten von
Programmier-Fehlern.
Und jetzt weißt du wieder etwas mehr;.)
In diesem Sinne; schönen Sonntag.
Adib.
--
Heinz M. schrieb:> Steht da auch drin, dass die Float Konvertierung in SW4STM32> standardmäßig abgeschalten ist? (ironische Frage)
Ähemm.. Es ist DEIN Problem, nicht meines. Und ob da irgendwo
irgendeine Konvertierung ab- zu- um- oder sonstwie geschaltet ist, geht
mich und meine Firmware nix an.
Also nochmal im Klartext: Wenn du denn unbedingt printf und Konsorten
benutzen willst, dann solltest du auch die dafür benötigten
Grundkenntnisse mitbringen. So wie Hans GuckindieLuft drauflos zu
programmieren, ohne sein System hinreichend zu beherrschen, führt genau
zu solchen Bauchlandungen, wie du sie im Eröffnungspost beschrieben
hast.
Nochwas:
Gegen mangelhafte Grundkenntnisse hilft übrigens auch kein (uint8_t*)out
- gelle? Wozu überhaupt bei einem Character-Stream aus einem char
out[20] ein Typecast? Es sind ja doch schiere char's, die da über die
Schnittstelle gehen sollen.
W.S.
W.S. schrieb:> Wozu überhaupt bei einem Character-Stream aus einem char> out[20] ein Typecast? Es sind ja doch schiere char's, die da über die> Schnittstelle gehen sollen.
Im konkreten Fall, ja. Im allgemeinen Fall übeträgt ein UART aber
einfach 8-Bit-Bytes. Ob darin Text oder ein Audio-Strem kodiert ist,
ist dem UART egal. Der korrekte Datentyp für ein 8-Bit-Byte ist aber
nicht char, sondern uint8_t. Deswegen erwartet die Funktion
HAL_UART_Transmit als zweites Argument keinen char- sondern einen
uint8_t-Pointer, und der Cast an dieser Stelle ist völlig richtig.
https://developer.mbed.org/users/EricLew/code/STM32L4xx_HAL_Driver/docs/tip/group__UART__Exported__Functions__Group2.html
W.S. schrieb:> Aber sowas machen eben nur Leute, die zu doof sind, irgend eine simple> Konvertierung sich selbst zu schreiben.
Das machen die Compilerhersteller, die unterschiedlich umfangreiche
printf-Varianten ausliefern, wie z.B. IAR. Die sind natürlich alle zu
doof, statt den Benutzer dazu zu erziehen, bloß kein printf zu
verwenden.
Heinz M. schrieb:> @Rolf Magnus: Ich habe etliche Seiten durchstöbert, bevor ich den Thread> eröffnet habe. Programmierung soll immer selbsterklärend und logisch> sein wurde mir immer gesagt. Die Funktion sprintf dient zur Umwandlung> von Werten in ein String/Char Format. Dass diese Funktion die Länge> zurückgibt ist für mich unlogisch.
Naja, die Logik ergibt sich doch aus deiner Benutzung und eine Funktion
wie
ist eben in C absoluter Standard. Da ist es egal ob du jetzt in eine
Datei, auf einen Socket oder eben deinen UART schreibst. Die Länge musst
du immer mit angeben. Was willst du denn sonst mit deinem String machen
außer ihn irgendwohin zu schreiben? Selbst wenn du den einfach nur mit
memcpy in einen anderen Buffer kopieren willst musst du die Länge
angeben:
1
void*memcpy(void*dest,constvoid*src,size_tn);
Jim M. schrieb:> Was für ein Schwachsinn. Lies Dir nochmal die Manpage für printf()> durch.
Auch wenn das nicht an dich (Heinz) adressiert war kann ich Man-Pages
für C-Standard-Funktionen absolut empfehlen. Auch wenn die
Implementierung zwischen glibc, newlib, musl und wie sie alle heißen
unterschiedlich sein mag, so ist die Signatur und das Verhalten - wie
der Name schon sagt - standardisiert. Dank Internet gibt es manpages
heute auch für Windows-Nutzer. Eine einfache Google-Suche nach "man
sprintf" liefert bei mir als erstes Ergebnis
https://linux.die.net/man/3/sprintf und dort unter "Return value" steht
dann, was sprintf und Konsorten zurückgeben.
@W.S.: Wenn dir das Problem eines Threads egal ist, dann bist du in
einem Forum fehl am Platz.
Typecast, weil es sonst nicht geht.
@Christopher: Ja solche Man Pages suche ich mir auch gerne raus.
Wenn man damit anfängt kommt halt jede Menge auf einmal. Da kommt man
vom 100sten ins 1000ste. Nur um dann von Leuten wie W.S. an den Kopf
geworfen zu bekommen, dass man die Grundlagen nicht beherrscht. Ja wie
denn auch, wenn man sie gerade lernt.
Die Kellerlüftungssteuerung funktioniert erst mal soweit. Testaufbau
liegt auf dem Fensterbrett zum Fehler suchen.
Heinz M. schrieb:> @Rolf Magnus: Ich habe etliche Seiten durchstöbert, bevor ich den Thread> eröffnet habe. Programmierung soll immer selbsterklärend und logisch> sein wurde mir immer gesagt.
Eine weitere wichtige Grundregel des Programmierens ist, keine Annahmen
zu treffen. Und zumindest sollte mal gelten: "If everything else fails,
read the manual". ;-)
> Die Funktion sprintf dient zur Umwandlung von Werten in ein String/Char> Format. Dass diese Funktion die Länge zurückgibt ist für mich unlogisch.
Für mich nicht. Die Länge wird nachher oft gebraucht, wie in deinem
Fall, und fällt praktisch eh an. Da finde ich es logisch und sinnvoll,
sie auch zurückzuliefern. Den Zeiger, den man selbst reingegeben hat,
wieder rauszugeben, hat dagegen wenig Mehrwert.
Davon abgesehen ist sprintf() ja auch nur eine Abwandlung von printf().
Was sollte man dort zurückgeben? Da gibt es diesen Zeiger ja gar nicht.
Oder soll bei jeder *printf()-Funktion was anderes zurückgegeben werden?
Das wäre dann ziemlich inkonsistent.
> Und genau da ist das Problem, wenn man sich neu einarbeitet. Überall wird> es anders gemacht und jeder meint seine Lösung wäre die Lösung überhaupt.> Im 6. Post wird empfohlen strlen zu benutzen und im 8. Post den> Rückgabewert zu benutzen.
strlen() muss eben nochmal den ganzen String durchlaufen, was man sich
komplett sparen kann, wenn man den Rückgabewert von sprintf() nutzt.
Viele wissen nur nicht, dass die *printf-Funktionen überhaupt einen
Returnwert haben - eben weil sie das Handbuch nicht gelesen haben.
Heinz M. schrieb:> Typecast, weil es sonst nicht geht.
Das ist ehrlich gesagt der falsche Grund. Hier ist der Cast völlig
richtig, aber man sollte, wenn man einen Cast benutzt, auch immer genau
wissen, warum er nötig ist. Mit einem Cast kriegt man den Compiler fast
immer irgendwie ruhig gestellt, aber das heißt nicht, dass dabei auch
das richtige rauskommt.
Jacko schrieb:> Boah, mit einem Tiny und etwas Festkomma liefert man> Temperaturen von (je nach Sensor) -77,77 °C bis 555,55 °C> nach Berücksichtigung der Sensor-Parameter und Ausreizung> der vorgegebenen Genauigkeit mit < 0,5 KB Code an die> SW-UART.>> Und hier bekommt man das nicht mit 5...50 KB sprintf-Lib> + 50...500 KB Math-Lib hin...
Manche Leute implementieren halt lieber ihr eigentliches Projekt, statt
zu versuchen, optimierte Versionen von Standard-Library-Funktionen zu
implementieren, weil sie ein überteuertes Steinzeitrelikt mit 8Bit
verwenden.
Außerdem ist das lang nicht so schlimm wie du behauptest. Ich habe
mehrere Projekt auf PIC24FV32KA304 mit float und snprintf - und bin
immer wunderbar mit den 32k Flash ausgekommen.
Noch eine Anmerkung zum Thema:
Ich persönlich würde noch etwas mehr Flash investieren, und snprintf()
verwenden. Zumindest, wenn dein Compiler das anbietet.
Man kann sprintf schon verwenden, so ist das nicht, aber snprintf() ist
um einiges sicherer. Insbesondere wenn die Arraylängen wegen des knappen
RAMs im Controller kürzer sind.