PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bitmanipulation: Problem



teamohnename
02.01.2013, 10:06
Hallo an alle,
wir haben ein paar Schwierigkeiten mit der Bitmanipulation auf einem RNmega2560. Folgendes Problem:
Eine Funktion fragt den Entfernungswert eines SRF10 ab. Zurückgegeben werden soll aber sowohl die Entfernung als auch eine Zahl zwischen 0 - 5 (falls mit der Kommunikation etwas nicht geklappt hat). Wir haben in der Funktion also nun drei 8 Bit Variablen (lsb, msb und die Kontrollzahl). Die Rückgabe der Funktion muss nun 24 Bit groß sein, da das aber nicht geht, nehmen wir 32bit. Die Zahlen werden nun so zusammengesetzt (wir nennen die Variablen jetzt mal returnvar, lsb_srf und msb_srf)

result = ((returnvar << 16) + (lsb_srf << 8 ) + msb_srf);

Ist das soweit richtig?

Wir könnten jetzt mit dem Zerlegen anfangen, aber anscheinend funktioniert nicht mal das Zusammensetzen. Wenn man folgende Werte für die drei Variablen einsetzt:

returnvar = 0b00000101;
lsb_srf = 0b00000111;
msb_srf = 0b11010110;

ist das Ergebnis, das von der Funktion zurückgegeben wird, Dezimal 2006, was Binär wiederum [0000000000000000[00000]]11111010110 ist. returnvar wurde dem also gar nicht hinzugefügt.
Jetzt nochmal zum Zusammensetzen:

So sollte man eigentlich returnvar wieder rausbekommen:

returnvar = ((result & 0xff0000) >> 16);

und so das 16 Bit Ergebnis des SRF10:

srf10 = (result & 0xffff);

Da hat sich nun bewiesen, dass nur das msb und lsb zusammengesetzt wurden, denn returnvar ist immer 0, egal, was man dafür einsetzt und die Entfernungsmessung funktioniert.
Woran liegt das?
Danke schon mal und
Grüße
Jan
teamohnename


EDIT: Anscheinend ist das Ergebnis 2006, da das Display nur 16 Bit Variablen ausgeben kann. returnvar wurde also bei der Displayausgabe einfach abgeschnitten. Außerdem musste returnvar als 32bit Variable deklariert werden. Uns ist gerade aufgefallen, dass vorher die Warnung

warning: left shift count >= width of type
Ausgegeben wurde. Aber warum braucht die Variable, die um 16 bit verschoben wird so viel Platz, während die 8bit Variable, die um 8 bit verschoben wird, nicht 16 bit groß sein muss?

schorsch_76
02.01.2013, 11:17
Das ist prinzipiell richtig gedacht, du must nur eines bedenken. "returnvar << 16" wird auf dem Datentyp von returnval ausgeführt. Ist returnvar ein uint16_t kommt danach einfach "0" raus. returnvar sollte 32 Bit breit sein, damit das klappt. Am besten alle 4 beteiligten Variablen vorher nach 32 Bit konvertieren.

Am besten auch die Ergebnisse verodern und nicht + .

Gruß
Georg

teamohnename
02.01.2013, 15:31
Das habe ich mir schon gedacht, warum funktioniert das Ganze aber dann mit der 8bit Variable lsb_srf? Die wird dann ja eigentlich auch aus dem Datenbereich ,,geschoben" und müsste somit mindestens 16bit groß sein.
Danke für Deine Hilfe!

schorsch_76
02.01.2013, 15:38
Aus dem obigen "Listing" kommt leider der Datentyp nicht raus. Prinzipiell kann das durchaus sein, das deine Variable auch ein 2 byte Integer ist und kein Byte. Wie sind deine Variable definiert?

result = ((returnvar << 16) + (lsb_srf << 8 ) + msb_srf);


würde ich so schreiben:



uint32_t result = returnvar; // convertion to 32 bit
result = result << 16; // shift by 16 bit and build result
result |= uint32_t(lsb_srf) << 8; // conversion to 32 bit and shift by 8 bit and build result
result |= uint32_t(msb_srf); // conversion to 32 bit and build result


Gruß
Georg

EDIT: Code

teamohnename
02.01.2013, 15:58
Vorher waren alle als uint8_t deklariert. Es funktioniert mit lsb als uint8_t, msb als uint8_t und returnvar als uint32_t. Jetzt ist es deklariert mit lsb als uint8_t, msb als uint16_t und returnvar als uint32_t, damit funktioniert auch alles problemlos.
Dieser Ausschnitt sieht so aus:



uint32_t getValue(uint8_t adr)
{
uint8_t lsb_srf = 0;
uint16_t msb_srf = 0;

uint32_t returnvar = 0;

[herausfinden von msb/lsb (I²C) und returnvar]

return ((returnvar << 16) | (lsb_srf << 8) | msb_srf);
}

und so wird es wieder ,,zerlegt":



gM_srf = getValue(ADDRESS);

gM_check = ((gM_srf & 0xff0000) >> 16);

if(gM_check == 0)
{
srf10_l = (gM_srf & 0xffff);
[...]
}

sternst
02.01.2013, 16:58
"lsb_srf << 8" funktioniert mit lsb_srf als uint8_t weil die Operation '<<' (wie auch alle anderen Operationen) in C mindestens in int (also hier 16-Bit) durchgeführt wird.

Nachtrag:

damit funktioniert auch alles problemlos.Obiges bedeutet aber auch, dass das Ergebnis von "lsb_srf << 8" dann signed ist. Probiere deinen Code mal mit einem Wert für lsb_srf bei dem das höchste Bit gesetzt ist, und bestaune dann das Ergebnis.

teamohnename
02.01.2013, 22:17
Danke, nun hab’ ich es verstanden! :)

SprinterSB
08.01.2013, 01:26
"returnvar << 16" wird auf dem Datentyp von returnval ausgeführt. Ist returnvar ein uint16_t kommt danach einfach "0" raus.Nicht nur: Es kommt auch eine Compilerwarnung raus :-)

"Shift count exceeds with of type" o.ä. Warnungen beachten, und schon hat man 90% Fehler weniger :p