2 Bytes zusammenfügen

Gast #5882916
Lesenswert?

hallo zusammen,

ich empfange per UART 2 Bytes und will die 12 Bit-Data in 16 Bit 
variable speichern.

z.B 3000=0xBB8.

uint8_t Data_Rx[2];
uint16_t Druck;

Druck= (((Data_Rx[0] & 0xFFF)<<4)&& (Data_Rx[1] & 0xFFF) ) ;


in der Variable kommt immer 1 raus statt 3000.
Angehängte Dateien:
Gast #5883200
Lesenswert?

Miki schrieb:
> uint8_t Data_Rx[2];
> uint16_t Druck;
>
> Druck= (((Data_Rx[0] & 0xFFF)<<4)&& (Data_Rx[1] & 0xFFF) ) ;

& 0xFFF macht keinen Sinn,  da Data_Rx vom Typ unsigned char ist und 
nicht größer als 0xFF sein kann.

bleibt
1
        Druck= ((Data_Rx[0] <<4)&& Data_Rx[1] ) ;
Ich nehme an, dass Data_Rx [0] die HIGH Wert und Data_Rx [1] den LOW 
Wert.

Warum wird der HIGH Wert nur um 4 Stellen nach links verschoben?
Druck ist vom Typ unsigned short und besteht daher aus zwei unsigned 
char
Ein unsigned char besteht aus 8 Bit, daher muss um 8 Stellen nach links 
verschoben werden

besser
^
1
       Druck = ((Data_Rx [0]<<8) && Data_Rx [1]); // <<8 entspricht *256

Beispiel:

       Data_Rx[0] = 0x47 und Data_Rx[1] = 0x10
1
       0x47 << 8 =  0x4700  HIGH Wert  16 Bit
2
       0x11 << 0 =  0x0001  LOW Wert   16 Bit 
3
                              ======
4
                              0x4711

Das heißt der HIGH Wert  16 Bit  muss zum LOW Wert 16 Bit  addiert (+) 
und nicht logisch verundet (&&) werden.

daher  richtig
1
     Druck = (Data_Rx [0] << 8) + Data_Rx [1];
Gast #5883206
Lesenswert?

GEKU schrieb:
> 0x47 << 8 =  0x4700  HIGH Wert  16 Bit
>        0x11 << 0 =  0x0001  LOW Wert   16 Bit
>                               ======
>                               0x4711

Anmerkung:

Die beiden Nullen hinter 0x47 kommen durch das Verschieben um 8 Stellen 
nach links bzw. durch die Multiplikation mit 256 zustande. Sie sind 
immer  Null.

Daher passiert beim Addieren kein Übertrag vom LOW Byte auf das HIGH 
Byte.
Das gilt auch umgekehrt für die vorderen zwei Nullen im LOW Wert.
Es könnte daher statt dem + Operator auch der | Oder Operator verwendet 
werden.
#5883668
Lesenswert?

HildeK schrieb:
> Wenn die Byteorder stimmt: union aus data[2] und wert.
> Benefit: Belegt nur einmal den Speicher ...

union ist eine sehr elegante Methode zur Typumwandlung, gerade
bei solchen Aufgaben, wo Daten byteweise übertragen werden.

Schade, dass der Beitrag negativ bewertet wurde. Verstehe ich nicht.

Man muss natürlich schon recht genau wissen, was man da tut.
Ich habe da mal eine Überraschung erlebt, als ich 32-Bit-Integer 
byteweise von einem PSoC5LP zu einem PSoC3 übertragen habe. Einer davon 
ist Big Endian, der andere Little Endian.

Miki: Der Screenshot stammt aus PSoC Creator, oder?
Ich kenne nicht viele, die Cypress-Controller nutzen. Wenn Du Lust hast, 
schreib mir mal eine PM.
#5883671
Lesenswert?

Günter N. schrieb:
> union ist eine sehr elegante Methode zur Typumwandlung, gerade
> bei solchen Aufgaben, wo Daten byteweise übertragen werden.
>
> Schade, dass der Beitrag negativ bewertet wurde. Verstehe ich nicht.


