Probleme mit Byte konvertieren nach int

Chefselber

Mitglied
Hallo Gemeinde,

ich habe folgendes Problem:
Ich schicke von einem Automatisierungssystem 200Byte Pakete an einen PC. Soweit so gut.
Wert in 4 Bytes.
Nun habe ich fest gestellt, dass manche Werte nicht richtig dargestellt werden.

Beispiele für Temperaturwerte:
Wert in SPS
127°C -> Byte [0] = 0x00 , Byte [1] = 0x00 , Byte[2] = 0x00 , Byte[3] = 0x7F
kommt in Java so an:
tempbytes[0] = 0, tempbytes[1]=0, tempbytes[2] = 0, tempbytes[3]=127

float l = (float)ByteBuffer.wrap(tempbytes).order(ByteOrder.BIG_ENDIAN).getInt();
= 127.0

alles ok soweit.

Jetzt mal 650°C
650°C -> Byte[0] = 0x00, Byte[1] = 0x00, Byte[2] = 0x02, Byte[3] = 0x8A
kommt in Java so an:
tempbytes[0] = 0, tempbytes[1]=0, tempbytes[2] = 2, tempbytes[3]=96
ergibt nach
float l = (float)ByteBuffer.wrap(tempbytes).order(ByteOrder.BIG_ENDIAN).getInt();

= 608.0

Java kann Bytes von -128 bis 127.
Wie kann ich das umwandeln? Ich verstehe die Logik dahinter nicht.

z.B.
128°C -> Byte [0] = 0 , Byte [1] = 0 , Byte[2] = 0 , Byte[3] = 80
kommt in Java so an:
tempbytes[0] = 0, tempbytes[1]=0, tempbytes[2] = 0, tempbytes[3]=-84
Also ist 128 -> in Java 0 0 0 -84

float l = (float)ByteBuffer.wrap(tempbytes).order(ByteOrder.BIG_ENDIAN).getInt();

= 172.0

Lt. Bitmuster sollte doch hier für 128 doch 10000000 rauskommen?

Wenn ich 0x80 & 0xFF maskiere bekomme ich 172 als int Wert.

Weiss hier jemand Rat?

Gruss Chef
 
Wenn ich 0x80 & 0xFF maskiere bekomme ich 172 als int Wert.
Bitte immer den kompletten Code mit angeben, der die unerwünschten Ergebnisse produziert.
Was genau ist Byte[] bei dir? Wie genau setzt du die einzelnen Elemente? Und was genau ist tempbytes[]? Wie genau werden diese befüllt?

Und 0x80 & 0xFF ist bei mir 128:
Java:
public class Bytes {
  public static void main(String[] args) {
    byte b = (byte) 0x80;
    int v = b & 0xFF;
    System.out.println(v); // <- Ausgabe: 128
  }
}

Und auch ein byte[] bytes = {0x00, 0x00, 0x02, (byte) 0x8A}; wird in BigEndian interpretiert zu einem 650:
Java:
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class Bytes {
  public static void main(String[] args) {
    byte[] bytes = {
      0x00, 0x00, 0x02, (byte) 0x8A
    };
    int integer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
    System.out.println(integer); // Ausgabe: 650
  }
}
 
Das Problem ist tatsächlich, dass die Bytes mit Vorzeichen gespeichert werden in Java.

Byte hat eine Methode toUnsignedInt, welche man hier verwenden könnte:

Java:
public class IntTest {
    @Test
    public void testByteTranslations() {
        byte bytes[] = { 0, 0, 0, -84 };
        int i = Byte.toUnsignedInt(bytes[3]) +
                + (Byte.toUnsignedInt(bytes[2]) << 8)
                + (Byte.toUnsignedInt(bytes[1]) << 16)
                + (Byte.toUnsignedInt(bytes[0]) << 24);

        System.out.println(i);
    }
}
 
Erstmal Danke für eure Antworten,

habe jetzt mal den Code angehängt.
Auch die SPS Übergabe.

Ich weiss keinen Rat.

Kommt definitiv im x[183] = 0x80 an?
Kann ich das irgendwie überprüfen?

Warum steht hier -84?




