PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C Sensor - Bekomme keinen Wert



hannes_u
21.03.2013, 17:44
Hallo Roboternetz,

ich versuche gerade vergeblich meinen ersten I2C Sensor auszulesen und auf einem LCD darzustellen.

Es handelt sich dabei um den l3gd20 Gyrosensor der auf folgendem Board enthalten ist:
http://www.ebay.de/sch/i.html?_from=R40&_trksid=p4340.m570.l2736&_nkw=L3G4200D

Die Adressen habe ich mal von folgendem INC File entnommen: http://www.mikrocontroller.net/attachment/161859/L3G4200D.inc
Dieses stammt von diesem Post: http://www.mikrocontroller.net/topic/278690#2937191

Hier mal vorab mein Code:


$regfile = "m8def.dat"
$crystal = 8000000

Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portd.7 , Db6 = Portb.0 , Db7 = Portd.4 , E = Portd.5 , Rs = Portb.7
Config Lcd = 16 * 2
Cls

Dim Wert As Word
Dim Wert2 As Word


Config Scl = Portc.5
Config Sda = Portc.4


Const L3g4200dslaveid = &HD2 'I2C SlaveAdresse GYRO

Do


I2cstart
I2cwbyte L3g4200dslaveid
I2cwbyte &H28
I2crbyte Wert

I2cwbyte L3g4200dslaveid
I2cwbyte &H29
I2crbyte Wert2
I2cstop


Waitms 10

Cls
Locate 1 , 1
Lcd Wert
Locate 2 , 1
Lcd Wert2
Waitms 100

Loop
End

Leider zeigt das Display nur 0 und 0 an.

Könnt ihr mir sagen was ich falsch mache?

Kampi
21.03.2013, 18:01
Hey,

ohne jetzt genauer ins Datenblatt zu gucken etc. Aber solltest du nicht nach dem Lesen des ersten Bytes ein Stop senden? Und erwartet der Sensor kein ACK/NACK nachdem du ein Byte gelesen hast?

hannes_u
21.03.2013, 19:52
Habe jetzt mal folgenden Code probiert:

I2cstart
I2cwbyte L3g4200dslaveid
I2cwbyte &H28
I2crbyte Wert , Ack
I2cstop

I2cstart
I2cwbyte L3g4200dslaveid
I2cwbyte &H29
I2crbyte Wert2 , Nack
I2cstop

Jetzt bekomme ich nichtmehr 0 und 0 sondern 255 und 255.

Habe ich richtig verstanden das Ack einen weiteren Wert fordert und Nack dann keinen mehr?

- - - Aktualisiert - - -

Habe jetzt nocheinmal ins Datenblatt geschaut:

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/CD00265057.pdf

Seite 22 bzw. 5.1.1 Table 13. Hier ist die Adressierung beschrieben.
Ich habe hier zwei Adressen:

Read (D3h) => Müsste doch dann in Bascom &HD3 sein?

Write (D2h)

Die Adressen die dann ausgegeben werden können sind auf Seite 27:

OUT_X_L output (28) => Müsste dann in Bascom &H28 sein?

OUT_X_output (29)

Che Guevara
21.03.2013, 21:14
Hi,

ja Ack bedeutet du erwartest noch etwas, bei Nack nicht mehr. Allerdings hast du da schon einen Fehler drin, da in deiner ersten Abfrage ein Ack steht anstatt Nack.
Ich glaube, du musst zuerst die Slave-Adresse senden, anschließend das benötigte Register, dann einen RepStart und dann kommen die Werte. Wenn du zwei Register hintereinander lesen willst bietet es sich meistens an, dies direkt hintereinander zu tun, also:


i2cstart
i2cwbyte L3g4200slaveid
i2cwbyte &h28
i2crepstart
i2crbyte wert1 , ack
i2crbyte wert2, nack
i2cstop


Gruß
Chris

Kampi
21.03.2013, 21:26
Du darfst außerdem nicht immer die selbe Adresse nehmen. Die Registerauswahl ist ein Schreibbefehl, da du das Register was du auslesen willst, auf den Bus schreibst. Das heißt für die Registerwahl musst du die Schreibadresse nehmen. Nach einem erneuten Start musst du die Leseadresse übersenden, da du aus dem Register lesen willst.

hannes_u
22.03.2013, 14:45
Daher meinst du das dann der Code folgendermaßen lauten muss:




i2cstart ' i2c Starten
i2cwbyte &HD2 ' Write Register senden (Read wäre &HD3)
i2cwbyte &h28 ' Register was ich lesen will
i2crepstart ' mir unbekannter Befehl
i2crbyte wert1, ack 'Wert des Registers &h28 wird in wert1 geschrieben
i2crbyte wert2, nack ' *?* wird hier jetzt automatisch das letzte Register um 1 erhöht (daher &h29) und dann in wert2 geschrieben?
i2cstop

