PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C für Anfänger, Arduino - MMA7660 Beschleunigungssensor



PlasmaTubeI²C
04.05.2013, 12:32
Hi,

ich bräuchte ein bisschen Unterstützung beim Einstieg in die I2C-Welt ;)

Bisher habe ich um Sensoren die per I2C kommunizieren auszulesen eine entsprechende Library für Arduino verwendet,
aber ich will jetzt auch mal die internen Register selbst ansprechen. Als Beispiel soll hier der Beschleunigungssensor
MMA7660 dienen. (Datenblatt gibt es hier: http://http://garden.seeedstudio.com/images/e/ee/MMA7660FC.pdf )
Ich hab zwar schon Google nach Infos durchforstet, aber mir fehlen halt die Grundlagen dazu. Wobei die Arduino-Befehle für I2C noch recht übersichtlich an der Zahl sind.



#include <Wire.h>
#define I2C_ADDRESS 0x4C

void setup(){
Serial.begin(9600);
Wire.begin(I2C_ADDRESS);
}
void loop(){
//start talking
Wire.beginTransmission(I2C_ADDRESS);
//ask for register
Wire.write(0x00);
//complete transmission
Wire.endTransmission();
//request 1 byte
Wire.requestFrom(I2C_ADDRESS, 1);
//wait for response
while(Wire.available() == 0);
//get the value
int x = Wire.read();
//printout
Serial.print(x);
Serial.println(", ");
delay(100);
}


Der Code an sich funktioniert leider nicht, bekomme nur 0-Werte für x.

Klar erstmal die Wire library hinzufügen und die Adresse des Sensors angeben. Mit Wire.begin die I2C Verbindung initialisieren und mit Wire.beginTransmission den Datenverkehr
zwischen Arduino und dem MMA7660 beginnen. Das Wire.write(0x00) soll das erste Register ansprechen, was sagt dem Sensor dieser Befehl? Praktisch eine Anfrage
dass dieses Register ausgelesen werden möchte? Wie mache ich dann am besten weiter? Mein Ziel ist es, nur das erste Register auszulesen, so schwer
wird das doch wohl ned sein...

Hoffe auf Antworten! :)

RoboHolIC
04.05.2013, 23:38
Hallo Stefan.

Die Adressierung am I2C-Bus wird m.W. je nach Bibliothek unterschiedlich gehandhabt: die einen betrachten die Adresse plus das 0-Bit für's schreiben als Basisadresse (Bits 7..0) und addieren beim lesen Eins dazu, die anderen betrachten nur den festen Teil (Bits 7..1) als Basisadresse und handhaben das R/W-Bit isoliert davon. So können die Adressen für ein-und-den-selben Baustein eben hex40 (für schreiben) und hex41 (für lesen) sein oder hex20 (also rechtsbündig gedacht ohne das R/W) plus das R/W-Flag.

Zum anderen kommen mir die Start- und Stopbefehle der I2C-Bibliothek rein aus der Sicht eines Outsiders etwas spanisch vor: Explizites Eröffnen und Beenden der Kommunikation, dito auch mal scheinbar implizit; Schreiben einer Adresse und dann Wire.Requestfrom(...) mit seinen zwei Argumenten - ich finde da die Strukturen des Busprotokolls nicht wieder, wie ich sie mir auf Assemblerebene angeeignet habe.
Bist du dir sicher, dass die gewählte Befehlsfolge wirklich das erforderliche Busprotokoll erzeugt? (Ich behaupte nicht, dass sie es nicht täte !!!!)

Gruß
RoboHolIC

Amri
05.05.2013, 10:24
Hallo!

Schau dir im Datenblatt einmal Seite 14 an. Da steht, was die einzelnen Register sind. Im Register 0x00 ist zum Beispiel immer der aktuelle Messwert für XOUT gespeichert, mit "Wire.write(0x00);" sagst du dem Sensor, dass du dieses Register auslesen möchtest.

Auf Seite 24 unter "Message Format for Reading MMA7660FC" siehst du, wie der Sensor ausgelesen wird. Die Schritte die man dort sieht entsprechen deinem Code.

Du könntest einmal versuchen, die anderen Register auszulesen. Wenn das Ergebnis überall 0 ist stimmt vielleicht etwas mit dem i2c-Bus nicht...

PlasmaTubeI²C
05.05.2013, 12:58
Hi,

danke für die Antworten!
Habs schonmal hinbekomen, es werden endlich Werte ausgegeben. Da ich ja mehrere Werte abfragen will, muss ich auch mehrere Variablen zum temporären Zwischenspeichern bereitstellen.



void loop(){
//start talking
Wire.beginTransmission(I2C_ADDRESS);
//ask for register
Wire.write(0x00);
//complete transmission
Wire.endTransmission();
//request 1 byte
Wire.requestFrom(I2C_ADDRESS, 7);
//wait for response
while(Wire.available() == 0);
//get the value
int a = Wire.read();
int b = Wire.read();
int c = Wire.read();
int d = Wire.read();
int e = Wire.read();
int f = Wire.read();
int g = Wire.read();
//printout
Serial.print(a);
Serial.print(", ");
Serial.print(b);
Serial.print(", ");
Serial.print(c);
Serial.print(", ");
Serial.print(d);
Serial.print(", ");
Serial.print(e);
Serial.print(", ");
Serial.print(f);
Serial.print(", ");
Serial.print(g);
Serial.println(", ");
delay(100);
}


Der Hauptteil bisschen verändert, mit Wire.write sage ich dass ich das erste Register auslesen möchte, so viel hab ich erstmal verstanden. Aber ich will ja nur das erste Register mit den
X-Werten auslesen, welches aus 7 nutzbaren Bits besteht, soweit ich das richtig lese, also schreibe ich doch auch beim Wire.request dass ich 7 Bits erhalten möchte oder? Oder kann man
die garned einzeln auslesen?
Als Return kommen nur die int-Werte der Register von 0x00 - 0x06, nicht der Bit-Inhalt des ersten Registers.
Heißt das die 7 gibt die Anzahl der auszulesenden Register inklusive dem ersten genannten an und man immer nur auf ein gesamtes Register Zugriff hat, nicht auf die einzelnen Bits?

Das verwirrt mich grade etwas ;)

Amri
05.05.2013, 14:25
Heißt das die 7 gibt die Anzahl der auszulesenden Register inklusive dem ersten genannten an und man immer nur auf ein gesamtes Register Zugriff hat, nicht auf die einzelnen Bits?

Genau so ist es. Du kannst immer nur ganze Register auslesen.
Wenn du nur bestimmte Bits daraus brauchst musst du den ausgelesenen Wert noch maskieren. Um die ersten beiden Bits zu löschen, also auf 0 zu setzen, schreibst du zum Beispiel
x = x & 0b00111111;

PlasmaTubeI²C
05.05.2013, 17:48
Ahh ok, dann is das schonmal klar.
Und um einzelne Bits zu ändern muss man immer das gesamte Register neu beschreiben. Was macht in deinem code das b nochmal?
Wie würde das jetzt in meinem Beispiel ausschauen wenn ich das erste Register neu beschreibe?
Wire.write(0x00) ruft das Register auf, was muss man dann noch schreiben, um alle Bits zu überschreiben?