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.
1) ...& 0xFF, nur 8 Bit maskieren
2) << 8, um 8 Bits schieben
3) nicht && (das ist logisches Und), sondern entweder + oder auch |
(Oder bitweise)
4) beide Teile noch auf 16 Bit casten
Du solltest mit 0xFF verunden - du hast ja nur 8 Bit.
Data_rx[0] gehört um 8 bit nach links verschoben
Die beiden bytes gehören dann verodert und nicht verundet. Und wie
vorher erwähnt mit dem bit wise operator und nicht mit dem logischen.
Dirk B. schrieb:> BS schrieb:>> Wenn Data_Rx 8 Bit ist, kann das & 0xFF entfallen.>> Aber nur, wenn es unsigned ist.
Ist es doch (beides):
Miki schrieb:> uint8_t Data_Rx[2];
Für Bitgefummel sollte man übrigens sowieso immer unsigned-Typen
verwenden.
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
^
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.
GEKU schrieb:> Es könnte daher statt dem + Operator auch der | Oder Operator verwendet> werden.genauer
Es könnte daher statt dem | Oder Operator auch der + Operator für die
Addition verwendet werden.
Bei solchen Anfängerübungen ist es hilfreich sich einen C Compiler für
den PC zu besorgen und das mit bekannten Daten am PC stat im μC
auszuprobieren.
Da hat man dann auch einen Debugger...
Jim M. schrieb:> sich einen C Compiler fürden PC zu besorgen> Da hat man dann auch einen Debugger...
Als kostenloses Gesamtpaket zum Beispiel https://www.qt.io/
Die IDE taugt auch für viele Mikrocontroller.
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.
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.
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 ...
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
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.
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.
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 :-) ...)?
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
HildeK schrieb:> Die Bewertung war ja bei meinem Beitrag.
Wolfgangs Beitrag wurde auch abgewertet
> 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.
Den Grund hast du doch gleich selber mitgeliefert.
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
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
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.
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:
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 = 0x08GEKU 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.
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 ;)
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.
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.
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.
GEKU schrieb:> #include <stdio.h>>> int main()> {> ...> }
Beide Methoden sind weder portabel noch besonders elegant
(Ansichtssache)! Daher lieber so wie weiter oben von mir beschrieben.
Die Variante fehlt übrigens in deinem Codebeispiel.
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.
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?