Java:
...
      datenlesen = new InputStreamReader(socket.getInputStream()); //Datenstrom vorbereiten

      ...
      byte[] Werte = new byte[201];
      for (int c=1; c<=200;c++)
        {
            try {
                y= (byte)datenlesen.read();
            } catch (IOException ex) {
                Logger.getLogger(Verbinden_thread.class.getName()).log(Level.SEVERE, null, ex);
                Haupt.Status("konnte keine Daten lesen", false);
                return;
            }
         
        Werte[c-1]=y;    
        Werteeintragen(Werte);
       ...
      public static void Werteeintragen(byte[] x)
      {
        byte[] tempbytes = { x[180], x[181],x[182],x[183] };
        float l = (float)ByteBuffer.wrap(tempbytes).order(ByteOrder.BIG_ENDIAN).getInt();
   
       System.out.println("Temperatur: " + l);
 
       jTextFieldKesselmax1.setText(bytesToString(new byte[] {x[180],x[181],x[182],x[183]}, (float) 1.0));


  // Wandeln der ankommenden Bytes in formatierten String
    public static String bytesToString(byte[] bytes, float teilung) 
    {
     String konvert;    
     float ergebnis;
     byte[] tempbytes = { bytes[0],bytes[1],bytes[2],bytes[3] };
     int l = ByteBuffer.wrap(tempbytes).getInt(); 
     ergebnis = l / teilung;
     konvert =  String.format("%.2f",ergebnis);
     return konvert;
    }
Bild2.jpg

Also als Ausgabe: 0 0 0 -84
und mit &FF maskiert: 0 0 0 172
 
Zuletzt bearbeitet:
Übertrage jetzt einen Realwert: 128.0
also

43 00 00 00

x[180]= 43
x[181]= 00
x[182]= 00
x[183]= 00

und dieser wird dann mittels

Java:
 public static float byteArrayToFloat(byte[] bytes) {
    int intBits =
    bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
    return Float.intBitsToFloat(intBits); 
}

auch nach 128.0 konvertiert.

Bei z.B. 650.0
44 22 80 00
also
x[180]= 44
x[181]= 22
x[182]= 80
x[183]= 00

kommt 650.69 raus.

Also es gibt nach wie vor ein Problem größer 0x7F.
Aber ich kann damit leben
 
Übertrage jetzt einen Realwert: 128.0
also

43 00 00 00

x[180]= 43
x[181]= 00
x[182]= 00
x[183]= 00

und dieser wird dann mittels

Java:
 public static float byteArrayToFloat(byte[] bytes) {
    int intBits =
    bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
    return Float.intBitsToFloat(intBits);
}

auch nach 128.0 konvertiert.

Bei z.B. 650.0
44 22 80 00
also
x[180]= 44
x[181]= 22
x[182]= 80
x[183]= 00

kommt 650.69 raus.

Also es gibt nach wie vor ein Problem größer 0x7F.
Aber ich kann damit leben

Die "80" verfolgt mich weiterhin, steht sie nämlich in einem anderen Byte gibts weiterhin Probleme.
 
Java:
byte[] buf = { 0x44, 0x22, (byte)0x80, 0x00 };
float value = ByteBuffer.wrap(buf).order(ByteOrder.BIG_ENDIAN).getFloat();
System.out.println(value);

Nachtrag: Deine Methode funktioniert im Prinzip genauso, nur dass die Reihenfolge falsch ist:

Java:
byte[] buf = { 0x44, 0x22, (byte)0x80, 0x00 };
int intValue = ((buf[0] & 0xff) << 24) | ((buf[1] & 0xff) << 16) | ((buf[2] & 0xff) << 8) | (buf[3] & 0xff);
float value = Float.intBitsToFloat(intValue);
System.out.println(value);
 
Zuletzt bearbeitet:
Hab mal etwas nach geforscht und Wireshark aktiviert, da ich schon Bedenken hatte, dass das Automatisierungssystem irgendwelche spuchten macht.
Es wird genau das übertragen was ich weg schicke.

Aber alles was über Byte 127 bzw. 7F und 159 bzw. 9F ist wird falsch interpretiert, egal in welchem Byte.

In dem Bild die ersten 4 Bytes sind Dezimal 131. Also in Byte 00 00 00 83
wird mit 0xFF maskiert als 146 dargestellt.

Es ist ansonsten alles richtig sobald sich keine "80" "81" "83" usw... bis "9F" in einem Byte befindet.

links gesendet, rechts dargestellt maskiert mit 0xFF in JAVA - Netbeans
7D (125) = 125 i.O
7E (126) = 126 i.O.
7F (127) = 127 i.O.

ab hier kommen komische Werte

80 (128) = 172 ?
81 (129) = 253 ?
82 (130) = 26 ?
83 (131) = 146 ?
84 (132) = 30 ?
85 (133) = 38 ?
86 (134) = 32 ?
usw....
geht bis
9F (159) = 120 ?

Komischerweise genau 4 Bytes (32 Werte) die Probleme machen.


ab hier stimmts wieder

A0 (160) = 160
A1 (161) = 161
A2 (162) = 162

80 - 9F machen Probleme. Unterhalb und oberhalb des Bereiches gibt es keine Probleme.

Ich versteh es nicht.

Vielleicht liegt es ja daran?
Java:
byte y;
datenlesen = new InputStreamReader(socket.getInputStream());
y = (byte)datenlesen.read();

Hab auch schon folgendes getestet:
Java:
int y;
datenlesen = new InputStreamReader(socket.getInputStream());
y = datenlesen.read();
 

Anhänge

  • Bild1.png
    Bild1.png
    21,6 KB · Aufrufe: 1
Zuletzt bearbeitet:
Vielleicht liegt es ja daran?
Java:
byte y;
datenlesen = new InputStreamReader(socket.getInputStream());
y = (byte)datenlesen.read();
InputStreamReader#read liest Character, keine Bytes - also mindestens eins, aber nicht genau ein Byte!

Bis 0x80 wird (zumindest mit UTF-8, umgestellt hast du das wahrscheinlich nicht) nur ein Byte gelesen, daher sieht es bis dahin normal aus. Ab 0x80 gibt es undefinierte Bereiche bzw es werden mehr als 1 Byte gelesen, daher ist es ab da "kaputt".

Den Reader kannst du an der Stelle einfach weglassen und direkt den InputStream nutzen.
 
Zuletzt bearbeitet:

Zurück
Oben