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
voidsetupAccGyro()
2
{
3
uint8_tsetup[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
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
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.
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)...
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
voidsetupAccGyro()
2
{
3
uint8_tsetup[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
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
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...
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.
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
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.
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.