Deswegen:
> Man muss natürlich schon recht genau wissen, was man da tut.
> Ich habe da mal eine Überraschung erlebt, als ich 32-Bit-Integer
> byteweise von einem PSoC5LP zu einem PSoC3 übertragen habe. Einer davon
> ist Big Endian, der andere Little Endian.

Der Compiler kann (wenn er darf) das Geschiebe und maskieren erkennen 
und optimieren.
Das ist portabel.
Gast #5883673
Lesenswert?

Günter N. schrieb:
> Schade, dass der Beitrag negativ bewertet wurde. Verstehe ich nicht.
Nicht schlimm :-). Ich verstehe es auch nicht, eine negative Aussage kam 
von niemandem.
Ich hab so mal vor langer Zeit (DOS, 386er) Daten und Infos aus 
Meßgeräten ausgelesen und weiterverarbeitet.

> Man muss natürlich schon recht genau wissen, was man da tut.
Ja, deshalb mein Nebensatz: wenn die Byteorder stimmt ...
Persönliche Seite #5883694
Lesenswert?

Günter N. schrieb:
> Schade, dass der Beitrag negativ bewertet wurde. Verstehe ich nicht.

Vielleicht weil Type-Punning kein robuster Code ist?  Jedenfalls ist man 
mit GCC auf der sicheren Seite:
1
To fix the code above, you can use a union instead of a cast
2
(note that this is a GCC extension which might not work with other
3
compilers)

http://gcc.gnu.org/bugs/#casting_and_optimization
Gast #5883719
Lesenswert?

Günter N. schrieb:
> Schade, dass der Beitrag negativ bewertet wurde. Verstehe ich nicht.

Nimm's nicht so ernst. Melde dich einfach nicht an, dann hast du keine 
Probleme mit dem Bewertungssystem.

Das ist wie mit einem schwerhörigen Hund. Der lässt sich auch nicht so 
einfach durch Bellen einschüchtern.
#5883786
Lesenswert?

Günter N. schrieb:
> union ist eine sehr elegante Methode zur Typumwandlung, gerade
> bei solchen Aufgaben, wo Daten byteweise übertragen werden.
> Schade, dass der Beitrag negativ bewertet wurde. Verstehe ich nicht.

union ist weder besonders elegant, noch ist es dafür gedacht oder 
geeignet. Das wird vermutlich der Grund für die Bewertung sein.

Wolfgang schrieb:
> Günter N. schrieb:
>> Schade, dass der Beitrag negativ bewertet wurde. Verstehe ich nicht.
>
> Nimm's nicht so ernst. Melde dich einfach nicht an, dann hast du keine
> Probleme mit dem Bewertungssystem.

Bewertet wirst du trotzdem. Du siehst es nur nicht, und du kannst selbst 
nicht bewerten.

> Das ist wie mit einem schwerhörigen Hund. Der lässt sich auch nicht so
> einfach durch Bellen einschüchtern.

Es ist eher wie mit dem Kind, das beim Versteckspiel seine Augen zuhält, 
weil es glaubt, dass andere es dann auch nicht mehr sehen können.
Gast #5883814
Lesenswert?

Johann L. schrieb:
> Jedenfalls ist man
> mit GCC auf der sicheren Seite:
> To fix the code above, you can use a union instead of a cast
> (note that this is a GCC extension which might not work with other
> compilers)

Offenbar war ich es auch damals mit dem MS C6.x (1990+). Also nicht nur 
GCC extension.

Wolfgang schrieb:
> Nimm's nicht so ernst.

Die Bewertung war ja bei meinem Beitrag. Es macht mir nichts aus, außer 
dass ich mir Gedanken mache, was falsches behauptet zu haben. Dann wäre 
eine entsprechende Erklärung hilfreicher.

