Float von anderer Steuerung einlesen

Hallo,

ich habe eine kleine Steuerung (µC 8051 mit Wickenhäuser Compiler) an IPS. Dort ist ein Wert als Float abgelegt (müßte 4 Byte sein). Diesen will ich übertragen und auch als Float in IPS verwenden. Die Daten bekomme ich schon als $inbuf[1…4]. Wie kann ich aus diesen Werten wieder ein Float machen? Pointer mit Float und $inbuf[1…4] auf selbe Adresse? Habe noch zu wenig Erfahrungen mit diesen Werten.
Wer kann helfen?

Hallo,

ein Beispielscript wie Du es auswertest wäre sehr hilfreich.

Ansonsten probier mal (float).

In Delphi sieht es so aus:

procedure TForm7.FormShow(Sender: TObject);
var
f1 : single;
a : array[1…4] of byte absolute f1;

inbuf : array[1…4] of byte;

begin

//die Werte kommen schon von meiner Übertragungsroutine
inbuf[1]:=65;
inbuf[2]:=159;
inbuf[3]:=173;
inbuf[4]:=212;

a[4]:=inbuf[1];
a[3]:=inbuf[2];
a[2]:=inbuf[3];
a[1]:=inbuf[4];

Label1.Caption:= FloatToStr(f1);

end;

In Delphi kann ich Werte übereinanderlegen, d.h. als array speichern und als float(single) auslesen mittels „absolute“.
Da ja hoffentlich die Speicherung der Float Werte in beiden Steuerungen gleich ist, sollte dann als Resultat auch das gleiche rauskommen.
Ich hoffe, mit diesen Informationen kann man was anfangen. Ein Auslesen aus dem µC und Umrechnen in Delphi bringt jedenfalls die korrekten Resultate.

Hallo,

ich dachte eher an die Auswertung in IPS mit PHP.

Irgendwie musst Du ja die Daten nach IPS bekommen.

Ja, ich will alles im IPS machen. Dies war nur ein Beispiel, wie ich es mit Delphi machen würde.

Der Puffer $inbuf[1…4] ist schon im IPS. Den hole ich mittels einen Comportaufrufes schon vom µC. Die Werte sind an sich schon in IPS, nur diese 4 Bytes muss ich in einen Float umgewandelt bekommen.

Die Werte sind an sich schon in IPS, nur diese 4 Bytes muss ich in einen Float umgewandelt bekommen.

Genau das wollte ich sehen in PHP.

SetValueString("V24_InBuffer",""); // clear Buffer

  $string = "Anfrage float";

  COMPort_SendText(50911, $string);

  while (strlen(GetValueString("V24_InBuffer"))<6) ;

  $inbuf = GetValueString("V24_InBuffer");

  if (ord($inbuf[0])==1) {  //wenn Anwort OK vom Protokoll
  
   
   return ("Laenge = ".strlen($inbuf)."|".ord($inbuf[0])."|".ord($inbuf[1])."|".ord($inbuf[2])."|".ord($inbuf[3])."|".ord($inbuf[4])."|".ord($inbuf[5])."|".ord($inbuf[6]));

//hier werden Werte angezeigt; in $inbuf 1..4 stehen dann die Werte, wie oben schon beschrieben.


    //return ($inbuf[1]);
  }
  else
    return 255; //error

Hat keiner eine Idee?
Im Grunde genommen kopiere ich nur ein Speicherabbild von einer Steuerung in eine andere. Da ja offensichtlich auch der Typ „float“ bei beiden Steuerungn gleich ist, sollte man das Speicherabbild von Steuerung 1 in Steuerung 2 schieben können. Der Wert, der dann angezeigt werden sollte, sollte bei beiden wieder gleich sein.
Letzten Endes könnte ich mir einen Speicherbereich aus Steuerung 1 reservieren, dann den Float mit sprintf reinschreiben, dann diese Bytes übertragen und mittels einer PHP Funktion wieder in ein „float“ umwandeln. Da ich aber aus verschiedenen Steuerungen diverse Werte holen will, wäre mir ein Kopieren des Speicherabbildes (jeweils ein Wert) lieber. Wenn ich ein Byte aus Steuerung 1 hole und dann in Steuerung 2 ablege, geht das ja auch. Mit Integer wirds es dann schon kniffliger, da zu beachten ist, welches Byte low und welches high ist. Aber man kann es schon zusammenbauen mittels $wert= $inbuf[1]*256 + $inbuf[2].

Diese Funktion sollte tun, was du benötigst: http://de.php.net/pack

paresy

Habs zwar immer noch nicht verstanden.

 $inbuf[4] = "212";
 $Ausgabe = $inbuf[4];
 echo $Ausgabe;

wenn in deinem inbuf 212 steht und Du diese weitergeben willst, speichere sie doch ab und ruf sie wieder auf.

SetValueFloat,Interger, oder was auch immer.:confused:

Ich versuch’s mit „pack“, aber nochmal zur Erklärung.
Jedes „float“ wird normalerweise in 4 Bytes abgespeichtert. Anzusprechen ist der Wert dann immer mit „$wert“. Dahinter verbergen sich aber 4 Bytes. In Steuerung 2 (IPS) hat man auch einen Wert „$wert2“. Dieser hat intern auch 4 Bytes. Wenn man nun die 4 Bytes nimmt und in die neue Steuerung überträgt, dann sollte man unter „$wert2“ auch wieder den gleichen Wert haben.

So in der Art.

