Forum: Mikrocontroller und Digitale Elektronik Buffer verschieben Problematik


von Uwe (Gast)


Lesenswert?

Hallo,

habe da ein Schiebeoperator Problem und komme nicht auf die Lösung.

Ich möchte das in der uiTemp00 Variable Bufferstelle [3] u. [4] und 
[high nibble von 5] und in der

uiTemp11 [lo nibble von 5] und [6] u. [7] steht.

Also zusammengefasst so: uiTemp00 = 0x01117
                         uiTemp11 = 0x186A0
1
uint8_t RxBuffer[8] = {0x57,     0x03, 0x92,    0x01, 0x11,   0x71,    0x86, 0xA0};  
2
                      //[0]      [1]   [2]      [3]   [4]     [5]      [6]   [7]
3
4
uiTemp00 =  (uint32_t)(RxBuffer[7] & 0x000FF);
5
uiTemp00 |= (uint32_t) ((RxBuffer[6] << 8) & 0x0FF00);
6
uiTemp00 |= (uint32_t) ((RxBuffer[5] << 16) & 0xFFFFF);
7
      
8
uiTemp11 =  (uint32_t) ((RxBuffer[5] >> 4) & 0x0000F);
9
uiTemp11 |= (uint32_t) ((RxBuffer[4] << 8) & 0x00FF);
10
uiTemp11 |= (uint32_t) ((RxBuffer[3] << 8) & 0x00FF);

Komme mit den Schiebeoperatoren nicht klar bitte um hilfe.

von holger (Gast)


Lesenswert?

>Komme mit den Schiebeoperatoren nicht klar bitte um hilfe.

Nicht nur damit nicht.

uiTemp11 |= (uint32_t) ((RxBuffer[4] << 8) & 0x00FF);

Um 8Bit nach links schieben und dann schön mit dem UND 0x00FF
gleich plattmachen auf 0.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Also zusammengefasst so: uiTemp00 = 0x01117

Damit setzt sich uiTemp00 zusammen aus
1
0x00007 (Buffer[5] >> 4)
2
0x00110 (Buffer[4] << 4)
3
0x01000 (Buffer[3] << 12)

von Uwe (Gast)


Lesenswert?

holger schrieb:
>>Komme mit den Schiebeoperatoren nicht klar bitte um hilfe.
>
> Nicht nur damit nicht.
>
> uiTemp11 |= (uint32_t) ((RxBuffer[4] << 8) & 0x00FF);
>
> Um 8Bit nach links schieben und dann schön mit dem UND 0x00FF
> gleich plattmachen auf 0.

habe es jetzt so abgeändert.
aber passt immer noch nicht die nibbles sind nicht an der richtigen 
stelle bzw.  nicht da.

Was mache ich noch falsch?

uiTemp00 = 0x086A0
uiTemp11 = 0x01107
1
  uiTemp00 =  (uint32_t)(RxBuffer[7] & 0xFF);
2
  uiTemp00 |= (uint32_t) ((RxBuffer[6] << 8) & 0xFF00);
3
  uiTemp00 |= (uint64_t) ((RxBuffer[5] << 10) & 0x0000F);
4
      
5
  uiTemp11 =  (uint32_t) ((RxBuffer[5] >> 4) & 0x000F);
6
  uiTemp11 |= (uint32_t) ((RxBuffer[4] << 8) & 0xFFFF);
7
  uiTemp11 |= (uint32_t) ((RxBuffer[3] << 8) & 0x00FF)

von guest (Gast)


Lesenswert?

Rechne doch einfach mal per Hand nach!

Uwe schrieb:
> uiTemp00 |= (uint64_t) ((RxBuffer[5] << 10) & 0x0000F);

RxBuffer[5] ist 0x71
Das ganze dann um 10 Bit nach links, was kommt raus?
Und dann das Ergebnis mit 0x0000F verundet, was kommt dann raus?

Und mit dem Rest kanns Du das dann auch allein.
Btw. das 'uint64_t' da oben ist Schwachfug, 32 Bit sind völlig 
ausreichend.

von A. S. (Gast)


Lesenswert?

Uwe schrieb:
> uiTemp00 =  (uint32_t)(RxBuffer[7] & 0xFF);
>   uiTemp00 |= (uint32_t) ((RxBuffer[6] << 8) & 0xFF00);
>   uiTemp00 |= (uint64_t) ((RxBuffer[5] << 10) & 0x0000F);
wieso << 10?? Hast Du nicht von Nibbles gesprochen?
und wieso dann &0xf? fehlen da nicht 4 Nullen hinter

