Forum: Mikrocontroller und Digitale Elektronik MPU-6050-Modul sendet nur 0


von M. T. (restfet)


Lesenswert?

Hallo!

Ich verwende hier ein MPU6050-Modul (Beschleunigungssensor/Gyrosensor).
Es hängt zusammen mit einem HMC5883L (elektronischer Kompass) am I2C-Bus 
eines ATmega324. Der sendet die I2C-Daten über UART weiter an ein 
Arduino-Board, was als UART-Brücke die Daten an den COM-Port meines PCs 
sendet.
So weit, so viele Fehlerquellen.
UART funktioniert aber in Software und Hardware, sowohl zwischen den 
beiden uCs als auch zwischen uC und PC. I2C ebenso, Pullups sind 
vorhanden.

Wenn ich vom MPU6050 Sensordaten anfordern will, egal ob Beschleunigung, 
Gyro oder Temperatur, sendet der aber immer nur 0 zurück. Wenn ich 
stattdessen das identification register auslese, antwortert er wie im 
Datenblatt beschrieben mit einem 'h' (0x68).
Der HMC5883L sendet brav seine Sensordaten.

Ich kann mir das nur dadurch erklären, dass ich in der 
Sensorkonfiguration etwas falsch mache. Hier mein Code dazu:
1
void setupAccGyro()
2
{
3
  uint8_t setup[2];  // setup data for burst write
4
  // setup[0] = reg_addr
5
  // setup[1] = reg_data
6
  
7
  while(!(i2c_getState() & I2C_ST_IDLE));   // wait for interface to idle
8
  
9
  setup[0] = 107;    // device reset
10
  setup[1] = (1<<7); // reset
11
  i2c_transmit(GYRO_ADDR, setup, 2);
12
  
13
  _delay_ms(50); // wait for device to finish reset
14
  
15
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
16
  
17
  setup[0] = 106;    // user control
18
  setup[1] = (0<<6); // disable fifo
19
  i2c_transmit(GYRO_ADDR, setup, 2);
20
  
21
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
22
  
23
  setup[0] = 26;  // configuration
24
  setup[1] = (0); // disable fsync and lowpass
25
  i2c_transmit(GYRO_ADDR, setup, 2);
26
  
27
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
28
  
29
  setup[0] = 27;     // gyroscope config
30
  setup[1] = (1<<3); // +- 500°/s range
31
  i2c_transmit(GYRO_ADDR, setup, 2);
32
  
33
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
34
  
35
  setup[0] = 28;     // accelerometer config
36
  setup[1] = (1<<3); // +- 4g/s range
37
  i2c_transmit(GYRO_ADDR, setup, 2);
38
}

Nachdem der Setup fertig ist werden in einem ca. 60Hz-Zyklus die Daten 
von Gyro bzw. Beschleunigungssensor gelesen.

Kann jemand einen Fehler finden?

Grüße

von Wolfgang (Gast)


Lesenswert?

M. T. schrieb:
> Es hängt zusammen mit einem HMC5883L (elektronischer Kompass) am I2C-Bus
> eines ATmega324. Der sendet die I2C-Daten über UART weiter an ein
> Arduino-Board, was als UART-Brücke die Daten an den COM-Port meines PCs
> sendet.

Und du bist sicher, dass nicht einer der beiden ATmegas überflüssig ist? 
Was macht das Arduino Board dabei wirklich?

> Kann jemand einen Fehler finden?
Mmhh.

Was soll das werden?
> setup[1] = (0<<6); // disable fifo

von restfet (Gast)


Lesenswert?

Das Arduinoboard dient als seriell-USB-Wandler, weil auf der 
324er-Platine keiner drauf ist. Der COM-Port am PC ist nämlich kein 
"richtiger" serieller Port.

Wolfgang schrieb:
> Was soll das werden?
> setup[1] = (0<<6); // disable fifo

"Kommentar für Arme" ;-)
Mir ist klar, dass dadurch kein "Nuller ins Bit 6 geschoben" wird. Das 
ist nur für mich selbst, dass ich weiß, dass mit Bit 6 der FIFO 
ein/ausgeschaltet wird.

von M. T. (restfet)


Lesenswert?

Hat jemand eine Idee?

von Herbert (Gast)


Lesenswert?

Bist du sicher, dass du die Bitmanipulation verstanden hast?

a=0b11110000;
a=(0<<6);

Dann ist a gleich 0

von Herbert (Gast)


Lesenswert?

Bist du sicher, dass du die Bitmanipulation verstanden hast?

a=0b11110000;
a=(0<<6);

Dann ist a gleich 0.

von M. T. (restfet)