$inbuf[1] = 65;
 $inbuf[2] = 159;
 $inbuf[3] = 173;
 $inbuf[4] = 212;
 $wert = $inbuf[1].$inbuf[2].$inbuf[3].$inbuf[4];
 echo $wert;
 
 COMPort_SendText(50911, $wert);

Hallo,

ich habe im Netz folgende Funktion gefunden, mit der es offensichtlich erst einmal geht.
Vielen Dank trotzdem für Eure Bemühungen.

http://de.php.net/manual/de/language.types.float.php

Einige Zeilen nach unten ist Funktion „function bin2float ($bin)“ zu finden.
Möglicherweise gibt es eine einfachere Funktion, aber ich habe schon alles mögliche probiert (inkl. Eurer Tipps)

Hallo zeras,

wie lautet denn der zu Deinem Beispiel gehörige Float-Wert?

Wenn ich den kenne, könnte ich eine Berechnungsfunktion erstellen.

Vielleicht kannst Du auch ein Beispiel mit negativem Wert und eines mit einem Wert kleiner als 1 nennen.

Gruß
HJH

Hier nochmal die Anzeige, in Delphi programmiert.
Rausgekommen ist: 19,9598770141602
In der Steuerung wird die Temperatur gelesen, die ich dann ab und zu in IPS einlesen will.
Mit der besagten Formel scheint es erst mal zu gehen, bei Werten um die 20°C. Im Moment werden 17 °C angezeigt.
Das passt ja mit der Aussentemperatur zusammen. Andere Werte habe ich noch nicht. Mal sehen, wenn es kälter wird.
Wenn man die float Variable im PHP direkt beschreiben könnte (jedes Byte einzeln), dann wäre das Problem gelöst. Ich denke, dass dies auch in C geht, aber in Delphi habe ich mehr Erfahrung.

Hier die Funktion nochmals, die ich zum Test geschrieben habe.

procedure TForm7.FormShow(Sender: TObject);
var
f1 : single;
a : array[1…4] of byte absolute f1;
inbuf : array[1…4] of byte;

begin

//die Werte kommen schon von meiner Übertragungsroutine
inbuf[1]:=65;
inbuf[2]:=159;
inbuf[3]:=173;
inbuf[4]:=212;

a[4]:=inbuf[1];
a[3]:=inbuf[2];
a[2]:=inbuf[3];
a[1]:=inbuf[4];

Label1.Caption:= FloatToStr(f1);

end;

Hallo zeras,

das folgende Skript berechnet aus 4 Byte eine 32bit Gleitkommazahl nach IEEE-Standard (siehe http://de.wikipedia.org/wiki/Gleitkommazahl).

// Float-Berechnung nach IEEE (siehe: http://de.wikipedia.org/wiki/Gleitkommazahl)
$inbuf = array(65, 159, 173, 212);

$s = ($inbuf[0] & 0x80) >> 7;                                   // Vorzeichen ermitteln
$c = ((($inbuf[0] & 0x7f) <<  8) | ($inbuf[1] & 0x80)) >> 7;    // Charakteristik ermitteln
$e = $c - 127;                                                  // aus der Charakteristik den Exponenten ermitteln
$m = (($inbuf[1] & 0x7f) << 16) | ($inbuf[2] << 8) | $inbuf[3]; // Mantisse ermitteln
$m = 1 + $m/8388608;                                            // Mantisse korrigieren

$temperatur = pow(-1, $s) * $m * pow(2, $e);                    // Float-Wert berechnen

Das Skript führt mit den von Dir angegebenen Werten zum selben Ergebnis: 19.95987701416

Völlig ohne Rechenaufwand ginge es, wenn man wie in C oder Delphi zwei Variablen im Speicher übereinander legen könnte. Aber eine solche Möglichkeit ist mir in PHP nicht bekannt.

Gruß
HJH

Dann will ich auch mal :slight_smile:


$a = array(65, 159, 173, 212); 

$val = unpack("f", chr($a[3]).chr($a[2]).chr($a[1]).chr($a[0]));

echo $val[1];

paresy

Hallo paresy,

Du hast Recht, es funktioniert mit der unpack-Funktion einwandfrei. :slight_smile:

Ich bin darüber allerdings ziemlich überrascht, da PHP im Manual den Eindruck erweckt, dass es gar keine 32bit Float-Werte (single) kennt, sondern nur 64bit (double).

Aber das ist nicht der einzige Punkt, wo das Manual bisweilen ungenau oder gar widersprüchlich ist. :o

Auf jeden Fall ist die Lösung sehr elegant.

Kennst Du vielleicht eine Möglichkeit, wie man mit Adressen und Zeigern das von zeras verwendete „absolute“-Verfahren von Delphi nachbilden kann?

Gruß
HJH

wie schon HJH berichtet, geht es, nur habe ich Probleme mit der automatischen Typkonvertierung. Für mich als Delphiprogrammierer ist das ein Riesennachteil bei PHP. Wenn es in Delphi nicht paßt, dann kommt eine Fehlermeldung, bei PHP wird irgendwas gerechnet. Es muss aber nicht immer passen.
Danke trotzdem für die Tipps. Jetzt kann ich sehen, wie sich die Aussentemperatur verhält.

Oh ja… Willkommen im Club…

Mir hat das wissen um diese Funktion ein ruhiges Gefühl gegeben in PHP. Die Variable ist zwar immernoch „unisex“ aber sie wird intern als float zwangs-betitelt.

Das ist zwar auch nicht Idiotensicher, aber wenn man sauber programmiert kann es einem nicht passieren, dass man versehendlich den falschen Typ am Wickel hat.

Gruß,

Toni