ADXL345 - Sensor defekt oder Programm fehlerhaft?

OP #4562932
Lesenswert?

Ich versuche seit Tagen einen ADXL345 Beschleunigungssensor auszulesen. 
Ich kommuniziere mit dem Modul über Software-SPI. Nachdem ich 
erfolgreich die DEVID ausgelesen hatte, kann ich soweit wohl behaupten, 
dass lesen und schreiben funktioniert.

Allerdings scheinen die Beschleunigungswerte der verschiedenen Axen 
nicht zu stimmen.
Z.B. Bekomme ich für den +-16-Modus mit Full-Res folgende Werte:
1
X: -370 Y:-400 Z:9564
 (in mG).

Ich rechne in mG da G Kommazahlen produzieren würde und die ja viel 
Rechenleistung brauchen ^^

Ich hätte erwartet, dass X und Y irgendwo so bei +-100 und Z bei 1000 
(mehr oder weniger) ist.

Da ich im 16g Modus mit Full-Res bin bedeutet das, dass ich den Messwert 
mit 4 malnehmen muss um den tatsächlichen Wert zu bekommen (4mG/LSB):
1
  //read X-Axis
2
  x0 = readRegister(0x80 | 0x32);
3
  x1 = readRegister(0x80 | 0x33);
4
  
5
  //read Y-Axis
6
  y0 = readRegister(0x80 | 0x34);
7
  y1 = readRegister(0x80 | 0x35);
8
  
9
  //read Z-Axis
10
  z0 = readRegister(0x80 | 0x36);
11
  z1 = readRegister(0x80 | 0x37);
12
  
13
  x = (int16_t)((x1 << 8) | x0);
14
  y = (int16_t)((y1 << 8) | y0);
15
  z = (int16_t)((z1 << 8) | z0);
16
  
17
  //+/- 16g mode & full-res: 4mg/LSB
18
  *x_val = x*4;
19
  *y_val = y*4;
20
  *z_val = z*4;

Das ist meine Initialisierung:
1
  write_command = ((0x00 | 0x31) << 8) | 0b01001011;//set SPI 3wire & 4g range & full-res
2
  writeCommand(write_command); 
3
  write_command = ((0x00 | 0x2D) << 8) | 0x08; //Enable measurements
4
  writeCommand(write_command);
5
  write_command = ((0x00 | 0x2C) << 8) | 0x0A; //100Hz data rate
6
  writeCommand(write_command);

Mache ich was falsch oder hab ich einen davon erwischt?

Beitrag "Defekte ADXL345 Beschleunigungssensoren aus der Bucht!"
OP #4563054
Lesenswert?

Danke für eure Antworten,

Wolfgang schrieb:
> Selbst wenn der Sensor sauber ausgerichtet ist, wären die Werte ok. Laut
> Datenblatt sollen der Offset von x und y im Bereich -150..+150mg liegen.

Der Sensor liegt waagerecht auf dem Tisch.
Möglicherweise hab ich das Datenblatt dann nicht verstanden aber wie 
kann ein Wert von 9000 mG (das wären 9G) okay sein? Da müsste doch nach 
meinem Verständnis nichts deutlich größeres als 1000 rauskommen?
OP #4563068
Lesenswert?

Wolfgang schrieb:
> Hier setzt du bestimmt nicht de 4g Range (Datenblatt Tab.21)

Ups, sorry. Hab vergessen den Kommentar zu ändern. Ich hab zum Testen 
diverse Modi durchprobiert. Trotzdem müsste meine Umrechnung des 
Messwertes in mG für den 16g-Modus in Ordnung sein, oder?

Ich verstehe immer noch nicht, wie ein Wert von 9000 für die Z-Axe in 
Ordnung sein kann.
Gast #4563093
Lesenswert?

Max M. schrieb:
> Ich verstehe immer noch nicht, wie ein Wert von 9000 für die Z-Axe in
> Ordnung sein kann.

Erstmal willst du doch wissen, ob dein Sensor richtig läuft. Dafür 
kannst du einen der zahllosen Beispielcodes auf deinen µC laden und die 
Ergebnisse mit den bekannten Werten vergleichen, z.B.
https://learn.adafruit.com/adxl345-digital-accelerometer/programming

Wenn du dich der richtigen Funktion deines Sensors versichert hast, 
kannst du dich um deine Software und das Datenblattverständniss 
kümmern.
Gast #4563110
Lesenswert?

Warum testest du dein Programm nicht mal mit vorberechneten Werten 
durch? Diese am besten mit einem zweiten UC via SPI deinem Programm 
zuführen. Danach wirst du schnell die Fehlerquelle lokalisren können. 
Das was hier passiert ist nur ein rumraten bzgl. Einer möglichen 
Ursache. Es selbst systematisch abzuklopfen sollte wesentlich schneller 
gehen.
Gast #4563138
Lesenswert?

visitor schrieb:
> Warum testest du dein Programm nicht mal mit vorberechneten Werten
> durch?

Schon den Sensor mal um 45°, 90° und 180° auf verschiedenen Achsen zu 
kippen, könnte einen Hinweis liefern, ob er grundsätzlich richtig 
arbeitet. Wenn man erstmal auf die Rohdaten guckt, könnte man die 
Sensorfunktion unabhängig von der Auswertesoftware beurteilen.
OP #4563184
Lesenswert?

Wolfgang schrieb:
> Schon den Sensor mal um 45°, 90° und 180° auf verschiedenen Achsen zu
> kippen, könnte einen Hinweis liefern, ob er grundsätzlich richtig
> arbeitet.

Werte vor dem Drehen:
X: 376 Y: -396 Z: 9640

Nach 180° Drehung:
X: -380 Y: -240 Z: 7600

Nach 90° Drehung:
X: 888 Y:-380 Z: 8650

90° in die andere Richtung:
X: -1600 Y:-340 Z: 8600

Hm...?
#4563208
Lesenswert?

Um welche Achse drehst du denn? Leg den Sensor doch mal so hin dass die 
Chipseite die vorher nach unten zeigte jetzt nach oben zeigt ... wenn 
sich dann das Vorzeichen vom z-Wert nicht umdreht ist der Sensor kaputt 
oder was ganz arg falsch ...

Was du hier machst sieht von den Werten erstmal so aus als ob du den 
Sensor auf dem Tisch liegend um die Achse drehst die nach oben zeigt, 
das bewirkt natürlich nur einen sekundären Effekt wenn der Tisch schräg 
steht ...
OP #4563211
Lesenswert?

Sven B. schrieb:
> Was du hier machst sieht von den Werten erstmal so aus als ob du den
> Sensor auf dem Tisch liegend um die Achse drehst die nach oben zeigt,
> das bewirkt natürlich nur einen sekundären Effekt wenn der Tisch schräg
> steht ...

Hab ich aber nicht sonder das was du sagst:

Sven B. schrieb:
> Leg den Sensor doch mal so hin dass die
> Chipseite die vorher nach unten zeigte jetzt nach oben zeigt

Sven B. schrieb:
> wenn
> sich dann das Vorzeichen vom z-Wert nicht umdreht ist der Sensor kaputt
> oder was ganz arg falsch ...

:(
Gast #4563262
Lesenswert?

Max M. schrieb:
> Werte vor dem Drehen:
> X: 376 Y: -396 Z: 9640
>
> Nach 180° Drehung:
> X: -380 Y: -240 Z: 7600

Wenn also "180° Drehung" bedeutet: Sensor-Chip liegt auf dem Kopf, dann 
misst dein Sensor als Z-Komponente einen Wert von 1020mg und die 
restlichen 8620 sind ein Offset. Das wäre doch erstmal nicht so abwegig.

Z_Offset = (Z_0° - Z_180°)/2

Mmh ... nicht schön, aber vielleicht kann man damit umgehen. Bestimme 
erstmal für alle Achsen den Offset, indem du die jeweilige Achse des 
Sensor einmal sauber nach unten und einmal nach oben richtest. Nach 
Offset-Korrektur müsste in 45° Stellung bezüglich der Vertikalen immer 
zwei Achsen den gleichen Wert produzieren.
OP #4563267
Lesenswert?

Wolfgang schrieb:
> dann
> misst dein Sensor als Z-Komponente einen Wert von 1020mg und die
> restlichen 8620 sind ein Offset.

Wie kommst du auf die 1020mg?

Das seltsame ist, wenn ich die Range auf +-2g stelle, ändert sich die 
Z-Komponente gar nicht mehr.

Edit:

Okay, ich hab mal einen kleinen Test für die Z-Werte gemacht:

2g-Range:
2044

4g-Range:
4092

8g-Range:
8188

16g-Range:
9632

Der Unterschied zwischen 2g und 4g beträgt 2048, der Unterschied 
zwischen 4g und 8g beträg 4096. Der Unterschied zwischen 8g und 16g 
beträg 1444.

Wenn ich dann diese Rechnung mache:
1
*z_val = (z*4) - (1444+4096+2048+1024)

Komme ich auf 1020mg, was ja halbwegs passen würde. Jetzt ändert sich 
auch das Vorzeichen wenn ich den Sensor umdrehe.

Ich ziehe also jedesmal 2^10, 2^11, 2^12 ab.

Die X- und Y-Achse zu kalibrieren ist aber irgendwie nicht ganz so 
offensichtlich.

Wenn ich um die Y-Achse drehe:

Position 1 (in Richtung der Y-Achse):
-1580

Position 2 (entgegen der Y-Achse):
884

Das gleiche mit der X-Achse:

Position 1 (in Richtung der X-Achse):
-1590

Position 2 (entgegen der X-Achse):
888
Gast #4563302
Lesenswert?

Max M. schrieb:
> Wie kommst du auf die 1020mg?

Wenn
1
Z=9640 für Z_Offset + Erdbeschleunigung
und
1
Z=7600 für Z_Offset - Erdbeschleunigung
ist der Rest weniger als kleines Einmaleins.

Das würde sich auch gut mit den Z=8600 bzw. Z=8650 für (mehr oder 
weniger genau) auf der Seite liegenden Chip (90° ?) decken.
OP #4563314
Lesenswert?

Wolfgang schrieb:
> Bei gesetztem FULL_RES Bit hast du immer einen
> Skalierungsfaktor von 4 mg/LSB

Sorry, das verstehe ich nicht. Warum kann sich der Wert nicht mehr 
ändern nur weil der Skalierungsfaktor gleich bleibt? Und warum ändern 
sich X- und Y Wert weiterhin?

Edit:

Irgendwie klappt es nicht ganz, die X und Y Werte zu korrigieren.

Wenn ich annehme das in Position 1 ~-1000mg herrschen, dann müsste ich 
~580 zum Wert dazuzählen. Wenn ich das aber mache, habe ich in Position 
2 ~1400mg. Wie löse ich das Dilemma?
#4563736
Lesenswert?

Könnte es sein, dass deine SPI-Routine das oberste Bit schluckt? Stimmt 
der SPI-Mode?
Schau dir mal die Rohwerte byteweise an. Bei 4mg/Bit ist die 
Vektor-Summe sqrt(x^2+y^2+z^2) der 3 Beschleunigungen beim ruhenden 
Sensor etwa 250. Wenn eine der Komponenten negativ ist (Sensor gedreht 
oder kleiner Wert mit negativem Offset) müsste der Wert im 
2er-Komplement erscheinen, also High-Byte 0xff und Low-Byte entsprechend 
mit führenden 1en.
Eigentlich dürften in den oberen Bytes nie andere Werte als 0x00 und 
0xff stehen, solange man den Sensor nicht heftig bewegt.
OP #4564719
Lesenswert?

Danke für deine Hilfe!

Das sind meine Datentypen:
1
void readXYZ(int16_t *x_val, int16_t *y_val, int16_t *z_val){
2
  uint8_t x0 = 0;
3
  uint8_t x1 = 0;
4
  uint8_t y0 = 0;
5
  uint8_t y1 = 0;
6
  uint8_t z0 = 0;
7
  uint8_t z1 = 0;
8
  
9
  int16_t x = 0;
10
  int16_t y = 0;
11
  int16_t z = 0;
12
}
#4569207
Lesenswert?

Wenn der Rest deines Programms in der readXYZ-Funktion steht, sollte es 
eigentlich passen. Gehen deinem Controller die Register für die 
temporären Variablen aus? Anderes Memory-Model einstellen, oder mal 
x_val, y_val und z_val als globale Varaibeln anlegen und testen.

Ebenso mal die Werte von x, y und z im Debugger überprüfen.

Brauchst du wirklich die Pointer zum Auslesen der Werte? Rufst Du die 
Funktion readXYZ(a,b,c) auch mal mit readXYZ(e,f,g) auf?
OP #4578576
Lesenswert?

Ich grüße dich,

Bernhard S. schrieb:
> Gehen deinem Controller die Register für die
> temporären Variablen aus? Anderes Memory-Model einstellen

Öhm, gute Frage. Ich hoffe mal nicht, mit 1kb RAM sollte der schon 
einige Variablen abkönnen.

Bernhard S. schrieb:
> oder mal
> x_val, y_val und z_val als globale Varaibeln anlegen und testen.

Hab ich gemacht, ändert leider nichts an den Werten.

Bernhard S. schrieb:
> Brauchst du wirklich die Pointer zum Auslesen der Werte?

Bei globalen Variablen nicht, ich fand / finde es nur schwierig, Arrays 
in C zurückzugeben.

Bernhard S. schrieb:
> Rufst Du die
> Funktion readXYZ(a,b,c) auch mal mit readXYZ(e,f,g) auf?

Was genau  meinst du mit e, f, g?

Die Z-Achse lässt sich anscheinend ganz gut konfigurieren. Aber die 
anderen Achsen nicht. In der vertikalen Lage der X-Achse ist der Wert 
einmal bei ~ 880 und einmal bei ~ -1560. Wenn ich beim ersten Wert 
120 addiere, komme ich beim zweiten Wert noch lange nicht bei -1000 
(das sollte der Wert bei vertikaler Ausrichtung in der Achse ja haben).
OP #4601120
Lesenswert?

So, ich hab nun eine Excel-Tabelle mit den raw-daten ohne und mit 
self-test enabled erstellt. Dabei kam heraus, dass die Self-test Offset 
Werte über bzw. unter den maximal bzw. minimal Werten des Datenblatts 
sind. Ich hab die Excel-Datei einmal angehängt. Was genau bedeutet das 
für den Sensor, kaputt? Laut Datenblatt:
1
If the self-test change is within the valid range, the test is considered successful. Generally, a part is considered to pass if the minimum magnitude of change is achieved. However, a part that changes by more than the maximum magnitude is not necessarily a failure.

Aber was genau das bedeutet steht da auch nicht? grr
Angehängte Dateien:
Gast #4601190
Lesenswert?

Max M. schrieb:
> Aber was genau das bedeutet steht da auch nicht? grr

Was verstehst du an "Generally, a part is considered to pass if the 
minimum magnitude of change is achieved. However, a part that changes by 
more than the maximum magnitude is not necessarily a failure." nicht?
OP #4601219
Lesenswert?

W.A. schrieb:
> Was verstehst du an "Generally, a part is considered to pass if the
> minimum magnitude of change is achieved. However, a part that changes by
> more than the maximum magnitude is not necessarily a failure." nicht?

Ich kann nicht darauf schließen, dass der Sensor wegen Überschreiten der 
Grenzen fehlerhaft ist, warum gibt es sie dann?

Werner M. schrieb:
> Stimmt, die Details stehen im Datenblatt auf S.22 im Abschnitt
> "SELF-TEST".

Danke!

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