Rolf M. schrieb:
> union ist weder besonders elegant, noch ist es dafür gedacht oder
> geeignet. Das wird vermutlich der Grund für die Bewertung sein.

Warum nicht elegant bzw. nicht geeignet? Weil ggf. nicht portabel?
Wofür dann gedacht? Nur um Speicherplatz zu sparen?
Hast du da ein paar Schlagworte dazu (auswendig; ich will dich nicht zum 
Durchsuchen von Papieren animieren :-) ...)?
#5883821
Lesenswert?

HildeK schrieb:
> Rolf M. schrieb:
>> union ist weder besonders elegant, noch ist es dafür gedacht oder
>> geeignet. Das wird vermutlich der Grund für die Bewertung sein.
>
> Warum nicht elegant bzw. nicht geeignet?

Ich finde es umständlich, dafür extra erst einen neuen Typ zu definieren 
und die Daten da rein und wieder rauszukopieren.

> Weil ggf. nicht portabel?

Das auch. ISO C sagt auch explizit, dass man nur das Element der union 
lesen darf, das als letztes geschrieben wurde. Es ist immer nur ein 
Element "aktiv".

> Wofür dann gedacht? Nur um Speicherplatz zu sparen?

Wenn man als Alternative eine struct sieht, von der man immer nur ein 
Element benutzt, könnte man das so sehen.
Ein beispielhafter Anwendungsfall wäre ein Event-Handling, wo den 
verschiedenen Events unterschiedliche Daten mitgegeben werden. Dann 
gibt's für jeden Eventtyp ein union-Element, wo die zu diesem Event 
gehörenden Daten drin sind. Anhand des Event-Typs weiß man dann, welches 
union-Element das aktive ist, und man kann darauf entsprechend 
zugreifen.
Gast #5883824
Lesenswert?

Rolf M. schrieb:
> Das auch. ISO C sagt auch explizit, dass man nur das Element der union
> lesen darf, das als letztes geschrieben wurde. Es ist immer nur ein
> Element "aktiv".

Humbug!
1
If the member used to read the contents of a union object is not the same as the member last used to
2
store a value in the object, the appropriate part of the object representation of the value is reinterpreted
3
as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type
4
punning’’). This might be a trap representation.
Gast #5883850
Lesenswert?

Rolf M. schrieb:
> Ich finde es umständlich, dafür extra erst einen neuen Typ zu definieren
> und die Daten da rein und wieder rauszukopieren.

Danke für deine Erklärungen, auch für die der anderen Poster.
An rein- und rauskopieren hätte ich jetzt nicht als Erstes gedacht, ich 
würde die Elemente direkt als Variablen verwenden.
Persönliche Seite #5883852
Lesenswert?

HildeK schrieb:
> Johann L. schrieb:
>> Jedenfalls ist man
>> mit GCC auf der sicheren Seite:
>> To fix the code above, you can use a union instead of a cast
>> (note that this is a GCC extension which might not work with other
>> compilers)
>
> Offenbar war ich es auch damals mit dem MS C6.x (1990+). Also nicht nur
> GCC extension.

Wenn's ein dokumentiertes Feature ist, kein Problem.  Wenn's auf dem 
Niveau von "was rauskommt, ist, was ich erwarte" ...

Bernd K. schrieb:
> Rolf M. schrieb:
>> ISO C sagt auch explizit, dass man nur das Element der union
>> lesen darf, das als letztes geschrieben wurde. Es ist immer nur ein
>> Element "aktiv".
>
> ISO C sagt aber auch explizit daß Type-Punning mit unions erlaubt ist.

Ab C99.
#5883875
Lesenswert?

Johann L. schrieb:
>> ISO C sagt aber auch explizit daß Type-Punning mit unions erlaubt ist.
>
> Ab C99.

Nein, da war das noch nicht so. In C99 heißt es noch:
"When a value is stored in a member of an object of union type, the 
bytes of the object representation that do not correspond to that member 
but do correspond to other members take unspecified values, but the 
value of the union object shall not thereby become a trap 
representation."

