Forum: Mikrocontroller und Digitale Elektronik Anfängerprobleme beim bitschieben


von Olaf B. (criopt)


Lesenswert?

Hallo zusammen!
Ich bin erst kürzlich von Bascom auf Atmel Studio umgestiegen und mein 
hirninterner Bitschieber ist schwer eingerostet...

Ich lese Daten von einem MPU 6050 über i2c. Der MPU stellt je Ache und 
Funktion die Rohdaten in einem hi und einem lo Register je 7 bit zur 
Verfügung. Mein Problem ist es die jeweils 7 bit Rohdaten der Register 
an die richtige Stelle der 8bit Variable zu schieben und beide 8 bits 
dann zu einem 16bit zusammenzufassen.Data_L und Data_H sind bei mir als 
int8_t deklariert.So sieht das momentan bei mir aus:

i2c_start_wait(MPU6050_ADDRESS);
i2c_write(MPU6050_RA_ACCEL_XOUT_L);
i2c_stop();
i2c_rep_start(MPU6050_ADDRESS | 1);
Data_L = i2c_readAck() << 8;
Data_L = Data_L | i2c_readNak();
i2c_stop();

i2c_start_wait(MPU6050_ADDRESS);
i2c_write(MPU6050_RA_ACCEL_XOUT_H);
i2c_stop();
i2c_rep_start(MPU6050_ADDRESS | 1);
Data_H = i2c_readAck() << 8;
Data_H = Data_H | i2c_readNak();
i2c_stop();
int16_t accel_x = (Data_H << 8) + Data_L;

Das letzte Mal das ich bits hin und hergeschoben hab war mein Rechner 
noch ein 80286 mit Bernsteinmonitor....

Vielen Dank für Eure Hilfe!

von Bernd (Gast)


Lesenswert?

Olaf Breuer schrieb:
> Data_L = i2c_readAck() << 8;
Ob das geschiebe richtig und notwendig ist,erschließt sich mir aus dem 
gezeigten Code nicht, aber das hier:
> int16_t accel_x = (Data_H << 8) + Data_L;
sieht so verkehrt nicht aus. Du solltest aber noch nach 16bit casten.
>int16_t accel_x = ((int16_t)Data_H << 8) + Data_L;

von Little B. (lil-b)


Lesenswert?

beim bitschieben sind int8_t ungeschickt
verwende besser uint8_t und co.
dann macht der compiler weniger blödsinn, wenn du in den überlauf 
reinshiftest

von Olaf B. (criopt)


Lesenswert?

Vielen Dank für die Antworten! Das casten habe ich eingefügt. Die Werte 
aus dem zusammengefügten Registern sollte eine Zahl zwischen -32786 und 
+32786 zeigen. Wenn ich mir die Data_L und Data_H ausgeben lasse, dann 
sehe ich dort bei beiden Registern teilweise Vorzeichen.
Momentan scheint das noch nicht richtig zu laufen. Ich bekomme 
aufeinanderfolgend zum Beispiel folgendes: Data_L: 81Data_H: 84accel_x: 
21585...Data_L: -90Data_H: -100accel_x: -25690
Der 6050 rauscht zwar ordentlich, aber das ist grad a bisserl viel...
Wenn ich mit unsigned arbeite, wie gelange ich dann am Ende wieder zu 
meinem Vorzeichen?

von Little B. (lil-b)


Lesenswert?

Olaf Breuer schrieb:
> int16_t accel_x = (Data_H << 8) + Data_L;

hier wird sicher das ergebnis falsch sein.
Mein vorschlag:
Caste Data_H auf int16_t und Data_L auf uint8_t

von Olaf B. (criopt)


Lesenswert?

also so?:  int16_t accel_x = ((int16_t)Data_H << 8) + (int8_t)Data_L;

meine Ergebnisse:

Data_L: 1Data_H: 104accel_x: 26625
Data_L: 1Data_H: 44accel_x: 11265
Data_L: 1Data_H: -120accel_x: -30719
Data_L: 1Data_H: 0accel_x: 1
Data_L: 1Data_H: -84accel_x: -21503
Data_L: 1Data_H: -108accel_x: -27647
Data_L: 1Data_H: -48accel_x: -12287
Data_L: 1Data_H: -80accel_x: -20479