So sollte es funktionieren? Hab ich den Code so richtig verstanden?

Vielen Dank für die freundliche Unterstützung! Habe bisher eben noch nie etwas mit I2C gemacht.

- - - Aktualisiert - - -

Habe jetzt den Code so versucht. Leider bekomme ich zweimal nur den Wert 40 angezeigt obwohl ich den Gyro bewege.
Wenn ich statt der W Adresse &HD2 die R Adresse &HD3 verwende bekomme ich zweimal konstant den Wert 195.

Klemme ich den Sensor ab bekomme ich zweimal 0.

Mhm, und nun? Schwerer Anfang ;)

Che Guevara
22.03.2013, 14:55
Hi,

probier mal das :


i2cstart
i2cwbyte &hd2
i2cwbyte &h28
i2crepstart
i2cwbyte &hd3
i2crbyte wert1 , ack
i2crbyte wert2 , nack
i2cstop


Gruß
Chris

Kampi
22.03.2013, 15:00
Hey,

nach dem wiederholten Start musst du die Deviceadresse erneut auf den Bus legen.
Die Kommunikation lautet also wie folgt:

I2C Start
Deviceadresse zum Schreiben
Registeradresse welches du auslesen willst
I2C wiederholter Start
Deviceadresse zum Lesen
Daten lesen und mit Ack/Nack bestätigen
I2C Stop

hannes_u
22.03.2013, 15:01
Und gleich nochmals ein Update:


I2cstart ' i2c Starten
I2cwbyte &HD2 ' Write Register senden (Read wäre &HD3)
I2cwbyte &H28 ' Register was ich lesen will
I2cstart
I2cwbyte &HD3 'Lese Register senden
I2crbyte Wert1 , Ack 'Wert des Registers &h28 wird in wert1 geschrieben
I2crbyte Wert2 , Nack ' *?* wird hier jetzt automatisch das letzte Register um 1 erhöht (daher &h29) und dann in wert2 geschrieben?
i2cstop

jetzt habe ich jedesmal einen anderen Wert stehen wenn ich den Controller starte. Allerdings ändert sich dieser nicht wenn ich drehe. Erst wenn ich die Spannung abschalte und wieder neu einschalte habe ich einen anderen Wert.

Sehr auffällig ist auch das Wert1 und Wert2 immer identisch sind.

Kampi
22.03.2013, 15:05
Du hast den Code ab schon in einer

Do
Loop

Schleife oder :D? Weil sonst wird der nur einmal ausgeführt (doofe Frage ich weiß aber es hört sich so an....)

hannes_u
22.03.2013, 15:33
$regfile = "m8def.dat"
$crystal = 8000000

Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portd.7 , Db6 = Portb.0 , Db7 = Portd.4 , E = Portd.5 , Rs = Portb.7
Config Lcd = 16 * 2
Cls

Dim Wert1 As Word
Dim Wert2 As Word
Dim Sad As Byte

$lib "i2c_twi.lbx"

Config Scl = Portc.5 ' Ports fuer IIC-Bus, nicht Standard !
Config Sda = Portc.4

Waitms 1000
Do

I2cstart ' i2c Starten
I2cwbyte &HD2 ' Write Register senden (Read wäre &HD3)
I2cwbyte &H28 ' Register was ich lesen will
I2cstart
I2cwbyte &HD3 'Lese Register senden
I2crbyte Wert1 , Ack 'Wert des Registers &h28 wird in wert1 geschrieben
I2crbyte Wert2 , Nack ' *?* wird hier jetzt automatisch das letzte Register um 1 erhöht (daher &h29) und dann in wert2 geschrieben?
i2cstop




Waitms 10

Cls
Locate 1 , 1
Lcd Wert1
Locate 2 , 1
Lcd Wert2
Waitms 1000

Loop
End

Che Guevara
22.03.2013, 15:45
Hi,

mach mal noch ein Config Twi = 400000 / 100000 rein und ein I2cinit. Außerdem würde ich Wert1 & Wert2 als Byte deklarieren. Dann könntest du dir noch den Error ausgeben lassen, um zu sehen, ob die Kommunikation überhaupt funktioniert.

Gruß
Chris

hannes_u
22.03.2013, 16:05
Dim Wert1 As Byte
Dim Wert2 As Byte
Dim Sad As Byte

$lib "i2c_twi.lbx"

Config Twi = 100000
I2cinit

Config Scl = Portc.5
Config Sda = Portc.4

Waitms 1000


Nach wie vor nur beim Einschalten dann nach einer Sekunde Für Wert1 und Wert2 den gleichen Wert der sich nicht ändert. Das kann mal 200 mal 75 oder mal 105 etc sein.

mit Config Twi = 400000 zeigt sich das Gleiche.

Sehr seltsam.

Che Guevara
22.03.2013, 16:23
Hi,

probier mal das :


$regfile = "m8def.dat"
$crystal = 8000000
$framesize = 80
$hwstack = 80
$swstack = 80



Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portd.7 , Db6 = Portb.0 , Db7 = Portd.4 , E = Portd.5 , Rs = Portb.7
Config Lcd = 16 * 2
Cls


$lib "i2c_twi.lbx"
Config Scl = Portc.5
Config Sda = Portc.4
Config Twi = 400000
I2cinit


Dim Wert1 As Word
Dim Wert2 As Word
Dim Sad As Byte



Waitms 200



Do


I2cstart
I2cwbyte &HD2
I2cwbyte &H28
I2crepstart
I2cwbyte &HD3
I2crbyte Wert1 , Ack
I2crbyte Wert2 , Nack
I2cstop

Sad = Err

Locate 1 , 1
Lcd Wert1 ; " : " ; Wert2 ; " "
Locate 2 , 1
Lcd "Error: " ; Sad ; " "


Waitms 1000


Loop

End

Weißt du den, dass der Sensor funktioniert?

Gruß
Chris

hannes_u
22.03.2013, 16:36
Sowas ähnliches habe ich gerade auch Gecodet.
Also die Errorausgabe auf dem LCD.

Mit deinem Code erhalte ich zb.
200 : 200
Error 0

102 : 102
Error 0

75 : 75
Error 0

Aber lediglich nur wenn ich die Spannung neu anmache. Sobald ich den Atmega8 laufen lasse ändert sich die Anzeige auf dem Bildschirm nichtmehr.
Nehme ich den Sensor aus seinem Sockel raus erhallte ich immer
205 : 205
Error 1


Der Sensor ist total neu. Ob er funktioniert kann ich nicht sagen da ich nicht weiß wie ich das prüfen könnte.

Che Guevara
22.03.2013, 16:51
Hast du mal im DB nachgeschaut, ob der Sensor irgendwie initalisiert werden muss? Bei den meisten Gyros kann man / muss man einstellen, welchen Wertebereich der erfassen soll, welchen Taktgeber er verwendet usw...
Sind Pullups in der Schaltung integriert?

Gruß
Chris

hannes_u
22.03.2013, 17:24
Genau an dem bin ich gerade dran.

Der Code den ich zu Beginn in meinem Post schonmal gepostet hab: http://www.mikrocontroller.net/attachment/161858/I2C_Ansteuerung_Ver2_Pololu_MinIMU-9.bas
Dieser enthält:



Sub GYRO_ini() ' L3G4200D_CTRL_REG4_Wert = &b00000000 '250 dps full scale L3G4200D_CTRL_REG4_Wert = &b00010000 '500 dps full scale ' L3G4200D_CTRL_REG4_Wert = &b00100000 '2000 dps full scale call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG1 , &b00001111) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG2 , &b00100110) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG3 , &b00000000) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG4 , L3G4200D_CTRL_REG4_Wert) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG5 , &b00000000) call Register_schreiben(L3G4200DSlaveid , L3G4200D_REFERENCE , &b00000000) end sub


Ich habe das jetzt mal so vor der DO Loop umgesetzt:


I2cstart
I2cwbyte &HD2
I2cwbyte &H20
I2cwbyte &B00001111
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H21
I2cwbyte &BB00100110
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H22
I2cwbyte &B00000000
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H23
I2cwbyte &B00010000
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H24
I2cwbyte &B00000000
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H25
I2cwbyte &B00000000
I2cstop


Jetzt bekomme ich jede Sekunde wahllos Werte ausgespuckt, selbst wenn der Sensor ruhig liegt schwanken diese zwischen 30 und 200 etc... Aber ich bekomme schon mal Werte übertragen.


Der gute Mann ließt die Werte so ein:




Sub X_GYRO_lesen() Gyro_Status_Reg = Register_lesen(L3G4200DSlaveid , L3G4200D_STATUS_REG) if Gyro_Status_Reg.0 = 1 then call GYRO_BDU_EIN Gyro_X_h = Register_lesen(L3G4200DSlaveid , L3G4200D_OUT_X_H) Gyro_X_l = Register_lesen(L3G4200DSlaveid , L3G4200D_OUT_X_L) call GYRO_BDU_AUS Gyro_X = MAKEINT(Gyro_X_l , Gyro_X_h) end if End Sub

Was hat das mit dem

call GYRO_BDU_EIN
bzw
call GYRO_BDU_AUS
auf sich?