>
>   uiTemp11 =  (uint32_t) ((RxBuffer[5] >> 4) & 0x000F);
>   uiTemp11 |= (uint32_t) ((RxBuffer[4] << 8) & 0xFFFF);
>   uiTemp11 |= (uint32_t) ((RxBuffer[3] << 8) & 0x00FF)
Auch hier scheinen mir die Anzahl an Schiebungen und die zugehörige 
Maske gewürfelt. ICh würde erwarten, dass nur maximal 2 Fs auftauchen 
und dass sie irgendwie dem geschobenen Wert entsprechen.

von Theor (Gast)


Lesenswert?

Tatsächlich sind die Maskierungen völlig unnötig. Denn mit den 
Schiebeoperationen fügst Du lediglich Nullen (links oder rechts) hinzu.
Lies das am besten nochmal in einem C-Buch nach (oder im Standard).

Wichtig ist hier das Kapitel "Integral-promotion" oder 
"Integer-Erweiterung". Es hängt auch von Deiner Maschine ab, was genau 
Du machen musst. Aber grundsätzlich wird der linke Operand ein (unsigned 
int) werden, was nicht grundsätzlich die selbe Länge wie ein uint32_t 
hat.
Auch das solltest Du nochmal nachlesen.

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Wieso eigentlich überall das &0xF ??
Wir brauchen doch nur die Bytes verschieben und mit der Ziel-Variabel 
ver-ODER-n.

uint8 wird wohl nur 8 bit breit sein, oder?
Wenn ich da was schiebe, bleiben es doch nur 8 bit - also ruck zuck Null

In Assembler würde ich die Bytes nacheinander bitweise in die 
Ziel-Variabel reinschieben.

uiTemp00 <-- 8xBuffer[3], 8xBuffer[4], 4xBuffer[5]
uitemp11 <-- 4xBuffer[5], 8xBuffer[6], 8xBuffer[7]

Und fertig.
Buffer[x] muß nur 8 bit breit sein, uitempxx sollte je 20 bit aufweisen.

(LSL und ROL wären meine Befehle)

MfG

von Uwe (Gast)


Lesenswert?

hab es jetzt so aber eine Stelle passt immer noch nicht.. hilfe.hilfe

Sollte ich es noch dazu besser casten ??

das steht jetzt drinne

uiTemp00 = 0x1117
uiTemp11 = 0x186A (soll aber 0x186A0)
1
   uiTemp00 =  (RxBuffer[5] >> 4);
2
   uiTemp00 |= (RxBuffer[4] << 4);
3
   uiTemp00 |= (RxBuffer[3] << 12);
4
    
5
   uiTemp11 =  (RxBuffer[5] << 12);
6
   uiTemp11 |= (RxBuffer[6] << 4);
7
   uiTemp11 |= (RxBuffer[7] >> 4);

von Theor (Gast)


Lesenswert?

Uwe schrieb:
> hab es jetzt so aber eine Stelle passt immer noch nicht.. hilfe.hilfe

Es scheint mir, dass Du sehr verwirrt und vor allem sehr aufgeregt bist.
Das wichtigste ist, dass Du ruhig wirst. Damit ist das Hauptproblem 
schon mal gelöst. Wenn nötig, lege das Problem beiseite und gehe 
schlafen. Es ist ohnehin schon spät.

Dann, im zweiten Schritt, liest Du die Stellen im C-Buch, die ich Dir 
genannt habe, gründlich durch und denkst darüber nach.

> Sollte ich es noch dazu besser casten ??
Das ist soweit richtig. Aber wichtig ist auch, dass Du verstehst, warum 
Du das tun sollst. Das lernst Du durch die Lektüre. Und dann verstehst 
Du auch, in welchen Typ Du casten must.

Nur Mut. Das schaffst Du schon. Nur vor allem: Ruhe bewahren. 
Systematisch vorgehen.

von Uwe (Gast)


Lesenswert?

habe es jetzt so gemacht. Aber scheinbar sind die verundungen doch 
notwenig weil sonst noch müll drinne steht das die Variable uint32_t 
breit ist ...

Hat jemand noch eine Idee?
1
 ulTemp0 =  (uint16_t) (ucRxBuffer[5] >> 4);
2
 ulTemp0 |= (uint16_t) (ucRxBuffer[4] << 4);
3
 ulTemp0 |= (uint16_t) (ucRxBuffer[3] << 12);
4
          
5
 ulTemp1 =   (ucRxBuffer[5] << 12);
6
 ulTemp1 |=  (ucRxBuffer[6] << 4);
7
 ulTemp1 |=  (ucRxBuffer[7] >> 4);
8
 ulTemp1 <<= 4;

von Theor (Gast)


Lesenswert?

Uwe schrieb:
> habe es jetzt so gemacht. Aber scheinbar sind die verundungen doch
> notwenig weil sonst noch müll drinne steht das die Variable uint32_t
> breit ist ...
>
> Hat jemand noch eine Idee?

