Forum: PC-Programmierung HEX in signed Short umrechnen


von Michael Z. (buddhafragt)


Lesenswert?

Hallo,
ich habe ein Problem, an dem ich mir gerade die Zähne ausbeisse:

Ich bekomme von einem CAN Bus 2 Bytes in Hex, die ich in ein signed 
Short umwandeln muß.
Mit unsigned ist das simpel: LSB+(MSB*255)
Mit signed bekomme ich es nicht hin.

Gruß, Michael

von Walter S. (avatar)


Lesenswert?

Michael Z. schrieb:
> 255

bist du da sicher?

von Michael Z. (buddhafragt)


Lesenswert?

Walter S. schrieb:
> Michael Z. schrieb:
>> 255
>
> bist du da sicher?

Nein, 256.... !! Tippfehler...... ;-)

von BS (Gast)


Lesenswert?

Das höchste Bit zeigt das Vorzeichen an. Im Prinzip wie geschrieben 
umrechnen:
Result = LSB +( MSB << 8)
Wenn das Ergebnis > 32767 ist, Zweierkomplement berechnen:
Result = (~Result) - 1.

Mit int16 reicht schon
Int16 Result = (int16) (LSB + (MSB << 8),
das wird dann schon richtig interpretiert.

von Oliver S. (oliverso)


Lesenswert?

BS schrieb:
> Result = LSB +( MSB << 8)
> Wenn das Ergebnis > 32767 ist, Zweierkomplement berechnen:
> Result = (~Result) - 1.

Wenn das, was über den Bus angeliefert wird, schon ein signed short ist 
(wovon ich ausgehen), dann muß nichts mehr umgerechnet werden. Die 
beiden (unsigned) bytes in der richtigen Reihenfolge in einen usigned 
short schieben, das Ergebnis nach signed short casten, fertig.

Oliver

: Bearbeitet durch User
von GeraldB (Gast)


Lesenswert?

BS schrieb:
> Result = (~Result) - 1.

Zweierkomplement ist aber
Result = (~Result) + 1.

von c-hater (Gast)


Lesenswert?

Oliver S. schrieb:

> Wenn das, was über den Bus angeliefert wird, schon ein signed short ist
> (wovon ich ausgehen), dann muß nichts mehr umgerechnet werden. Die
> beiden (unsigned) bytes in der richtigen Reihenfolge in einen usigned
> short schieben, das Ergebnis nach signed short casten, fertig.

Vorsichtig. Das stimmt so nur, wenn Quell- und Zielsystem gleichermaßen 
zur Darstellung von negativen Zahlen das Zweierkomplement verwenden. 
Allerdings: wenn beide Systeme aus der Nach-Steinzeit stammen, kann man 
davon ausgehen, das es so ist...

Aber nach der reinen Lehre muss man halt davon ausgehen, das es nicht so 
ist.

Die C-Fetischisten fahren voll auf solchen historischen Dreck ab, 
genauso wie auf Bytes (ähm: chars), die keine 8 Bit haben usw.

Das kommt davon, wenn eine Sprache viel zu alt ist und niemals 
sinnvoll weiterentwickelt wurde, was auch heißen muss: alte Zöpfe 
einfach mal irgendwann abzuschneiden.

Hatte wohl niemand Lust, die Specs umzuschreiben, denn schon diese 
beiden kleinen Sachen zu "normalisieren" (sprich: an die objektive 
Realität anzupassen) rüttelt gehörig an den Grundfesten von C...

Und es gäbe da noch einiges mehr zu "normalisieren"...

Aber ich sehe das inzwischen gelassen. Auf Dauer wird die Evolution ihr 
Werk tun. Entweder C passt sich an oder es wird irgendwann verschwinden. 
So einfach ist das. Inzwischen (schon eine ganze Weile...) gibt es ja 
Sprachen mit modernen Konzepten, die all das können, was C kann, aber 
den ganzen historischen Ballast von C nicht mitschleppen müssen...

Nur die riesige Codebasis rettet C bisher. Dank der vielen C&Pler, die 
sich "Programmierer" nennen...

von Michael Z. (buddhafragt)


Lesenswert?

Vielen Dank für eure Hilfe,
ich habe es jetzt so gelöst:

(((B1+(B0*256))-65536)+1)

von Oliver S. (oliverso)


Lesenswert?

c-hater schrieb:
> Aber nach der reinen Lehre muss man halt davon ausgehen, das es nicht so
> ist.
>
> Die C-Fetischisten fahren voll auf solchen historischen Dreck ab,
> genauso wie auf Bytes (ähm: chars), die keine 8 Bit haben usw.
>
> Das kommt davon, wenn eine Sprache viel zu alt ist und niemals
> sinnvoll weiterentwickelt wurde, was auch heißen muss: alte Zöpfe
> einfach mal irgendwann abzuschneiden.

Oh mann...

Ja, du hast theoretisch recht, aber gib es zu: Auch dir ist noch nie ein 
System unter die Finger gekommen, welches was anders als 
Zweierkomplement zur Dastellung negativer Zahlen benutzt hat. Schon gar 
nicht eines, das so modern ist, daß es CAN-Bus hat (also weniger als 
30-40 Jahr alt).

Insofern ist das einfach Geschwafel.

Michael Z. schrieb:
> ich habe es jetzt so gelöst:
>
> (((B1+(B0*256))-65536)+1)

Warum? Was genau bezweckst du damit?

Oliver

: Bearbeitet durch User
von Michael Z. (buddhafragt)


Lesenswert?

Oliver S. schrieb:
> Warum? Was genau bezweckst du damit?

Umrechnung ins Zweierkomplement!

von zitter_ned_aso (Gast)


Lesenswert?

steht "B" in MSB / LSB eigentlich nicht für "Bit"?

von Oliver S. (oliverso)


Lesenswert?

Michael Z. schrieb:
> Umrechnung ins Zweierkomplement!

Von was?
Damit das nicht in hundert Beiträge mit je einer Zeile ausartet:

Was ist das für ein Datentyp, der dir im zwei Bytes aufgeteilt über den 
Can-Bus angeliefert wird?

Oliver

von Klaus S. (skibby)


Lesenswert?

(int16_t)((MSB<<8)+LSB) sollte es auch tun (falls LSB und MSB jeweils 
uint8_t sind)

von Michael Z. (buddhafragt)


Lesenswert?

Oliver S. schrieb:
> Michael Z. schrieb:
>> Umrechnung ins Zweierkomplement!
>
> Von was?
> Damit das nicht in hundert Beiträge mit je einer Zeile ausartet:
>
> Was ist das für ein Datentyp, der dir im zwei Bytes aufgeteilt über den
> Can-Bus angeliefert wird?
>
> Oliver

Nun,
die definition des CAN Bus Protokolls ist 8 x ein Byte, nicht wahr?
Wenn also ein Word übermittelt werden soll, geschieht das über 2 Bytes. 
Die definition, ob es signed oder unsigned ist, ist hier noch nicht 
festgelegt, sondern muß bei der Zusammenführung der beiden Bytes dann 
berücksichtigt werden.
Der Datentyp ist signed Word!

von NichtWichtig (Gast)


Lesenswert?

zitter_ned_aso schrieb:
> steht "B" in MSB / LSB eigentlich nicht für "Bit"?

Jupp

Daumen hoch

von Oliver S. (oliverso)


Lesenswert?

Michael Z. schrieb:
> Die definition, ob es signed oder unsigned ist, ist hier noch nicht
> festgelegt, sondern muß bei der Zusammenführung der beiden Bytes dann
> berücksichtigt werden.
> Der Datentyp ist signed Word!

Du hast es nicht verstanden...

Natürlich sind die Bytes auf dem Bus einfach nur 8 bit.

Aber die Definition, was diese Bits bedeuten, wird im Absender 
definiert. Der zerlegt einen 16-Bit Datentyp in zwei Bytes, und was das 
für ein Datentyp ist, und wie der den zerlegt, musst du in dessen Spec 
nachschauen.

Und wie jetzt schon mehrfach geschrieben wurde, wäre alles andere als 
ein schlichtes aneinanderhängen der beiden Bytes im Empfänger äusserst 
seltsam.

Ein manuelles Umrechnen von 16 bit unsigned in ein 
16-bit-signed-Zweierkomplement ist dazu eh völlig sinnlos.

Entweder interpretierst du die 16 Bit des Ausgangswertes als 16 bit 
unsigned, dann gibt es per Definition keine negativen Zahlen, oder du 
interpretierst die 16 bit des Ausgangswertes als signed, dann sind die 
schon im Zweierkomplement.

Oliver

: Bearbeitet durch User
von Michael Z. (buddhafragt)


Lesenswert?

Oliver S. schrieb:
> Aber die Definition, was diese Bits bedeuten, wird im Absender
> definiert. Der zerlegt einen 16-Bit Datentyp in zwei Bytes, und was das
> für ein Datentyp ist, und wie der den zerlegt, musst du in dessen Spec
> nachschauen.

Ja, da habe ich dich wohl nicht richtig verstanden.
Der Absender hat es als signed Word definiert!

von Oliver S. (oliverso)


Lesenswert?

Oliver S. schrieb:
> Wenn das, was über den Bus angeliefert wird, schon ein signed short ist
> (wovon ich ausgehen), dann muß nichts mehr umgerechnet werden. Die
> beiden (unsigned) bytes in der richtigen Reihenfolge in einen usigned
> short schieben, das Ergebnis nach signed short casten, fertig.

Klaus S. schrieb:
> (int16_t)((MSB<<8)+LSB) sollte es auch tun (falls LSB und MSB jeweils
> uint8_t sind)

Oliver

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Genau für solche Fälle habe ich mein µSer-Bibliothek geschrieben, welche 
das Abbilden von beliebigen Binärformaten auf Sprach-Typen ermöglicht. 
Man definiert erst die Nachricht als "annotiertes struct" bestehend aus 
den einzelnen Datenfeldern und kann diese dann in einzelne Bytes 
umwandeln, und umgekehrt. Ein Beispiel:
1
#include <cstdint>
2
#include <iostream>
3
#include <uSer.hh>
4
5
// Nachricht definieren
6
struct CanMessage1 {
7
  USER_STRUCT (CanMessage1, uSer::AttrNone)
8
9
  // Felder der Nachricht
10
  std::int16_t a, b;
11
  std::uint8_t c;
12
  std::uint16_t d;
13
  std::uint8_t e;
14
  
15
  // Felder bekannt machen
16
  USER_ENUM_MEM (a, b, c, d, e)
17
};
18
19
int main () {
20
  
21
  // Reserviere Bytes für Nachricht
22
  std::uint8_t raw [8];
23
  
24
  // Simuliere Absenden einer Nachricht
25
  {
26
    // Nachricht anlegen
27
    CanMessage1 msg { -42, 37, 1, 7777, 3 };
28
    
29
    // Nachricht in einzelne Bytes zerlegen
30
    uSer::serialize (raw, msg);
31
  }
32
  
33
  // Bytes ausgeben
34
  for (std::uint8_t r : raw)
35
    std::cout << std::hex << std::setw(2) << "0x" << int { r } << ", ";
36
  std::cout << std::endl;
37
  
38
  // Simuliere Empfang einer Nachricht
39
  {
40
    // Nachricht anlegen
41
    CanMessage1 msg;
42
    
43
    // Einzelne Bytes in Nachricht umwandeln
44
    uSer::deserialize (raw, msg);
45
    
46
    // Nachricht anzeigen
47
    std::cout << std::dec << "CanMessage1 { " << msg.a << ", " << msg.b << ", " << int { msg.c } << ", " << msg.d << ", " << int { msg.e } << " }" << std::endl;
48
  }
49
}

Beispiel-Ausgabe:
1
0xd6, 0xff, 0x25, 0x0, 0x1, 0x61, 0x1e, 0x3, 
2
CanMessage1 { -42, 37, 1, 7777, 3 }

Es ist zu sehen wie der negative Integer in die Bytes 0xD6 0xFF zerlegt 
und dann wieder zurück zu -42 zusammen gebaut wird.

Die Bibliothek kann auch exotischere Vorzeichen-Formate (2er-Komplement, 
1er-Komplement und Sign-And-Magnitude) und Byte-Reihenfolgen (Big 
Endian, Little Endian, PDP und beliebige eigene). Die Bibliothek macht 
keine Annahmen über die Eigenschaften der Host-Plattform und setzt nur 
das voraus was im Sprachstandard garantiert ist; daher hat der Code auf 
allen Plattformen exakt das gleiche Verhalten und ist somit auch auf 
Architekturen mit exotischen Integer-Typen portabel, solange der 
Compiler Standard-Konform ist. Die Verwendung auf Mikrocontrollern ist 
ohne Overhead möglich.

Die Bibliothek:
https://github.com/Erlkoenig90/uSer
Mehr zum Thema:
Serialisierung

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.