Lesenswert?

Herbert schrieb:
> Bist du sicher, dass du die Bitmanipulation verstanden hast?

Ja, bin ich.

von Markus F. (mfro)


Lesenswert?

Ich hab' nur einen kurzen Blick in die Registerbeschreibungen geworfen, 
aber da steht ziemlich prominent:

> Note: The device will come up in sleep mode upon power-up.

und ich kann jetzt auf die Schnelle nicht entdecken, wo Du den Kerl 
aufwecken tätest (reset value für das PWR_MGMT_1-Register ist 0x40)...

von Herbert (Gast)


Lesenswert?

M. T. schrieb:
> Herbert schrieb:
>> Bist du sicher, dass du die Bitmanipulation verstanden hast?
>
> Ja, bin ich.

Die Frage war eher rhetorischer Natur. Wenn ich deinen Kommentar im Code 
richtig deute möchtest du im ersten Schreibzyklus den Reset auslösen. 
Das möchtest du machen indem du Bit7 in Register 107 setzt. (Man gibt 
Register in C übrigens immer im Hex Format an (hat sich so eingebürgert 
und gehört zum guten Schreibstil). Besser noch macht man am Anfang ein 
Define, z.B.

#define PWR_MGMT_1 0x6B

dann kannst du immer PWR_MGMT_2 statt 0x61 bzw. 106

Aber zurück zu deinem Bitmanipulationsproblem. So geht das einfach 
nicht.

Lies hier
https://www.mikrocontroller.net/articles/Bitmanipulation


Zur Veranschaulichung habe ich dir deinen Code "übersetzt" was du machst 
und dir statt deiner Bitmanipulation den Binärwert hingeschrieben den du 
auch reinschreiben willst.

1
void setupAccGyro()
2
{
3
  uint8_t setup[2];  // setup data for burst write
4
  // setup[0] = reg_addr
5
  // setup[1] = reg_data
6
  
7
  while(!(i2c_getState() & I2C_ST_IDLE));   // wait for interface to idle
8
  
9
  setup[0] = 107;    // device reset
10
  setup[1] = 0b00000001; // reset
11
  i2c_transmit(GYRO_ADDR, setup, 2);
12
  
13
  _delay_ms(50); // wait for device to finish reset
14
  
15
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
16
  
17
  setup[0] = 106;    // user control
18
  setup[1] = 0b00000000; // disable fifo
19
  i2c_transmit(GYRO_ADDR, setup, 2);
20
  
21
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
22
  
23
  setup[0] = 26;  // configuration
24
  setup[1] = (0); // disable fsync and lowpass
25
  i2c_transmit(GYRO_ADDR, setup, 2);
26
  
27
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
28
  
29
  setup[0] = 27;     // gyroscope config
30
  setup[1] = 0b00001000; // +- 500°/s range
31
  i2c_transmit(GYRO_ADDR, setup, 2);
32
  
33
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
34
  
35
  setup[0] = 28;     // accelerometer config
36
  setup[1] = 0b00001000; // +- 4g/s range
37
  i2c_transmit(GYRO_ADDR, setup, 2);
38
}

von Herbert (Gast)


Lesenswert?

Jetzt habe ich mich selber vertan.
1
while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
2
  
3
  setup[0] = 27;     // gyroscope config
4
  setup[1] = 0b00000001; // +- 500°/s range
5
  i2c_transmit(GYRO_ADDR, setup, 2);
6
  
7
  while(!(i2c_getState() & I2C_ST_IDLE));  // wait for interface to idle
8
  
9
  setup[0] = 28;     // accelerometer config
10
  setup[1] = 0b00000001; // +- 4g/s range
11
  i2c_transmit(GYRO_ADDR, setup, 2);
12
}

Das machst du mit deiner Bitmanipulation. Du siehst du schreibst in die 
Register immer 1 oder 0. hart, egal was vorher drin stand hinterher 
steht im ganzen Register 00000001 oder 00000000

von Markus F. (mfro)


Lesenswert?

Herbert schrieb:
> Du siehst du schreibst in die
> Register immer 1 oder 0. hart, egal was vorher drin stand hinterher
> steht im ganzen Register 00000001 oder 00000000

... und wenn er genau das will?

Es ist nun mal nicht so einfach, ein "und" oder "oder" über den i2c-Bus 
zu schieben...

von M. T. (restfet)


Lesenswert?

Markus F. schrieb:
> Ich hab' nur einen kurzen Blick in die Registerbeschreibungen
> geworfen,
> aber da steht ziemlich prominent:
>
>> Note: The device will come up in sleep mode upon power-up.
>
> und ich kann jetzt auf die Schnelle nicht entdecken, wo Du den Kerl
> aufwecken tätest (reset value für das PWR_MGMT_1-Register ist 0x40)...

Danke!! Das wars. Jetzt kommen von allen drei Sensoren Daten. So oft hab 
ich das Datenblatt gelesen und trotzdem hab ich das übersehn...


Herbert schrieb:
> Man gibt Register in C übrigens immer im Hex Format an (hat sich so eingebürgert
> und gehört zum guten Schreibstil).

Mag schon sein, dass sich das eingebürgert hat, aber hier find ich die 
dezimale Darstellung praktischer, weil die Register im 
Inhaltsverzeichnis vom Datenblatt auch dezimal aufgelistet sind. Und dem 
Compiler ist Hex oder Dec sowieso Jacke wie Hose.

von Herbert (Gast)


Lesenswert?

M. T. schrieb:
> Herbert schrieb:
>> Man gibt Register in C übrigens immer im Hex Format an (hat sich so 
eingebürgert
>> und gehört zum guten Schreibstil).
>
> Mag schon sein, dass sich das eingebürgert hat, aber hier find ich die
> dezimale Darstellung praktischer, weil die Register im
> Inhaltsverzeichnis vom Datenblatt auch dezimal aufgelistet sind. Und dem
> Compiler ist Hex oder Dec sowieso Jacke wie Hose.

Ja da hast du Glück, das ist eines der wenigen Datenblättern bei dem es 
in Dezimal angegeben ist. Da wirst du bei anderen Datenblättern nichts 
finden. Bei 8 bit geht es noch, bei 16 bit braucht man schon echt Übung 
und bei 32 bit ist es schier unmöglich irgendwas zu erkennen. Hex hat 
halt den Vorteil, dass man immer 4 Bit auf einmal zusammengefasst sieht. 
Diese Magic Numbers sind ohnehin Schrott und gehören als #define 
ersetzt. Das ist ja ätzend sonst. Gleiches gilt für Bitmasken

M. T. schrieb:
> setup[1] = (1<<3); // +- 500°/s range

das macht man einfach nicht. Das gibt Trouble bei jedem Code Review. 
Schon in der I2C Funktion die du verwendest ist das gleich mal richtig 
gemacht.

Dein Codeabschnitt

M. T. schrieb:
> while(!(i2c_getState() & I2C_ST_IDLE));   // wait for interface to
> idle
>
>   setup[0] = 107;    // device reset
>   setup[1] = (1<<7); // reset
>   i2c_transmit(GYRO_ADDR, setup, 2);

gehört (streng genommen) so:
1
#define REG__PWR_MGMT_1 0x6B
2
#define DEVICE_RESET 7
1
  while(!(i2c_getState() & I2C_ST_IDLE));   // wait for interface to idle
2
  
3
  setup[0] = REG__PWR_MGMT_1;    // device reset
4
  setup[1] |= (1 << DEVICE_RESET); // reset
5
  i2c_transmit(GYRO_ADDR, setup, 2);

von Herbert (Gast)


Lesenswert?

Markus F. schrieb:
> Herbert schrieb:
>> Du siehst du schreibst in die
>> Register immer 1 oder 0. hart, egal was vorher drin stand hinterher
>> steht im ganzen Register 00000001 oder 00000000
>
> ... und wenn er genau das will?

Könnte theoretisch sein dem Kommentar nach zu urteilen möchte er den 
Device Reset machen und das geht durch setzen von Bit7

  setup[0] = 107;    // device reset
  setup[1] = (1<<7); // reset
  i2c_transmit(GYRO_ADDR, setup, 2);

Nur setzt er hier sicher nicht Bit7 sondern Bit0 und löscht alle anderen 
Bits.

> Es ist nun mal nicht so einfach, ein "und" oder "oder" über den i2c-Bus
> zu schieben...

Ich gehe zu Gunsten des Codeschreibers stark davon aus, dass diese I2C 
Funktion zuerst die Werte einliest und dann zurückschreibt. Ansonsten 
wäre die Bitmanipulation ja völlig wertlos und würde zeigen, dass jemand 
grundlegende Konzepte nicht verstanden hat.

von Markus F. (mfro)


Lesenswert?

Herbert schrieb:
> setup[0] = 107;    // device reset
>   setup[1] = (1<<7); // reset
>   i2c_transmit(GYRO_ADDR, setup, 2);
>
> Nur setzt er hier sicher nicht Bit7 sondern Bit0 und löscht alle anderen
> Bits.

Da solltest Du möglicherweise nochmal drüber nachdenken.

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.