Schon. Aber ich bin jemand der in gewissen Fällen nicht einfach die 
Antwort gibt. In der Regel wollen wir hier helfen, Dir selbst zu helfen 
und das bedeutet, dass Du selbst etwas leisten musst.

An sich hast Du die Grundidee schon erfasst, aber Du wendest sie noch 
falsch an.

Es ist vor allem nötig, dass Du Dir einmal klarmachst, was genau 
geschieht. Wie die Ausdrücke, die Du verwendest, vom Compiler 
interpretiert werden.

Schaue Dir einmal folgendes an:
1
ulTemp0 =  (uint16_t) (ucRxBuffer[5] >> 4);

Zerlege das mal in die einzelnen Schritte:

Zunächst hast Du den Ausdruck:
1
 ucRxBuffer[5]

Was ist das?
Nun, Du hast ucRxBuffer als Vektor von uint8_t deklariert. D.h. jedes 
Element besteht aus einem uint8_t. Einer vorzeichenlosen Zahl aus 8 Bit, 
die daher Werte von 0 bis 255 (dezimal) bzw. 0 bis 0xFF (hexadezimal) 
annehmen kann.

An der Position, dem Index 5 steht, wegen Deiner Intialisierung
1
uint8_t RxBuffer[8] = {0x57,     0x03, 0x92,    0x01, 0x11,   0x71,    0x86, 0xA0};
der Wert 0x71 (hexadezimal).

Nun steht da, wenn man die Datentypen in der Form eines Casts 
ausdrücklich hinschreibt im ersten Schritt:
1
 ((uint8_t) 0x71)

Gut. Weiter. Betrachten wir den Ausdruck, in dem dieser Inhalt des 
Buffers Verwendung findet und setzen den Inhalt gleich ein:
1
 (((uint8_t) 0x71) >> 4)

Da schau ich gleich mal nach, weil ich das eben schon geübt habe. Was 
hat denn die "4" für einen Datentyp? Dafür gibt es ja keine Deklaration 
aus der ich das ablesen kann.

Das ergibt sich aus der Sprachbeschreibung von C. Das steht im 
C99-Standard, den Du hier: 
www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf nachlesen kannst, im 
Abschnitt 6.4.4.1 im Paragraph "Semantics". Alternativ kannst Du Dir 
auch mal den Kernighan/Ritchie, 2. Auflage, Abschnitt A.2.5.1 
durchlesen. Das gibt es auf Deutsch. Allerdings ist es veraltet und es 
gibt Abweichungen zu C99 (die bei dem Thema aber, soweit ich weiß, nicht 
wesentlich sind).

Danach hat eine aus dezimalen Ziffern zusammengesetzte den Typ der in 
der Reihenfolge int, long int und unsigned long int noch hineinpasst. In 
unserem Fall wäre das int, da die 4 gerade dort hineinpasst.

OK. Nochmal das selbe Spiel. Schreiben wir die Typen ausdrücklich als 
Cast hin:
1
 (((uint8_t) 0x71) >> (int) 4)

Nun kommt endlich das eigentliche Problem, dass Dir Schwierigkeiten 
bereitet.

Für jeden Operator in C ist festgelegt ob er einen bestimmten Typ als 
Operanden erwartet und falls ja, welcher das ist.

Für die Schiebeoperationen ist das der Typ int. Das steht im Standard 
unter Abschnitt 6.5.7. Im K&R unter A.7.8

Nun ist aber nur einer der Typen in dem Ausdruck int. Der andere ist 
uint8_t! Was nun?

Auch dazu steht im Standard und im Buch etwas: Nämlich, dass die 
Operanden der in einem anderen Beitrag von mir in diesem Thread schon 
erwähnten Integer-Erweiterung unterzogen werden. Das steht im Standard 
unter 6.3 Conversions, im K&R unter A.6.1 bzw. online in 
http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/007_c_typumwandlung_001.htm#mj5c5e497ac2ab4367fe9df0ffd218cfca 
unter Abschnit 7.1.

Kurz gesagt, wird die 0x71, die verschoben werden soll in ein int 
umgewandelt.

Nun ist aber int nicht gleich int. Das hängt von der Maschine und dem 
Compiler ab. Im allgemeinen gilt zwar, dass häufig ein int 16 Bit breit 
ist, aber das sollte man nicht voraussetzen. Wie das konkret ist, steht 
in der Dokumentation Deines Compilers. Aber Achtung. Wenn der Compiler, 
wie der GCC für mehrere Prozessoren existiert, musst Du zunächst den 
Abschnitt suchen, der für Deine CPU zutrifft.

So. Ich denke das sollte genug Anleitung sein, wie Du Dir das Thema 
selbst näherbringen kannst.


