STM32 und MPU6050: Falsche Werte

OP #4783899
Lesenswert?

Hallo, ich versuche gerade mit einem STM32 Werte aus einer MPU6050-IMU 
zu lesen. Ich habe dazu diese Funktion geschrieben:
1
void read_sensor(sensor_raw * data) {
2
  int8_t buf[14];
3
  read_buffer(MPU6050_RA_ACCEL_XOUT_H, &buf, 14);
4
  data->temp =   (((float) (buf[6] << 8 | buf[7]))    /340.0 + 36.53);
5
  data->x_acc =   (((float) (buf[0] << 8 | buf[1]))    /16384.0);
6
  data->y_acc =   (((float) (buf[2] << 8 | buf[3]))    /16384.0);
7
  data->z_acc =   (((float) (buf[4] << 8 | buf[5]))    /16384.0);
8
  data->x_gyro =   (((float) (buf[8] << 8 | buf[9]))    /131.0);
9
  data->y_gyro =   (((float) (buf[10] << 8 | buf[11]))    /131.0);
10
  data->z_gyro =   (((float) (buf[12] << 8 | buf[13]))    /131.0);
11
}
read_buffer() ist dabei nur ein Wrapper um eine HAL-Funktion, die per 
I2C von der IMU liest.

Ungefaehr bei jeder zweiten Messung, allerdings ohne (erkennbares) 
Muster, zeigt der Debugger (Eclipse CDT mit OpenOCD) eigenartige 
Ergebnisse im Speicher an.

Beispiel:
x_acc:-0.434814453
y_acc:-0.00268554688
z_acc:-0.00317382812

Da ich mich auf dem Planeten Erde befinde, und die IMU vor mir auf einem 
Tisch liegt, wuerde ich erwarten, dass sqrt(x^2 + y^2 + z^2) zumindest 
in der Groessenordnung von eins liegen muesste. Bei etwa jeder zweiten 
Messung taucht auf der z-Achse auch der richtige Wert, etwa 0.8, auf.
Als Schuldigen vermute ich meinen Code, der nach float castet, da die 
rohen Sensordaten gut aussehen.

Zum Beispiel fuer die z-Achse (selbes Sample):
H: 0x32 L: 0xcc
(Das ist eine Zweierkomplementzahl, bei der das erste Bit nicht gesetzt 
ist. Das dabei als Ergebnis ueberhaupt was Negatives rauskommt ist also 
schonmal komplett verkehrt).

Ist mein Code falsch? Oder spielt mir Eclipse da einen Streich?
OP #4783957
Lesenswert?

Ich verstehe, was du meinst. Aber wie gesagt: Ich schreibe das Ergebnis 
anders als in deinem Samplecode ja nicht in eine 8Bit-Speicherstelle, 
verliere die vorderen Bits also auch nicht. C speichert das 
Zwischenergebnis beim Kompilieren automatich in einer 16-bit-Variablen. 
Zum Vergleich:
1
#include <stdio.h>
2
#include <stdint.h>
3

4
int main(int argc, const char *argv[])
5
{
6
  uint8_t foo = 0x80;
7
  float test = (float) (foo << 8);
8
  printf("Ergebnis: %f \n", test);
9
  return 0;
10
}
liefert als Ergbnis: 32768.0

(Habe auch schon probiert, erstmal das Zwischenergebnis in einem 
int_16t-Array zu speichern und dann zu casten. Macht fuer den Fehler 
aber keinen Unterschied)
OP #4784025
Lesenswert?

Ah, habe die Loesung glaube ich gefunden:
Das hintere Byte wird bei der Umrechnung ebenfalls als 
vorzeichenbehaftet betrachtet, was scheinbar die Oder-Operation 
veraendert. Falsche Ergebnisse gibts immer genau dann, wenn das MSB im 
unteren Byte gesetzt ist. Werde das nachher mal fixen, und gucken, was 
passiert.
#4784046
Lesenswert?

Left shift von nicht-negativen Zahlen geht. Aber sobald du eine negative 
Zahl hast, ist das Ergebnis nicht definiert.

Du solltest dir nochmal genau ansehen, was da aus deinem read_buffer 
wirklich kommt. Der Code dazu sollte helfen.

http://stackoverflow.com/questions/7622/are-the-shift-operators-arithmetic-or-logical-in-c
> The caveat here is that for signed types the value should be non-negative
> and the resulting value should be representable in the result type.
> Otherwise the operation is undefined.
OP #4784090
Lesenswert?

Damit hat es nix zu tun. Mittlerweile ist mir klar, wo das Problem 
liegt.

Falls sich jemand fuer die Loesung interessiert:
Beide Zahlen werden vorzeichenbehaftet interpretiert, das heisst sie 
werden auch mit Blick aufs MSB expandiert.
1
1010 1010 << 8 | 1010 1010

wird intern also zu:
1
   1010 1010 0000 0000
2
OR 1111 1111 1010 1010
3
=  1111 1111 1010 1010
Deshalb kam auch immer eine sehr kleine, negative Zahl raus.

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