Hallo Forum,
ich versuche aktuell einen Float Wert eines Sensors über UART zu
übertragen. µC ist hierbei ein STM8S103F3P6, UART/USB-Converter ein
CH340-Modul.
Ich benutze ST Visual Develop als IDE und den Cosmic Compiler. Leider
bietet mit diese Kombination keine Standard-C Funktionen, die es mir
erlauben würden, den float in einen char umzuwandeln (zumindest hab ich
diese noch nicht gefunden).
Daher stellt sich mir die Frage, wie ich die Werte nun als Float
ausgeben kann?
Meine UARTSend-Funktion:
1
voidUARTSend(char*message){
2
char*ch=message;
3
while(*ch){
4
while(!(UART1->SR&(1<<6)));//Wait until transmission is complete
5
UART1->DR=*ch;
6
ch++;
7
}
8
}
Ich hab in anderen Beitragen zu ähnlichen Themen gelesen, dass man den
float in einzelne 8-bit Blöcke zerlegen kann und diese dann überträgt.
Allerdings frage ich mich, wie ich die dann am anderen Ende wieder
zusammenstückel? Funktioniert es, dass man den Float direkt als Char
bzw. ASCII-Zeichenkette überträgt?
Falls die Lösung schon irgendwo steht, sry.
> Daher stellt sich mir die Frage, wie ich die Werte nun als Float> ausgeben kann?>> Ich hab in anderen Beitragen zu ähnlichen Themen gelesen, dass man den> float in einzelne 8-bit Blöcke zerlegen kann und diese dann überträgt.> Allerdings frage ich mich, wie ich die dann am anderen Ende wieder> zusammenstückel? Funktioniert es, dass man den Float direkt als Char> bzw. ASCII-Zeichenkette überträgt?>> Falls die Lösung schon irgendwo steht, sry.
Kein sprintf? Kannst den float auch binär übertragen. Das Format ist
standardisiert.
Max M. schrieb:> Allerdings frage ich mich, wie ich die dann am anderen Ende wieder> zusammenstückel?
Bevor du sie zusammenstückeln kannst, muss du erstmal wissen, wo die
Übertragung eines neuen Werten beginnt. Du brauchst ein Datenformat,
dass eine Synchronisationsinformation enthält.
> Funktioniert es, dass man den Float direkt als Char bzw. ASCII-> Zeichenkette überträgt?
Der Übertragungsstrecke ist es egal, was in deinen Augen die
übertragenen Zeichen bedeuten. Da muss sich die Empfangsroutine drum
kümmern.
The D. schrieb:> Kannst den float auch binär übertragen. Das Format ist standardisiert.
Wenn Sender und Empfänger den selben Standard verwenden, werden sie sich
sogar verstehen. ;-)
Funktioniert es vllt. wenn ich den Float einfach * 1000 nehme (passt ja
noch in ein uint16_t) und dann diese uint16_t in chars umwandel? Wie
würde das funktionieren?
The D. schrieb:> Kein sprintf?
Nope :(
The D. schrieb:> Kannst den float auch binär übertragen. Das Format ist> standardisiert.
Ich hätte das ganze halt schon gerne als Text auf der Konsole und nicht
als '1' und '0'.
Max M. schrieb:> Funktioniert es vllt. wenn ich den Float einfach * 1000 nehme (passt ja> noch in ein uint16_t) und dann diese uint16_t in chars umwandel? Wie> würde das funktionieren?>> The D. schrieb:>> Kein sprintf?>> Nope :(>> The D. schrieb:>> Kannst den float auch binär übertragen. Das Format ist>> standardisiert.>> Ich hätte das ganze halt schon gerne als Text auf der Konsole und nicht> als '1' und '0'.
Dann kommst du nicht um eine manuelle Konvertierung herum. Also den
Integer Anteil umwandeln und dann in einer Schleife mit 10
multiplizieren und wieder den integer Anteil umwandeln. Die Anzahl der
Schleifendurchläufe bestimmt die Genauigkeit.
The D. schrieb:> Die Anzahl der Schleifendurchläufe bestimmt die Genauigkeit.
Die Genauigkeit ist durch das Float Format bestimmt - da nützen auch
mehr Schleifendurchläufe nichts.
Wolfgang schrieb:> The D. schrieb:>> Die Anzahl der Schleifendurchläufe bestimmt die Genauigkeit.>> Die Genauigkeit ist durch das Float Format bestimmt - da nützen auch> mehr Schleifendurchläufe nichts.
Ja, die maximal erzielbare. Bis dahin zählen die Schleifendurchläufe.
Wolfgang schrieb:> The D. schrieb:>> Kannst den float auch binär übertragen. Das Format ist standardisiert.>> Wenn Sender und Empfänger den selben Standard verwenden, werden sie sich> sogar verstehen. ;-)
Da gibt's quer durch alle Prozessorenfamilien und Compilervarianten eine
große Ubereinstimmung :
https://de.m.wikipedia.org/wiki/IEEE_754
The D. schrieb:> Dann kommst du nicht um eine manuelle Konvertierung herum. Also den> Integer Anteil umwandeln und dann in einer Schleife mit 10> multiplizieren und wieder den integer Anteil umwandeln. Die Anzahl der> Schleifendurchläufe bestimmt die Genauigkeit.
Könntest du da netterweise ein kurzes Beispiel zeigen, was du genau
meinst?
Mein Code aktuell:
1
uint16_tx,y,z;
2
uint8_tx1,x2;
3
readXYZ(&x,&y,&z);
4
x1=(x&(0xFF00))>>8;
5
x2=x&(0x00FF);
x1 und x2 stellen die 8-Bit Anteile der 16-Bit Zahl x dar. Warum
muss ich die nun mit 10 multiplizieren?
Max M. schrieb:>> x1 und x2 stellen die 8-Bit Anteile der 16-Bit Zahl x dar. Warum> muss ich die nun mit 10 multiplizieren?
Du hast von float Werten geschrieben. Ich seh keine.
The D. schrieb:> Du hast von float Werten geschrieben. Ich seh keine.Max M. schrieb:> Funktioniert es vllt. wenn ich den Float einfach * 1000 nehme (passt ja> noch in ein uint16_t) und dann diese uint16_t in chars umwandel? Wie> würde das funktionieren?
Max M. schrieb:> The D. schrieb:>> Du hast von float Werten geschrieben. Ich seh keine.>> Max M. schrieb:>> Funktioniert es vllt. wenn ich den Float einfach * 1000 nehme (passt ja>> noch in ein uint16_t) und dann diese uint16_t in chars umwandel? Wie>> würde das funktionieren?
Integers kann man mit itoa in strings umwandeln.
Wolfgang schrieb:> The D. schrieb:>> Da gibt's quer durch alle Prozessorenfamilien und Compilervarianten eine>> große Ubereinstimmung :>>>> https://de.m.wikipedia.org/wiki/IEEE_754>> Meinst du da z.B. den Real Datentyp von Turbo Pascal?
Ich rede von Datentypen die die floating point units heutiger
Prozessoren und C-compiler nutzen.
Servus,
über uart kann man nur 8 bits übertragen, d.h. für einen float braucht
man 4 bytes. Hier ist es auch wichtig zu wissen, welche Endianess die
beiden µC besitzen, sodass es villt notwendig sei die bytes zu
"swappen".
Nun gut:
1
#define SIZE_FLOAT sizeof(float) //kann man auch gleich 4 schreiben
2
3
uint8_tarray_Rx[100];// RX array
4
floatvar_fl;
5
6
//hier die richitge bibiothek einfügen für memcpy
7
memcpy(&(array_Rx[x]),&var_fl,SIZE_FLOAT);//fuer x die richtige stelle reinschreiben!
8
9
//Als Alternative geht es auch mit den Verschiebeoperator >><< oder event auch so:
10
uint32_tschiebab;
11
schiebab=(uint32_t)array[x];//wenn die Endiannes passt sonst muss man schieben
aSma>> schrieb:> Servus,> über uart kann man nur 8 bits übertragen, d.h. für einen float braucht> man 4 bytes. Hier ist es auch wichtig zu wissen, welche Endianess die> beiden µC besitzen, sodass es villt notwendig sei die bytes zu> "swappen".>
Er will es ja als lesbaren Text übertragen und nicht die
Binärdarstellung. Im übrigen ist deine Ausführung Unsinn weil die IEEE
Darstellung auf allen Plattformen identisch ist. Swappen muss man die
bytes nur für Integers wenn man sie zwischen big endian und little
endian Plattformen austauschen will.
The D. schrieb:> Er will es ja als lesbaren Text übertragen und nicht die> Binärdarstellung.
Aso, sry.
Das wurde aber schon tausendfach hier diskutiert. Es gibt sogar ein
Artikel darüber: https://www.mikrocontroller.net/articles/FAQ
Selber basteln oder sprintf nutzen.
mfg
Max M. schrieb:> Wie gesagt, ich hab keine Standard-C Funktionen.
Dann lade dir die Lernbetty hier im Forum herunter. Dort findest du in
conv.c alles was du brauchst. Und ohne sprintf und Konsorten.
W.S.
Stimmt, du hast recht ^^.
Aber es gibt kein itoa und nur sprintf zum konvertieren. Leider
funktioniert dieser Code hier nicht:
1
floatx,y,z;
2
charbuffer_x[255];
3
charbuffer_y[255];
4
charbuffer_z[255];
5
readXYZ(&x,&y,&z);
6
sprintf(buffer_x,"%-.5f",x);
7
sprintf(buffer_y,"%-.5f",y);
8
sprintf(buffer_z,"%-.5f",z);
Nur wenn ich *%d* als Format benutze, bekomme ich was in die Konsole
geschrieben, so bleibt die einfach leer.
Edit: Diese FAQs von denen sind ja schön und gut aber nirgends steht wo
man die Dateien tatsächlich findet? Mir ist inzwischen klar, warum sie
ihren Compiler ohne Begrenzung weggeben, bei der ausführlichen Doku
benutzt den sicher jeder gerne.
Max M. schrieb:> Edit: Diese FAQs von denen sind ja schön und gut aber nirgends steht wo> man die Dateien tatsächlich findet? Mir ist inzwischen klar, warum sie> ihren Compiler ohne Begrenzung weggeben, bei der ausführlichen Doku> benutzt den sicher jeder gerne.
Unter dem Punkt: Eigene Umwandlungsfunktionen
ist die Fkt. : void ItoA( int z, char* Buffer ) von den Macher K&R, in
vollster Länge aufgeschrieben. Was will man da mehr? Der Rest ist in 10
min zusammen gefriemelt.
Oder du bedienst dich hier im Forum:
Beitrag "Re: C-Umwandlungsfunktionen für double/int/long nach String"
Eine echt klasse lib. Einfach nur ein paar Datentypen ändern und schon
läuft der Rubbel.
Ich habe letzte Woche an einer eigenen sehr minimalistischen printf -
Funktion gebastelt (allerdings für einen AVR - grundsätzlich für einen
ATtiny) der eben sehr Speicherplatzsparend sein sollte...
Eine echte Float-Ausgabe gibts nicht, aber er gibt eine Zahl mit 2
Nachkommastellen aus (welche mir sehr oft für ausgelesene Sensoren
reicht) mit einem Beispiel wie ein 10-Bit ADC als Spannungswert
angezeigt werden kann.
Vllt. hilft dir das hier:
Beitrag "Re: #define Ich bekomme ein Makro nicht hin."
Hier mußt du die Funktionen der seriellen Schnittstelle natürlich selbst
definieren und das AVR - eigene Auslesen eines Strings aus dem Flash
(pgm_read_byte) ersetzen...
Smile, werde ich auch ganz sicher noch auf einem STM8 ausprobieren...
sobald meiner aus China hier eingetroffen ist...
Gute Nacht
Max M. schrieb:> ich hab keine Standard-C Funktionen
dann schreib dir doch die itoa-, dtostr- usw. Funktionen selbst. Das ist
jetzt nicht wirklich ein Hexenwerk da dabei nur mit den Grundrechenarten
gearbeitet wird.
Sinnvollerweise legt man ein Byte Array und den float aufeinander, dann
kann man float nach byte wandeln. Wenn man nun ASCII uebertragen will,
macht man aus jedem Byte einen Hex.
Auf der anderen Seite Hext to Byte und in den Byte array, von dort den
Float auslesen. egal ob 32bit oder 64bit.
Hier ein Beispiel, welches einen Long-Festkommawert als String ausgibt.
Um CSV-Dateien zu erzeugen, kann anstatt des Dezimalpunktes auch ein
Komma eingefügt werden.
Max M. schrieb:> Daher stellt sich mir die Frage, wie ich die Werte nun als Float> ausgeben kann?
Ich stelle mir gerade die Frage, wie Du auf einem STM8 überhaupt zu
einem float gekommen bist? Das erste und letzte mal, als ich mit einem
STM8 gearbeitet habe, wäre ich im Leben nicht auf die Idee gekommen, den
kleinen 8-Bitter mit Mathe zu quälen ;-)
Wäre eine Festkomma-Zahl nicht viel passender? Einen float braucht man
doch wirklich nur dann, wenn der Exponent auch mal mehr als eine paar
neben einander liegende Werte annehmen kann.
Torsten R. schrieb:> Wäre eine Festkomma-Zahl nicht viel passender? Einen float braucht man> doch wirklich nur dann, wenn der Exponent auch mal mehr als eine paar> neben einander liegende Werte annehmen kann.
Es handelt sich um einen Beschleunigungssensor der Werte in mG liefert.
Ich hätte halt schon ganz gerne echte "G" (also z.B. 1,243G) und nicht
1243 mG. Oder doch lieber Ganzzahlen?
aSma>> schrieb:> Oder du bedienst dich hier im Forum:
Vielen Dank, genau das, was ich suche!
Max M. schrieb:> Es handelt sich um einen Beschleunigungssensor der Werte in mG liefert.> Ich hätte halt schon ganz gerne echte "G" (also z.B. 1,243G) und nicht> 1243 mG. Oder doch lieber Ganzzahlen?
Doch lieber Festkomma-Zahlen! :-)
Max M. schrieb:> Die ltoa-Funktion läuft einwandfrei, danke!
schreibst Du die Werte auf die UART, dammit sie von einem Menschen
gelesen werden? Wenn ja, dann kannst Du das Komma ja z.B. auch einfach
bei der Ausgabe setzen (übertragen).
Max M. schrieb:> Oder doch lieber Ganzzahlen?
Und wo siehst du da den Unterschied zur Festkommazahl? ;)
Im Prinzip ist das immer besser mit Festkommaarithmetik zu arbeiten. In
der Regel spart das Speicher und CPU-Load im Vergleich zur
Gleitkommaarithmetik.
Torsten R. schrieb:> Ich stelle mir gerade die Frage, wie Du auf einem STM8 überhaupt zu> einem float gekommen bist? Das erste und letzte mal, als ich mit einem> STM8 gearbeitet habe, wäre ich im Leben nicht auf die Idee gekommen, den> kleinen 8-Bitter mit Mathe zu quälen ;-)
OT: ich habe in den 90-ern noch mein Z80-Homecomputer Mandelbrötchen
backen lassen in BASIC: 8-bit, Mathe und Interpreter. Langsamer geht
nicht :-D Und dann nach eine Nacht rechnen feststellen, dass das
Programm mit einem "Syntax Error" oder "Out of Memory" verabschiedet
hat...
Torsten R. schrieb:> Ich stelle mir gerade die Frage, wie Du auf einem STM8 überhaupt zu> einem float gekommen bist? Das erste und letzte mal, als ich mit einem> STM8 gearbeitet habe, wäre ich im Leben nicht auf die Idee gekommen, den> kleinen 8-Bitter mit Mathe zu quälen ;-)
Aber manchmal braucht man halt ein bischen Mathe. Ich hatte beim STM8
letzten auch float verwendet um schnell etwas zu probieren. Was mich
erstaunte war, dass zumindest mit dem Cosmic Compiler, Rechnungen in
float um einiges schneller waren als einen uin32_t durch 10 zu teilen :)
Max M. schrieb:> Torsten R. schrieb:>> Wäre eine Festkomma-Zahl nicht viel passender? Einen float braucht man>> doch wirklich nur dann, wenn der Exponent auch mal mehr als eine paar>> neben einander liegende Werte annehmen kann.>> Es handelt sich um einen Beschleunigungssensor der Werte in mG liefert.
Dann übertrage doch die Werte in mG und mach die Umsetzung am PC!
Max M. schrieb:> Eric B. schrieb:>> Dann übertrage doch die Werte in mG und mach die Umsetzung am PC!>> So werde ich es dann auch machen.
Dann musst Du den Integer aber nicht erst in einen Text umwandeln...
Torsten R. schrieb:> Dann musst Du den Integer aber nicht erst in einen Text umwandeln...
Stimmt, man kann in das Datenregister auch eine uint8_t Ganzzahl
reinschieben, oder? Dann müsste ich meine 16-bit aber in 2 Zahlen
unterteilen. Die Frage ist, was dann schneller geht.
Max M. schrieb:> Torsten R. schrieb:>> Dann musst Du den Integer aber nicht erst in einen Text umwandeln...>> Stimmt, man kann in das Datenregister auch eine uint8_t Ganzzahl> reinschieben, oder? Dann müsste ich meine 16-bit aber in 2 Zahlen> unterteilen. Die Frage ist, was dann schneller geht.
Ist das eine ernst gemeinte Frage ?
Auf der einen Seite Umwandlung in Text, dann ca. 6 Bytes
Datenübertragung. Auf der anderen Seite einfach nur 2 bytes übertragen.
Was da wohl schneller ist ...
Max M. schrieb:> Torsten R. schrieb:>> Dann musst Du den Integer aber nicht erst in einen Text umwandeln...>> Stimmt, man kann in das Datenregister auch eine uint8_t Ganzzahl> reinschieben, oder? Dann müsste ich meine 16-bit aber in 2 Zahlen> unterteilen. Die Frage ist, was dann schneller geht.
Ja, wahrscheinlich hat das Datenregister sogar den typen uint8_t. Und 2
Bytes zu übertragen ist viiiieel schneller.
Die Funktion dürfte recht interessante Ergebnisse für negative Integer
liefern. So wie sie ist sollte der zweite Parameter besser den Typ
uint16_t haben.
The D. schrieb:> Die Funktion dürfte recht interessante Ergebnisse für negative Integer> liefern. So wie sie ist sollte der zweite Parameter besser den Typ> uint16_t haben.
Richtig! Hier das original:
1
char*ltoa(char*buf,unsignedlongval,charpad)
Sonst nehme die !SIMPLE ltoa fkt. Das ist dann mit Vorzeichen Erkennung.
Hallo Max
Wenn du die Daten binär überträgst, benötigst du auf der PC-Seite ein
Auswerteprogramm. Das würde ich nur empfehlen, wenn du mit der
Geschwindigkeit nicht hinkommst.
Hast du meinen Vorschlag "printfk.txt" überhaupt angeschaut?
Beitrag "Re: Float über UART übertragen - STM8"
Die Daten können damit in Text umgewandelt und Buchstabenweise gesendet
werden. HTerm empfängt, zeigt an, und kann exportieren.
http://www.der-hammer.info/terminal/
Selbst wenn du nur mit 9600 Baud sendest, dauert die Übertragung von
einem Buchstaben ca. 1ms. Eine Zahl im Format -3,456 dauert dann 6ms,
bei drei Achsen (x, y, z) 18ms. Wenn das zu langsam ist, kannst du auf
115200 Baud hoch, dann geht alles 10 mal so schnell.
Du übergibst deine milli-G, das Komma an der 3. Stelle und das
Vorzeichen wird auch ausgewertet.
1
charausgabe[13];
2
charlen,i;
3
int16_tx,y,z;
4
5
readXYZ(&x,&y,&z);// Vorzeichenbehaftete Werte in mG