Hallo
wie kann ich eine Float in Byte umwandeln ?
wie kann ich interger in Byte umwandeln ?
Hallo
wie kann ich eine Float in Byte umwandeln ?
wie kann ich interger in Byte umwandeln ?
In ein Byte gar nicht. Ein int hat 2 Bytes. Ein float hat 4 bytes.
int -> 2 Bytes:
int i = 1000;
byte low = lowByte(i);
byte high = highByte(i);
oder:
byte low = i;
byte high = i >> 8;
2 Bytes -> int
byte low = 10;
byte high = 20;
int i = word(high, low);
oder:
int i = (high << 8) | low;
float -> byte array:
float f = 123.45;
byte* bytes = (byte*)&f;
Das ist ein Zeiger auf Bytes, d.h. ein Array aus 4 Bytes (da float eben 4 Bytes hat). Du kannst z.B. bytes[0] machen oder mit einer for-Schleife darüber iterieren
byte array -> float:
float f = *(float*)bytes;
Alternativ geht bei sowas auch eine union aus einem byte Array und dem Wert:
union floatUnion { float f; byte b[4]; };
union intUnion { int i; byte b[2]; };
Dann eine Instanz der union erstelllen und man kann mit .i, .f und .b auf die Werte zugreifen. Da die sich den gleichen Speicher teilen, wird dann automatisch der jeweils andere Wert mitgeändert.
Wenn die Zahl klein genug ist um in ein Byte zu passen dann einfach:
variable_byte = byte(variable_float);
variable_byte = byte(variable_int);
Dabei gehen aber die Kommastellen verloren. Bzw kommt Blödsinn heraus wenn die Zahl größer als 255 oder negativ ist.
Grüße Uwe
Diese Umwandlung von Uwe macht der Compiler automatisch für dich
void setup() {
float f = 123.456;
int i = -1;
byte b = f; // bekommt den Wert 123
Serial.begin(9600);
Serial.println (f); // 123.46
Serial.println (b); // 123
b = i;
Serial.println(b); // 255
Serial.println(b,HEX); // FF
}
Wenn du keine Umwandlung willst,
sondern den unveränderten Speicherinhalt einer int bzw. float Variable als byte array verwenden willst,
ist Serenifly's Lösung das was du suchst
Hallo
vielen dank erst mal hat mir geholfen.
Leider konnte ich das eigenliche Problem einen Byte array in eine SPS schreiben nicht lösen.
Ich hänge mal den Link an fals jemand eine lösung hierzu hat.
http://forum.arduino.cc/index.php?topic=200132.msg1714531#msg1714531
Hallo
ich msste einen floatin Big-Endian Konvertiren und dann in byte umwandeln
Hat jemand eine Lösung hierzu ?
Wandle es erst in ein Byte Array um,wie ich es oben gesagt habe. Genaugenommen ist das nicht wirklich eine Wandlung, sondern du kannst den Speicher den der Float belegt einfach anders ansprechen.
Du kannst dann bytes[0], etc. machen. Also das:
float f = 123.45;
byte* bytes = (byte*)&f;
byte bigEndian[4];
bigEndian[0] = bytes[3];
bigEndian[1] = bytes[2];
bigEndian[2] = bytes[1];
bigEndian[3] = bytes[0];
Super danke.
geht das dann genau so bei INT und BYTE ?
Ja. Wobei du auf dem Arduino - weil int nur 2 Bytes hat (wie short auf dem PC) - eben auch einfach mit lowByte()/highByte() arbeiten kannst.
Hallo
habe versuch eine Fuktion zu erstellen wo float in Byte wandelt und die Bytes dreht.
Bei 1. Habe ich es in der Loop schleife versucht. ergebis 66246230102.
Bei 2. Fabe ich versucht dies in eine funktion zu packen. ergebniss 2550254118.
Was mache ich bei 2. Falsch ?
#include <SPI.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
}
void loop() {
// Float
float Zahl1=123.45;
Serial.println(Zahl1 );
// 1.Float in Byte umwandeln
byte* bytes = (byte*)&Zahl1;
// 1.Byte drehen
byte bigEndian[4];
bigEndian[0] = bytes[3];
bigEndian[1] = bytes[2];
bigEndian[2] = bytes[1];
bigEndian[3] = bytes[0];
Serial.print(bigEndian[0]);
Serial.print(bigEndian[1]);
Serial.print(bigEndian[2]);
Serial.println(bigEndian[3]);
delay(1000);
byte* b = S7Float_to_Byte(Zahl1);
Serial.print(b[0]);
Serial.print(b[1]);
Serial.print(b[2]);
Serial.println(b[3]);
delay(2000);
}
// 2.Funktion Float in Byte, Byte drehen
byte* S7Float_to_Byte( const float inFloat )
{
byte* retVal;
byte* bytes = (byte*)&inFloat;
byte bigEndian[4];
bigEndian[0] = bytes[3];
bigEndian[1] = bytes[2];
bigEndian[2] = bytes[1];
bigEndian[3] = bytes[0];
return retVal;
}
Du kannst keine Zeiger auf lokale nicht-statische Variablen zurückgeben. Der Speicher hört am Ende der Funktion auf zu existieren! Außerdem wird returnVal nie beschrieben.
Erstelle das Array außerhalb der Funktion und übergebe den Zeiger als Paramter:
byte* S7Float_to_Byte(const float inFloat, byte* buffer)
{
byte* bytes = (byte*)&inFloat;
buffer[0] = bytes[3];
buffer[1] = bytes[2];
buffer[2] = bytes[1];
buffer[3] = bytes[0];
return buffer;
}
Und dann so aufrufen:
byte bigEndian[4];
S7Float_to_Byte(value, bigEndian);
Alternativ kannst du auch das Array innerhalb der Funktion als static deklarieren. Dann sind die 4 Bytes halt immer belegt. Wie eine globale Variable mit lokalem Scope.
Hallo
returnVal habe ich vergessen.
hab das hier abgeschaut
float ReverseFloat( const float inFloat )
{
float retVal;
char *floatToConvert = ( char* ) & inFloat;
char *returnFloat = ( char* ) & retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[3];
returnFloat[1] = floatToConvert[2];
returnFloat[2] = floatToConvert[1];
returnFloat[3] = floatToConvert[0];
return retVal;
}
So sollte es eigentlich heißen. geht aber auch nicht.
byte* S7Float_to_Byte( const float inFloat )
{
byte* retVal;
byte* bytes = (byte*)&inFloat;
byte* bigEndian=( byte* ) & retVal;;
bigEndian[0] = bytes[3];
bigEndian[1] = bytes[2];
bigEndian[2] = bytes[1];
bigEndian[3] = bytes[0];
return retVal;
}
Mache es jetzt mal so wie du es beschrieben hast.
Du hast nicht verstanden was da gemacht wird. Und dir ist nicht klar wie der Speicher und Zeiger funktionieren.
Ein Zeiger ist eine Adresse auf einen Speicherbereich. In einer Funktion existieren die lokalen Variablen nur auf dem Stack. Der Stack wird nach dem Ende der Funktion wieder zurückgenommen. Entsprechend ist der Speicher dann ungültig.
Dann zu dem hier:
byte* bytes = (byte*)&inFloat;
Hier wird mit & die Adresse von inFloat genommen. Das ist erst mal ein float*. Ein Zeiger auf Float. Den castet man dann auf byte*. Damit wird aber nirgends extra Speicher angelegt. "bytes" ist einfach ein Zeiger auf den Speicher den "inFloat" schon belegt. "bytes" ist einfach ein anderer Weg um "inFloat" anzusprechen. Eben byte-weise und mit mit dem Subscript Operator []. Aber wenn du was bei "bytes" änderst, änderst du direkt "inFloat"
Entsprechend ist das hier völlig sinnfrei:
byte* bigEndian=( byte* ) & retVal;
retVal ist bei dir schon ein byte*. Die Adresse davon wäre dann ein Zeiger auf einen Zeiger. Also ein byte**
Du hast den Code von hier:
Da ist returnVal ein float. Damit hat man schon mal 4 Bytes. Wenn man dann "return returnVal" macht werden die gesamten 4 Bytes zurückgegeben. Nicht wie bei dir nur ein Zeiger auf lokalen Speicher.
Elementare Datentypen kann man anders als Zeiger auf lokale Variablen zurückgeben. Und Arrays sind nur Zeiger auf das erste Element. Entsprechend kann man auch keine lokalen Arrays zurückgeben. Der Standard C Weg ist das Array als Parameter zu übergeben. Einen Zeiger auf ein Array das als Paramter übergeben wurde kann man zurückgeben. Da der Speicher außerhalb der Funktion existiert. Damit kann man die Funktion dann direkt in anderen Funktionen einsetzen.
Ich dachte du wolltest die Daten als Bytes. Daher habe die Variante mit dem Array genommen. Wenn du auch den Float-Wert herumgedreht verarbeiten kannst, kannst es natürlich auch so wie in dem Link machen.
Das ist in C sehr fehleranfällig für Anfänger, da Arrays in ganzes Stück primitiver sind als in vielen anderen modernen Sprachen. In strikt objekt-orientierten Sprachen sind Arrays Objekte. Entsprechend kann man auch ganze Arrays aus Funktionen zurückgeben. In C landet man da schnell auf der Schnauze, da Array Variablen nur Zeiger aus das erste Element sind. Man würde also einen Zeiger auf ungültigen Speicher zurückgeben.
Hallo
vielen dank est mal für deinen ausführlichen Bericht. Ich beschäftige mich ehr mit SPS Programiereung.
Ich versuche grande Werte von einem Arduino in eine SPS zu übertragen. Hierzu muss ich ein float in Byte wandeln und drehen.
Habe es jetzt mit deiner Hilfe so gelöst.
Ich hoffe das ist so korrekt ?
#include <SPI.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
}
void loop() {
// Float
float Zahl1=123.45;
Serial.println(Zahl1 );
byte*b = S7Float_to_Byte(Zahl1);
Serial.print(b[0]);
Serial.print(b[1]);
Serial.print(b[2]);
Serial.println(b[3]);
delay(2000);
}
// Funktion Float in Byte, Byte drehen
byte* S7Float_to_Byte(const float inFloat )
{
byte bigEndian[4];
byte* bytes = (byte*)&inFloat;
bigEndian[0] = bytes[3];
bigEndian[1] = bytes[2];
bigEndian[2] = bytes[1];
bigEndian[3] = bytes[0];
return bigEndian;
}
static byte buffer[4];
Dann sollte es theoretisch gehen. Das static sorgt dafür, dass der Speicher dauerhaft existiert und nicht am Ende der Funktion wieder freigegeben wird. Lokale static Variablen verhalten sich im Prinzip wie globale Variablen, aber sind nur lokal sichtbar.
Lokale nicht-static Variablen existieren nur solange du in der Funktion bist. Entsprechend kann man keine Zeiger darauf zurückgeben. Der Compiler erlaubt das natürlich und das Programm läuft auch. Aber wenn du dann außerhalb auf den Speicher über den Zeiger zugreifst steht da vielleicht schon wieder was anderes drin.
Hallo
ich musste es doch so wie du beschrieben hast lösen da ich die Funktion mehrfach verwenden muss
#include <SPI.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
}
void loop() {
//Var
float Zahl[11];
byte bigEndian[4];
Zahl[0]=0.01;
Zahl[1]=11.11;
Zahl[2]=22.22;
Zahl[3]=33.33;
Zahl[4]=44.44;
Zahl[5]=55.55;
Zahl[6]=66.66;
Zahl[7]=77.77;
Zahl[8]=88.88;
Zahl[9]=99.99;
Zahl[10]=10.10;
for (int i=0; i <= 10; i++){
Serial.println(Zahl[i]);
S7Float_to_Byte(Zahl[i], bigEndian);
Serial.print(bigEndian[0]);
Serial.print(bigEndian[1]);
Serial.print(bigEndian[2]);
Serial.println(bigEndian[3]);
delay(10);
}
delay(2000);
}
// Funktion Float in Byte, Byte drehen
byte* S7Float_to_Byte(const float inFloat, byte* buffer)
{
byte* bytes = (byte*)&inFloat;
buffer[0] = bytes[3];
buffer[1] = bytes[2];
buffer[2] = bytes[1];
buffer[3] = bytes[0];
return buffer;
}
Ich muss jetzt nur noch den speicherbrecht byte bigEndian[4]; löschen. Wenn nicht alle Arrays belegt sind kommen sonnst falsche werte bei den nicht belegten Arrays an.
memset():
http://www.cplusplus.com/reference/cstring/memset/
memset(bigEndian, 0, 4);
Verstehe aber nicht wirklich wozu, da die Funktion alle 4 Bytes beschreibt.
Das Problem ist wenn ich nicht in alle Arrays eine Zahl lege erhalte ich falsche werte in der Ausgabe bigEndian der nicht belegten Araays
funktioniert
float Zahl[11];
byte bigEndian[4];
Zahl[0]=1.01;
Zahl[1]=11.11;
Zahl[2]=22.22;
Zahl[3]=33.33;
Zahl[4]=44.44;
Zahl[5]=55.55;
Zahl[6]=0;
Zahl[7]=0;
Zahl[8]=0;
Zahl[9]=0;
Zahl[10]=0;
funktioniert nicht.
float Zahl[11];
byte bigEndian[4];
Zahl[0]=1.01;
Zahl[1]=11.11;
Zahl[2]=22.22;
Zahl[3]=33.33;
Zahl[4]=44.44;
Zahl[5]=55.55;
Ok, du willst zahl[] löschen. Nicht bigEndian[]
Verwende Array Initialisierer. Dann klappt das auch auf Anhieb:
float zahl[11] = { 1.0, 2.0 };
Damit wird der Rest automatisch auf 0.0 initialisiert.
Ansonsten memset(zahl, 0, sizeof(zahl));
Das ist aber nicht nötig wenn man es gleich richtig initialisiert. Außerdem sind die geschweiften Klammern übersichtlicher.
Wenn ich nochmal ganz kurz auf int -> byte zurückkommen darf: Was ist die schnellste Variante, um einen vom ADC gelesenen Wert auf 8 Bit runterzubrechen?
So?
byte high = i >> 8;