Der oben von "Jemand" zitierte Satz taucht dort nicht auf.
Gast #5883876
Lesenswert?

Miki schrieb:
> Druck= (((Data_Rx[0] & 0xFF)<<8)+ (Data_Rx[1] & 0xFF) ) ;
>
> kommt nun 47880 raus

<<4 war richtig, denn Du schreibst, Du hast nur 12-bit Daten.
1
MSB               LSB
2
DATA[0]       DATA[1]
3
1011 1011   0000 1000   
4
            ^^^^-wird verworfen

Deswegen DATA[1] nur mit 0xF ver-AND-en.

Dies:
1
Druck = (((Data_Rx[0] & 0xFF)<<4) + (Data_Rx[1] & 0xF));
sollte richtig sein.

Gruß
HolgerT
#5883898
Lesenswert?

Johann L. schrieb:
>> ISO C sagt aber auch explizit daß Type-Punning mit unions erlaubt ist.
>
> Ab C99.

Weil man feststellte daß sowieso schon alle (zurecht?) die ganze Zeit 
über so taten als sei es erlaubt. Die Fußnote wurde wohl auch nur 
nachträglich in einem späteren Korrigendum als Klarstellung eingefügt, 
als Interpretationshilfe der betreffenden Paragraphen, zur 
Verdeutlichung der eigentlichen Intention hinter den grottenhäßlich 
verklausulierten Formulierungen im Text.

Man kann die Erlaubnis oder den Ausgang der vermeintlich fragwürdigen 
Tat auch indirekt aus dem jeweiligen ABI schließen denn dort ist das 
exakte Speicherlayout von Unions festgeschrieben. Man muss sein Programm 
in dem Fall ja sowieso unweigerlich auf dieses eine ABI oder kompatible 
ABIs festnageln.

Eleganterweise (und auch um unmißverständlich zu dokumentieren daß man 
sich sehr wohl ganz genau bewußt war was man tat) sichert man solche 
endgültigen Festlegungen auf bestimmte ABI Eigenschaften (Endianness, 
Alignment, Wortgrößen, etc.) mit statischen Asserts ab, so daß kein 
Zweifel daran bestehen kann wofür der Code mal gedacht war und wofür er 
definitiv nicht gedacht war.
#5883902
Lesenswert?

Rolf M. schrieb:
> Der oben von "Jemand" zitierte Satz taucht dort nicht auf.

Es gibt ein Korrigendum. Dort wurde die betreffende Fußnote nachträglich 
eingefügt die die eigentliche Intention des verklausulieren Textes 
noch mal explizit klarstellt. Denn es war auch ohne die Fußnote schon so 
gemeint, nur leider nicht menschenlesbar hingeschrieben.

http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm

Und da sieht man auch daß das selbe bereits für C89 galt.
Gast #5883912
Lesenswert?

Rolf M. schrieb:
> HolgerT schrieb:
>> <<4 war richtig, denn Du schreibst, Du hast nur 12-bit Daten.
>
> Wenn denn in dem einen Data_RX[0] die unteren 4 Bit liegen und in [1]
> die oberen 8. Wenn wie oben angegeben 3000 rauskommen sollen, dann ist
> das wohl tatsächlich so, auch wenn das eher ungewöhnlich ist.

Nach links verschoben muss das höherwertige Byte.
Das niederwertige Byte nutzt alle 8 Bits.
Wenn das höherwertige Byte nur um 4 Bit nach links verschoben wird, dann 
gibt es einen Konflikt mit den 4 höherwertigen Bits des niederwertigen 
Bytes.

Beispiel:  0x47 0x11

falsch :

        0x0011 niederwertige Byte
        0x0470 höherwertige Byte    0x47<<4
        =======
        0x0481

richtig :

        0x0011 niederwertige Byte
        0x4700 höherwertige Byte    0x47<<8
        =======
        0x4711
#5883935
Lesenswert?

GEKU schrieb:
> Das niederwertige Byte nutzt alle 8 Bits.

