Ich habe da mal ne Frage :D
Mir stehen zwei Ansatzpunkte zur Verfügung. Wobei ich eher den zweiten
Ansatzpunkt, aus Sichtpunkt der Geschwindigkeit, bevorzuge.
Der Hintergrund:
Ich möchte mehrere Werte (ersteinmal drei um genau zu sein) von einem PC
über RS232 zu einem µC (tiny2313) schicken. Die Werte liegen mir als
32Bit Float im PC vor, sind aber alles 16Bit und 8Bit Integer Werte
(einmal bis max 300, 10 und 10.000). PC Seitig programmiere ich mit C#
und den µC mit Atmel Studio.
Meine Überlegungen:
1. Die Werte direkt als Float rausschicken, da komme ich halt auf
insgesamt 12Byte. Der µC muss dann den Float in Int umrechnen um
weiterzumachen. Da aber so alle 50-100ms ein Paket kommt, sind selbst
12Byte schon viel. Desweiteren muss ich den Float ja auch umrechnen, die
würde ich dann in etwa so bewerkstelligen wollen:
1
unsignedint*temp;
2
floatval;
3
4
temp=(unsignedint*)&val;
2. Überlegung: Die Werte schon direkt im PC mit C# umrechnen und dann
als Integer (Char 16Bit) schon rüber schicken. Da komme ich dann auf
bloß 6 Byte. Ist ja immerhin bloß die hälfte. Nur, weiß ich nicht genau
wie ich in C# die den Float richtig in Char bringe?! Momentan mach ich
dies für alle drei Werte so (Schon mit UART, die 132 ist die Position im
ByteField - davon werden 4Byte (Float) genutzt):
Da überträgt er es ja dann direkt als String aber, das heißt ich müsste
im Tiny den String erst wieder in eine Integer wandeln - und genau da
ist mein Problem! Das kostet mit atoi wahnsinnig viel Speicher und vor
allem auch Zeit.
Wie kann ich dies besser lösen?! Jemand nen Ansatz?!
Wäre euch sehr dankbar!
Draco schrieb:> Die Werte liegen mir als> 32Bit Float im PC vor, sind aber alles 16Bit und 8Bit Integer Werte
dann schick sie als Integer, die Float Darstellung in PC und mc sind
nicht notwendigerweise gleich, 8/16 Bit schon (endianess beachten)
Draco schrieb:> Der Hintergrund:>> Ich möchte mehrere Werte (ersteinmal drei um genau zu sein) von einem PC> über RS232 zu einem µC (tiny2313) schicken. Die Werte liegen mir als> 32Bit Float im PC vor, sind aber alles 16Bit und 8Bit Integer Werte> (einmal bis max 300, 10 und 10.000). PC Seitig programmiere ich mit
Entweder dein Datentyp ist ein float (32-bit) oder ein int. Was meinst
du mit "sind alles 16Bit und 8 Bit Integer Werte"?.
Draco schrieb:> dies für alle drei Werte so (Schon mit UART, die 132 ist die Position im> ByteField - davon werden 4Byte (Float) genutzt):>> ComPort.Write(Convert.ToInt16(BitConverter.ToSingle(OutBytes,> 132)).ToString());>> Da überträgt er es ja dann direkt als String aber, das heißt ich müsste> im Tiny den String erst wieder in eine Integer wandeln - und genau da
Ja, der überträgt das als String, weil die Funktion Write vermutlich
einen String überträgt. Du kannst aber auch deine Zahlen einzeln
raushauen, also z.B. zuerst die ersten 8 Bit deiner 16 Bit Zahl, dann
die nächsten 8 Bit. usw. Dann hast du auch keinen String, sondern nur
ein Bytefeld.
Ich versteh aber nicht was dein Problem ist, weil ein String ja nur ein
Zeichen mehr hat, als deine einzelnen Zeichen, nämlich die 0.
Das du nach jedem mal, wenn du ein Zeichen empfangen hast, dieses
verarbeiten musst, ist halt so. Das ist eine Eigenschaft deines Systems.
Draco schrieb:> Wie kann ich dies besser lösen?!
float sind doch nur 4byte. Die sollte auch zwischen PC und µC gleich
sein.
in c kannst du die 4byte einfach per memcopy in ein float kopieren.
1
uint8_t[4]temp;
2
floatval;
3
memcpy(&float,tmp,4);
in C# kannst du die mit BitConverter.GetBytes(floats); arbeiten.
Peter II schrieb:> float sind doch nur 4byte. Die sollte auch zwischen PC und µC gleich> sein.
Hüstel.
Es gibt mindestens 4 gebräuchliche Permutationen der 4 Bytes eines float
oder long bzw. 2 bei short.
Eine praktischere Lösung wäre, wenn PC und MC in Network Byte Order
konvertieren könnten.
Wenn es aber eh nur ints sind, dann einfach auf dem PC die Kommastellen
abschneiden. Dann muß der MC nicht die float Lib dazulinken.
Peter D. schrieb:> Hüstel.> Es gibt mindestens 4 gebräuchliche Permutationen der 4 Bytes eines float> oder long bzw. 2 bei short.
warum sollte 4 Byte durcheinander kommen? Es sind einfach 4 Bytes 0-3
ferig.
Bei einen "Text" kommt doch auch nicht mal "xteT" raus.
Peter D. schrieb:> Eine praktischere Lösung wäre, wenn PC und MC in Network Byte Order> konvertieren könnten.
wozu? float ist gleich auf beiden Seiten gleich - die Byteorder ist für
int werte.
Peter II schrieb:> Loddar schrieb:>> das ist nur was für Mutige>> warum?>> https://de.wikipedia.org/wiki/IEEE_754>> welcher PC oder µC macht das anders?
siehe dazu Zitat aus deinem Link:
Die bei einer Rechenanlage konkrete Anordnung der Bits im Speicher kann
von diesem Bild abweichen und hängt von der jeweiligen Bytereihenfolge
(little/big endian) und weiteren Rechnereigenheiten ab.
Loddar schrieb:> Die bei einer Rechenanlage konkrete Anordnung der Bits im Speicher kann> von diesem Bild abweichen und hängt von der jeweiligen Bytereihenfolge> (little/big endian) und weiteren Rechnereigenheiten ab.
und wie ist sie auf einen tiny? Und wie ist sie auf einem PC?
Man darf dort bei seinen eigenem Protokoll übertragen wie man will. Man
muss auf niemand Rücksicht nehmen. Wenn sie wirklich verschieden ist,
kann man dem PC es zumuten es zu drehen, damit es für den µC passt.
Loddar schrieb:> Peter II schrieb:>> Die sollte auch zwischen PC und µC gleich>> sein.>> das ist nur was für Mutige
Oder für welche, die einfach wissen, dass es gleich ist, weil sie es
nachgelesen haben.
Peter D. schrieb:> Peter II schrieb:>> float sind doch nur 4byte. Die sollte auch zwischen PC und µC gleich>> sein.>> Hüstel.> Es gibt mindestens 4 gebräuchliche Permutationen der 4 Bytes eines float> oder long bzw. 2 bei short.
Und die hast du alle auf dem hier diskutierten tiny2313 schon erlebt?
> Eine praktischere Lösung wäre, wenn PC und MC in Network Byte Order> konvertieren könnten.
Ich würde eher die Byteorder des Systems nehmen, bei dem der Aufwand zum
rumdrehen am teuersten ist.
"Network Byteorder" ist der Begriff für die Reihenfolge, die IP-Stacks
für ihre Protokollheader verwenden. Welchen Vorteil soll die denn auf
einer RS232 haben?
Rolf M. schrieb:> "Network Byteorder" ist der Begriff für die Reihenfolge, die IP-Stacks> für ihre Protokollheader verwenden. Welchen Vorteil soll die denn auf> einer RS232 haben?
Das wäre ein Standard, der die Reihenfolge festlegt, d.h. damit
funktioniert es garantiert.
Ansonsten muß man prüfen, wie es die verwendeten CPUs und Compiler
halten. Es kann rein zufällig passen, muß aber nicht.
Peter D. schrieb:> Das wäre ein Standard, der die Reihenfolge festlegt, d.h. damit> funktioniert es garantiert.> Ansonsten muß man prüfen, wie es die verwendeten CPUs und Compiler> halten.
Das muss man sowieso. Schließlich brauchst du ja erstmal eine Funktion,
um in deine network byteoder zu konvertieren. Auf dem PC kann man da
noch die Funktionen des IP-Networking dafür missbrauchen, solange man
nicht mehr als 32 Bit benötigt, aber auf dem µC hat man die meist nicht.
Rolf M. schrieb:>> das ist nur was für Mutige>> Oder für welche, die einfach wissen, dass es gleich ist, weil sie es> nachgelesen haben.
ich kann natürlich nachschauen wie es heute ist, bei den verwendeten
Compilern und bei dem verwendeten PC ist und dann per quick and dirty
was reinhacken. Das kann sich aber auch schnell ändern.
Als Bastler kann man das machen. Wenn man dann auf ein anderes System
umsteigen muss macht man es einfach neu, ist ja schließlich Hobby.
Ich weiß ja nicht, ob union aus float und long definiert ist, dann
könnte man die 4 Bytes auf beiden Maschinen durch Schieben extrahieren
und zusammensetzen.
Allerdings wie gesagt, aufm ATTiny2313 wirds recht eng mit der
float-LIb.
Sooo... also langsam bin ich echt am Verzweifeln hier. Ich kann mir auch
keinen Rat mehr geben.
Ich übergebe nun die "Zahl" als String Quasi "312"... lese diese mit dem
Interrupt Vektor für die UART ein und übergebe sie an:
1
volatilechardataUART;
2
3
ISR(USART_RX_vect)
4
{
5
chardata=UDR;
6
dataUART=data;
7
}
Das klappt auch, aber ich bekomme diesen verdammten String nicht zu
einer Int16 gewandelt. Mit z.b. atoi bekomme ich nur Fehlermeldungen um
die Ohren gehauen weil es ja nicht const char ist:
1
intmain(void){
2
3
inituart();
4
sei();
5
6
uint16_tRechner=0;
7
8
while(1){
9
10
Rechner=atoi(dataUART);
11
12
if(Rechner>=80)
13
{
14
transmitbyte(dataUART);
15
}else{
16
transmitbyte('o');
17
}
18
_delay_ms(100);
19
}
20
return0;
21
}
Sehe ich da den Wald vor lauter Bäumen nicht mehr?!
Sooo... fertsch. Ich lasse es mir nun einfach als ByteArray schicken,
brauche ja sowieso noch ein StatusByte welches dem µC mitteilt um
welchen Wert es sich überhaupt handelt.
Das ist auf der C# Seite etwas nunja: "umständlich", da man an ein Array
nicht einfach noch ein Byte "ansetzen" kann, ich aber das StatusByte
brauche, sowie noch ein NewLine ('\n'). Deswegen musste ich da den Umweg
über zwei Arrays gehen:
Draco schrieb:> ... ich aber das StatusByte brauche, sowie noch ein NewLine ('\n').
Damit handelst du dir einen überflüssigen Overhead von 15 Bit. Bei 13,3
Bit Nutzdaten ist das schon eine ganze Menge, wenn man daraus keinen
weiteren Gewinn zieht.
Es würden locker reichen, 3 Byte zu übertragen, in denen jeweils ein Bit
als Synchronisationsinformation fungiert. Dann hättest du noch 21 Bit,
i.e. 14 Bit für die Daten (0..10000) und 7 freie Bit zur beliebigen
Verwendung.
Wolfgang schrieb:> Damit handelst du dir einen überflüssigen Overhead von 15 Bit. Bei 13,3> Bit Nutzdaten ist das schon eine ganze Menge, wenn man daraus keinen> weiteren Gewinn zieht.> Es würden locker reichen, 3 Byte zu übertragen, in denen jeweils ein Bit> als Synchronisationsinformation fungiert. Dann hättest du noch 21 Bit,> i.e. 14 Bit für die Daten (0..10000) und 7 freie Bit zur beliebigen> Verwendung.
Die Idee ist nicht verkehrt. Da ich weiß, das die Daten ja eh nie in
solche höhen gehen, kann ich ja zweiten Byte, welches die Integer schon
belegt, 3Bit als Statusbits zu "missbrauchen" und dann im Tiny einfach
die drei Bits wieder mit nullen füllen. Die Idee werde ich mal umsetzen,
danke.
Und wenn ich gerade so meinen letzten Post gesehen habe, sehe ich auch
gerade das ich den NewLine garnicht mitsende, sonder ja bloß die ersten
3Byte aus ListTemp. Da kann ich das ja quasi auch weglassen, muß ich mal
probieren wie das unter Stress aussieht.
Draco schrieb:> Hmm... aber selbst einen Pointer mag er nicht.
Der mag den Pointer deshalb nicht, weil du ihn nicht übergibst. Du
übergibst weiterhin einen char, nur diesmal noch falscher.
> int main(void) {>> inituart();> sei();>> uint16_t Rechner = 0;> char *ptr;
Hier definierst du einen Zeiger.
> while(1) {>> ptr = dataUART;
Hier interpretierst du das vom UART empfangene Byte als Adresse und
schreibst diese in den Pointer. Wenn also vom UART z.B. 0x57 kommt,
zeigt der Zeiger nun auf die Speicher-Adresse 0x57.
> Rechner = atoi(*ptr);
Hier dereferenzierst du nun den Pointer, liest also das Byte aus, was an
der Adresse im Speicher steht, auf die er gerade zeigt, also in unserem
obigen Beispiel die Speicherstelle 0x57. Sagen wir mal, da steht im
Speicher 0x20 drin.
Das übergibst du an atoi, welches dieses Byte wiederum als Adresse
interpretiert und versucht, dort aus dem Speicher einen String zu lesen.
atoi erwartet also nun an Speicheradresse 0x20 einen String, den es
umwandeln kann.
Das zeigt (no pun intended), dass du noch nicht ansatzweise verstehst,
wie Zeiger funktionieren. So wirst du damit aber kein funktionierendes
Programm zustande bekommen. Also solltest du dich erstmal mit den
Grundlagen vertraut machen.