Der Sensor ist fest auf meinem Tisch fixiert bei den Messungen...

von Olaf B. (criopt)


Lesenswert?

Hmmm die Ergebnisse des bitschiebens und zusammenführung sahen 
eigentlich ganz ok aus. Aber die Werte der hi und lowbits änderten sich, 
als wären hi und lo vertauscht. Tatsächlich sind die Adressen des 
MPU6050 genau anders herum als beim mpu9150 (der 9150 sollte einen 6050 
enthalten) Jetzt funkts einwandfrei. Ich bekomme stabile Werte die im 
gewünschten Bereich liegen. DANKE FÜR EURE HILFE!

Gruss aus Portugal
Olaf.

von Bernd K. (prof7bit)


Lesenswert?

Little Basdart schrieb:
> Olaf Breuer schrieb:
>> int16_t accel_x = (Data_H << 8) + Data_L;
>
> hier wird sicher das ergebnis falsch sein.
> Mein vorschlag:
> Caste Data_H auf int16_t und Data_L auf uint8_t

Wird das nicht automatisch vorher nach int promotet?

von Olaf B. (criopt)


Lesenswert?

Könnt Ihr mir bitte kurz erklären was casten und was promoten bedeutet? 
Es soll ja nicht nur funktionieren, ich muss es auch begreifen...
Danke
Olaf.

von Bernd K. (prof7bit)


Lesenswert?

Olaf Breuer schrieb:
> Könnt Ihr mir bitte kurz erklären was casten und was promoten bedeutet?
> Es soll ja nicht nur funktionieren, ich muss es auch begreifen...
> Danke

In dem Post von "Little Basdart" wurde vermutet daß beim Schieben eines 
8-Bit-Wertes um 8 Bit nach links alle Bits links herausgeschoben würden 
und somit nur noch 0 stehenbleibt. Das wäre in der Tat der Fall wenn man 
annehmen würde daß die Schiebeoperation direkt auf die 8-Bit-Variable 
Data_H angewendet würde.

Dem ist aber nicht so.

"Little Basdart" schlug aufgrund dieser Befürchtung vor sie zuvor 
manuell nach uint16 zu casten um auf Nummer Sicher zu gehen und auf 
jeden Fall das Schieben mit einer 16-Bit breiten Variable durchzuführen 
die breit genug wäre damit links nichts herausrutschen kann.

Aber das macht der Compiler bereits automatisch weil vor solchen 
Operationen alles was kleiner als int ist ertmal auf int (oder unsigned 
int, je nachdem) verbreitert (promoted) wird wird und dann erst die 
Operation durchgeführt wird.

Nur wenn der Compiler beweisen kann dass eh nichts rausgerutscht wäre 
oder das Ergebnis in jedem möglichen Falle identisch wäre dann kann der 
Compiler das auch bleiben lassen (optimieren), also wenn Du zum Beispiel 
ein uint8_t um ein paar bit nach links schiebst und gleich wieder in ein 
uint8_t speicherst dann muss er sich nicht die Mühe machen das vorher 
auf 16 bit zu verbreitern (ungünstig und teuer auf ner 8-bit CPU) nur um 
es hinterher sofort wieder abzuschneiden, sowas würde dann im Zuge der 
Optimierung komplett auf 8 bit belassen.

Im oben besprochenen Falle würde ich vom Compiler erwarten daß er vor 
dem left-shift auf jeden Fall ein unsigned int draus macht, also muss 
man es nicht explizit selbst machen.

von Olaf B. (criopt)


Lesenswert?

Wow, vielen Dank für die Mühe, die Du Dir gemacht hast.Jetzt bin wieder 
ein Stückchen weitergekommen. Wo wären wir ohne Foren und LEuten die 
sich die Mühe machen zu helfen und Wissen weiterzugeben??

Gruss
Olaf.

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.