Woher weißt Du das? Das geht aus Mikis Daten nicht hervor! Bei Ihm ist 
zu lesen:
Data[0] = 187 = 0xBB
Data[1] = 8 = 0x08

Er möchte, daß 0xBB8 als 3000 dargestellt wird. Also wird das 
High-Nibble von Data[1] verworfen. Punkt.

GEKU schrieb:
> GEKU schrieb:
>> Du hast nur 12-bit Daten
>
> 12 Bit Daten bedeuten normalerweise die Nichtverwendung der obersten 4
> Bits
>
> siehe 12 Bit ADC Konverter

Hier interessiert nicht, wie die NORMALERWEISE Bedeutung ist. Miki hat 
in seinem Eingangspost seine Daten in einem Screenshot mitgeliefert. Und 
da sind die so dargestellt, dass meine Berechnung passt.


Ich verstehe die ganze Diskussion der "Experten" um C-Standards, Unions 
und den anderen Kram nicht. Dieser Faden ist voll gekapert. Und die nur 
12-bit Breite wurde völlig ignoriert. Hoffentlich liest Miki überhaupt 
noch mit.

Gruß
Holger
Gast #5883993
Lesenswert?

Normalerweise macht man das so:
1
uint8_t Data_Rx[2U];
2
uint16_t Druck;
3

4
Druck = ((uint16_t)Data_Rx[0U] + ((uint16_t)Data_Rx[1U] << 8U));

bzw. in C++:
1
uint8_t Data_Rx[2U];
2
uint16_t Druck;
3

4
Druck = (static_cast<uint16_t>(Data_Rx[0U]) + (static_cast<uint16_t>(Data_Rx[1U]) << 8U));


Das funktioniert garantiert immer und auf allen Architekturen mit allen 
Compilern und allen C/C++ Versionen.
Falls die Bytes vertausch sind, entsprechend 0U und 1U tauschen.
Gast #5884027
Lesenswert?

Miki schrieb:
> hallo zusammen,
>
> ich empfange per UART 2 Bytes und will die 12 Bit-Data in 16 Bit
> variable speichern.
>
> z.B 3000=0xBB8.
>
> uint8_t Data_Rx[2];
> uint16_t Druck;
>
> Druck= (((Data_Rx[0] & 0xFFF)<<4)&& (Data_Rx[1] & 0xFFF) ) ;
>
> in der Variable kommt immer 1 raus statt 3000.

Das müßte auch funktionieren:
1
Data_Rx[0] = 0xbb;
2
Data_Rx[1] = 8;
3
Druck = 0;
4