Die nächste Frage ist dann: Falls die 0x71 in ein 16 Bit int umgewandelt 
wird, wie sieht diese Zahl dann aus, wenn sie etwa um 12 Bit nach links 
verschoben wird?

Viel Erfolg.

von Uwe (Gast)


Lesenswert?

Hallo,

danke für die Anleitung. Habe soweit alles gelesen und es entsprechend 
abgeändert, aber die letzte Operation will einfach nicht funktionieren 
und ich weiß nicht weiter....

Könnte bitte Jemand mal drüber schauen?
ulTemp0 = 0x186A0
ulTemp1 = 0x0C350  hier müsste aber 0x0C35F stehen
1
uint8_t cRxBuffer[8] = {0x57,     0x03, 0x92,    0x0C, 0x35,   0xF1,  0x86, 0xA0};
2
          //[0]      [1]   [2]      [3]   [4]     [5]      [6]   [7] 
3
4
uint32_t ulTemp0; 
5
uint32_t ulTemp1;
6
7
ulTemp0 =  (uint32_t) cRxBuffer[7] & 0x00FF;
8
ulTemp0 |= ( (uint32_t) cRxBuffer[6] << 8 ) & 0xFF00;
9
ulTemp0 |= ((uint32_t)  cRxBuffer[5] << 16) & 0xF0000;
10
 
11
ulTemp1 =  ( (uint32_t)  cRxBuffer[3] << 12 ) & 0xFF000;
12
ulTemp1 |= ( (uint32_t) cRxBuffer[4] << 4 ) & 0x00FF0;
13
ulTemp1 |= ( (uint32_t) cRxBuffer[5] >> 8 ) & 0x0000F;

von Ralf G. (ralg)


Lesenswert?

Wenn du eine 8Bit breite Zahl um 8Bit nach rechts schiebst...

von Uwe (Gast)


Lesenswert?

Ralf G. schrieb:
> Wenn du eine 8Bit breite Zahl um 8Bit nach rechts schiebst...

Danke! So geht es jetzt:
1
        uint8_t cRxBuffer[8] = {0x57,     0x03, 0x92,    0x0C, 0x35,   0x01,  0x86, 0xA0};
2
                 //[0]      [1]   [2]      [3]   [4]     [5]      [6]   [7]    
3
  
4
5
        uint32_t ulTemp0; 
6
  uint32_t ulTemp1;
7
8
  ulTemp0 =  (uint32_t) cRxBuffer[7] & 0x00FF;
9
  ulTemp0 |= ( (uint32_t) cRxBuffer[6] << 8 ) & 0xFF00;
10
  ulTemp0 |= ( (uint32_t)  cRxBuffer[5] << 16) & 0xF0000; 
11
  
12
  ulTemp1 =  ( (uint32_t) cRxBuffer[3] << 12) & 0xFF000;
13
  ulTemp1 |= ( (uint32_t) cRxBuffer[4] << 4 ) & 0x00FF0;
14
  ulTemp1 |= ( (uint32_t) cRxBuffer[5] >> 4 ) & 0x0000F;

von Theor (Gast)


Lesenswert?

Uwe schrieb:
> Ralf G. schrieb:
>> Wenn du eine 8Bit breite Zahl um 8Bit nach rechts schiebst...
>
> Danke! So geht es jetzt:

Prima! Gut gemacht.

Vielleicht versuchst Du aber doch noch, die Maskierung einmal 
wegzulassen. Das wäre eine Gelegenheit etwas interessantes 
festzustellen.

Nimm den Ausdruck:
[c]
( (uint32_t) cRxBuffer[3] << 12) & 0xFF000;
[c]

An der Stelle 3 steht die Zahl 0x0C. Eingesetzt in den Ausdruck ergibt 
das:
[c]
( (uint32_t) 0x0C << 12) & 0xFF000;
[c]

Während das Programm ausgeführt wird, wird zunächst das Cast wirksam:
Aus 0x0C wird 0x0000000C. Das ist die 32 Bit-Zahl 0xC, nur mit vielen 
Nullen um die Anzahl der Bits deutlich zu machen.

Nun wird diese Zahl um 12 Bit nach links verschoben. Das ergibt 
0x0000C000.
Also wird der Ausdruck:
[c]
( 0x000C000 & 0xFF000;
[c]

Um deutlich zu machen, was bei dem nun abschliessenden maskieren 
geschieht, schreibe ich die beiden Wert untereinander.

0x0000C000
0x000FF000

Die Bitweise Und-Verknüpfung ergibt:

0x0000C000

Diese Und-Verknüpfung ändert also nichts an dem ursprünglichen Wert.

Der Punkt ist, dass die Schiebeoperation definitiv keine zusätzlichen 
Bits setzt; die Anzahl der gesetzten Bits bleibt gleich. Deswegen wird 
keine zusätzliche Maskierung benötigt.

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.