Liegt dort das letzte Rätsel versteckt? Diesen Teil versteh ich nicht ganz.

- - - Aktualisiert - - -

Ich habe jetzt mal den BascomCode von dem anderen Forum genommen und nur auf meine Anwendung gekürzt. Funktioniert 1A!
Jetzt versuche ich das mal Schritt für Schritt zu meinem Ursprünglichen Code umzuschreiben. Wenn ich den Fehler gefunden habe geb ich euch Bescheid!

Danke für die Unterstützung! :)

Kampi
22.03.2013, 19:06
Genau an dem bin ich gerade dran.

Der Code den ich zu Beginn in meinem Post schonmal gepostet hab: http://www.mikrocontroller.net/attachment/161858/I2C_Ansteuerung_Ver2_Pololu_MinIMU-9.bas
Dieser enthält:



Sub GYRO_ini() ' L3G4200D_CTRL_REG4_Wert = &b00000000 '250 dps full scale L3G4200D_CTRL_REG4_Wert = &b00010000 '500 dps full scale ' L3G4200D_CTRL_REG4_Wert = &b00100000 '2000 dps full scale call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG1 , &b00001111) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG2 , &b00100110) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG3 , &b00000000) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG4 , L3G4200D_CTRL_REG4_Wert) call Register_schreiben(L3G4200DSlaveid , L3G4200D_CTRL_REG5 , &b00000000) call Register_schreiben(L3G4200DSlaveid , L3G4200D_REFERENCE , &b00000000) end sub


Ich habe das jetzt mal so vor der DO Loop umgesetzt:


I2cstart
I2cwbyte &HD2
I2cwbyte &H20
I2cwbyte &B00001111
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H21
I2cwbyte &BB00100110
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H22
I2cwbyte &B00000000
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H23
I2cwbyte &B00010000
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H24
I2cwbyte &B00000000
I2cstop

I2cstart
I2cwbyte &HD2
I2cwbyte &H25
I2cwbyte &B00000000
I2cstop


Jetzt bekomme ich jede Sekunde wahllos Werte ausgespuckt, selbst wenn der Sensor ruhig liegt schwanken diese zwischen 30 und 200 etc... Aber ich bekomme schon mal Werte übertragen.


Der gute Mann ließt die Werte so ein:




Sub X_GYRO_lesen() Gyro_Status_Reg = Register_lesen(L3G4200DSlaveid , L3G4200D_STATUS_REG) if Gyro_Status_Reg.0 = 1 then call GYRO_BDU_EIN Gyro_X_h = Register_lesen(L3G4200DSlaveid , L3G4200D_OUT_X_H) Gyro_X_l = Register_lesen(L3G4200DSlaveid , L3G4200D_OUT_X_L) call GYRO_BDU_AUS Gyro_X = MAKEINT(Gyro_X_l , Gyro_X_h) end if End Sub

Was hat das mit dem

call GYRO_BDU_EIN
bzw
call GYRO_BDU_AUS
auf sich?

Liegt dort das letzte Rätsel versteckt? Diesen Teil versteh ich nicht ganz.

- - - Aktualisiert - - -

Ich habe jetzt mal den BascomCode von dem anderen Forum genommen und nur auf meine Anwendung gekürzt. Funktioniert 1A!
Jetzt versuche ich das mal Schritt für Schritt zu meinem Ursprünglichen Code umzuschreiben. Wenn ich den Fehler gefunden habe geb ich euch Bescheid!

Danke für die Unterstützung! :)

Das klingt doch super :)

Che Guevara
22.03.2013, 20:43
Hi,

BDU steht für Block Data Update. Das bedeutet, solange BDU gesetzt ist (1), werden die Register, in denen der 16Bit Wert enthalten ist, nicht verändert, damits beim Auslesen keinen Datenwirrwarr gibt, eine Art Dead Lock.
Ob der Sensor zwingend auf die Veränderung dieses Bits warten, kann ich dir nicht sagen, wird sicher irgenwo stehen.

Viel Erfolg!

Gruß
Chris

hannes_u
24.03.2013, 16:37
Genau das wars! Erst wenn der Wert ausgelesen wurde setzt er wieder neue in das Register.
Ich bin echt froh das ich gleich am Anfang mal einen recht komplizierten I2C Sensor genommen habe. Jetzt versteh ich grundsätzlich den Aufbau dieser Dinger und kann mit dem ACC weiter machen.

Ich hab hier sogar schon ganz schöne Ergebnisse beim Integrieren um den Winkel zu erhalten. Sehr wenig Drift! :)

Bisher hatte ich immer Analoge Gyros. Sehr ungenau...

Vielen Dank euch allen und noch einen schönen Sonntag! :)