5
Druck = ( (uint16_t) (Data_Rx[0] << 4U) | ( (uint16_t) (Data_Rx[1]) );
6

7
Das ergibt:
8

9
Druck = 0x0bb8; oder 3000 in Dec.
Beim GCC sind die Casts notwendig.
Gast #5884045
Lesenswert?

Holger T. schrieb:
> GEKU schrieb:
>> Das niederwertige Byte nutzt alle 8 Bits.
>
> Woher weißt Du das? Das geht aus Mikis Daten nicht hervor! Bei Ihm ist
> zu lesen:
> Data[0] = 187 = 0xBB
> Data[1] = 8 = 0x08

GEKU schrieb:
> Nach links verschoben muss das höherwertige Byte.
> Das niederwertige Byte nutzt alle 8 Bits.
> Wenn das höherwertige Byte nur um 4 Bit nach links verschoben wird, dann
> gibt es einen Konflikt mit den 4 höherwertigen Bits des niederwertigen
> Bytes.

Mein Post beschreibt nicht welches Byte das höherwertige ist.
Es beschreibt welche Konsequenzen ein Verschieben um nur 4 Bits hat.
Gast #5884052
Lesenswert?

Arduino Fan schrieb:
> Data_Rx[0] = 0xbb;
> Data_Rx[1] = 8;
> Druck = 0;
>
> Druck = ( (uint16_t) (Data_Rx[0] << 4U) | ( (uint16_t) (Data_Rx[1]) );

Einmal kurz laut nachgedacht:

0x8 =>         0x0008    bleibt unverändert,  ist ok
0xbb =>       0x0bb0    Verschiebung um 4 Bit, man beachte ein Hexdigit 
ist 4bit groß!
ergibt =>      ======   Veroderung mit |
                     0x0bb8    und nicht 0xbb08


Warum sollt das niederwertige Byte nur 4 Bit groß sein?
Wenn das der Fall ist, dann mag die Berechnung von Arduino Fan richtig 
sein,
aber so eine Realisierung eines 12 Bit Wertes ist mir in meiner langen 
Beruflaufbahn noch nicht vorgekommen. War endlich ein mal Zeit ;)
#5884063
Lesenswert?

Das Rätsel um die höchst eigenwillige Kodierung könnte gelüftet werden 
wenn OP mal sagen würde woher er die Daten eigentlich bekommt 
(Typenbezeichnung oder Handbuch des sendenden Geräts oder 
Quelltextauszug desselben falls Eigenbau).

Vielleicht hat er auch nur nen Zahlendreher in seinen hingeschriebenen 
Beispieldaten fabriziert (wahrscheinlich) und die ganze 4-Bit-Aufregung 
ist somit hinfällig.
Gast #5884101
Lesenswert?

GEKU schrieb:
> Warum sollt das niederwertige Byte nur 4 Bit groß sein?

Damit man um Zweifel mit einem Lesebefehl die obersten 8 signifikanten 
Bits bekommt.

Nur hätte ich dann fürs liebste 0x80 und nicht 0x08 erwartet.


PS.: Ich nutze statt Unions dann lieber pointercasts, z.b

#define BACC(v,o) ((unsigned char*)&(v))[o]

Natürlich abgesichert mit static-asserts etc. Entweder ich mach solche 
Speicherspielchen, dann direkt, oder eben nicht.
Gast #5884269
Lesenswert?

Miki schrieb:
> ich empfange per UART 2 Bytes und will die 12 Bit-Data in 16 Bit
> variable speichern.

Wäre interessant welche Bytes in welcher Reihenfolge aus dem UART 
ausgelesen werden und welche Bedeutung die Information hat.

Miki schrieb:
> ich empfange per UART 2 Bytes und will die 12 Bit-Data in 16 Bit
> variable speichern.
>
> z.B 3000=0xBB8.

sagt nicht viel aus.
Gast #5884329
Lesenswert?

1
#include <stdio.h>
2

3
int main()
4
{
5
    // Beispiel mit UNION
6
    {
7
        union UINT_UNION // gross geschrieben der TYP von union
8
        {
9
            int a; // integer
10
            char b[sizeof(short int)]; // Array mit zwei Bytes
11
        }
12
        c; // klein geschrieben die Variable
13

14
        c.a = 0x4711;
15

16
        printf("a=%x  b0=%x b1=%x\r\n",c.a,c.b[0],c.b[1]);
17

18
        // liefert a=4711  b0=11  b1=47
19
    }
20

21

22

23
    // Beispiel Methode von A.S. :
24

25
    {
26
        unsigned int a;
27

28
        a=0x4711;
29

30
        printf("a=%x  b0=%x b1=%x\r\n",*(unsigned int*)&a, *(unsigned char*)&a, *((unsigned char*)&a+1));
31

32
        // liefert a=4711  b0=11  b1=47
33
    }
34
}
Angehängte Dateien:
#5884659
Lesenswert?

GEKU schrieb:
> Menüsucher schrieb:
>> Die Variante fehlt übrigens in deinem Codebeispiel.
>
> Das ist natürlich die sauberste Methode (siehe Anhang)
> Ich würde sie auch bevorzugen.

Da stimme ich zu. Sie hat nebenbei auch noch den Vorteil, von der 
Endianness des Zielsystems unabhängig zu sein.

PS: Warum eigentlich überall dieses U?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren