Zu doof für byte-Umrechnung ...

  • Themenstarter Themenstarter tuxedo
  • Beginndatum Beginndatum
T

tuxedo

Gast
Hallo zusammen,

ich seh mal wieder den Wald vor lauter Bäumen nicht...

Ich hab ein Thermometer, welches seinen Messwert in Form von 2 bytes liefert.

Die Beschreibung zu dem Gerät sagt folgendes:

Die Daten werden jeweils in Bytes übertragen, bei den 24-Bit-/16-Bit-Werten das hochwertigere zuerst (MSB First).
...
Für die Temperatur wird ein vorzeichenbehafteter Integer-Wert verwendet.

Mehr gibt die Anleitung zu dem Thema nicht her.

Die zu lesende Temperatur ist ein solcher 16-bit-Wert (also 2 Bytes). Hinzu kommt, das der Wert in 0,1°C gefasst ist.

Ergo:

-257 = -25,7°C
138 = 13,8°C

Soweit so gut. Ich kriegs jetzt aber nicht gebacken die zwei Byte in einen brauchbaren Integerwert von z.B. -257 oder 138 zu konvertieren.

Meine Ansätze waren bisher:
Java:
int  i = ((b[0] << 8) + (b[1] << 0));

int  i = ((b[0] << 8) + (b[1] << 0)) & 0xff;

int  i = ((b[0] << 8) + (b[1] << 0)) & 0xffff;

Je nachdem welche Werte ich hineingefüttert habe hat die eine oder andere Variante besser oder schlechter funktioniert. Aber keine hat mit sämtlichen Temperaturbereichen funktioniert.

Hab ein kleines Testprogram gebastelt und darin ein paar reelle Messwerte eingefügt:

Java:
public class Tester {

    public static void main(String[] args) {
        byte[] data = new byte[2];
        int i;

        data[0] = 1; // erstes byte
        data[1] = -128; // zweites byte
        i = 384; // zum prüfen: das hier sollte das umformen von byte->int ergeben
        check(data, i);

        data[0] = 1;
        data[1] = 100;
        i = 356;
        check(data, i);

        data[0] = 1;
        data[1] = 0;
        i = 256;
        check(data, i);

        data[0] = 0;
        data[1] = -35;
        i = 221;
        check(data, i);


        data[0] = 0;
        data[1] = 91;
        i = 91;
        check(data, i);


        data[0] = -1;
        data[1] = 109;
        i = -147;
        check(data, i);


        data[0] = -1;
        data[1] = 71;
        i = -185;
        check(data, i);


        data[0] = -1;
        data[1] = -127;
        i = -127;
        check(data, i);
        
    }

    static void check(byte[] b, int i) {
        System.out.println("\nChecking ... b0="+b[0]+" b1="+b[1]+" i="+i);

        int calc = getInt(b);

        System.out.println("calc="+Integer.toBinaryString(calc));
        System.out.println("   i="+Integer.toBinaryString(i));

        if (calc!=i) {
            System.out.println("****** Check NOT OKAY");
        } else {
            System.out.println("###### Check okay");
        }

    }

    static int getInt(byte[] b) {
        System.out.println("b0="+Integer.toBinaryString(b[0])); 
        System.out.println("b1="+Integer.toBinaryString(b[1]));
        return ((b[0] << 8) + (b[1] << 0)); // <------------ Hier stimmt was nicht. HILFE!
    }

}

Kann mir vielleicht jemand unter die Arme greifen und mir 'nen heißen Tipp für die getInt() Methode geben der bei allen Wertebereichen funktioniert?

- Alex
 
Also Arithmetik ist bei solchen Sachen gefährlich - wenn man bits verORen will, sollte man sie such verORen, und nicht versuchen, dort was mit "+" zu addieren - das funktioniert nur in Spezialfällen, und Vorzeichen sind selbst dann noch Stolperfallen.
Außerdem muss man bei negativen Werten aufpassen: Wenn die eigentlich nur für ein paar gesetzte Bits im untersten byte stehen (und NICHT für einen negativen Wert) dann bekommt man bei der Umwandlung nach int u.U. 1en, wo keine hin sollten. Notfalls mit 0xFF verANDen.

Ungefähr so dürfte das eher hinkommen
Java:
    static int getInt(byte[] b) {
        System.out.println("b0  ="+Integer.toBinaryString(b[0]));
        System.out.println("b1  ="+Integer.toBinaryString(b[1]));
        int result = (
            ((b[0]       ) << 8) |
            ((b[1] & 0xFF) << 0));
        return result;
    }
 
Hmm, leuchtet ein. Das mit dem + hatte ich mir beim DataInputStream abgeschaut:

Java:
public final int readInt() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }

... und nicht mehr weiter drüber nachgedacht. --> Fehler. Dort geht's wohl, da die bytes vor dem Senden scho mit "&0xff" behandelt werden..

Mit deinem Ansatz funktioniert's jetzt mit allen bisher gemessenen Wertebereichen. Danke hierfür.

Gruß
Alex
 
Hmja, die "bytes" die da gelesen werden, werden ja als ints (zwischen 0 und 255) zurückgegeben. Bei readInt steht interessanterweise aber auch dabei

The value returned is:

(((a & 0xff) << 24) | ((b & 0xff) << 16) |
((c & 0xff) << 8) | (d & 0xff))

...
 

Zurück
Oben