L3G4200D Register auslesen

OP #2936388
Lesenswert?

Hallo,

ich möchte das Gyroscope (L3G4200D - ich besitze das Breakout board von 
Pololu) gerne auslesen und die Daten dann auf einem Display ausgeben.

Ich nutze einen ATMEGA16 und programmiere in C / C++.
Verbinden möchte ich den Sensor per SPI.

Leider gelingt es mir nicht geeignete Tutorials oder Einsteigertipps 
hierzu zufinden. Auf der Pololu-Seite gibt es nur Arduino-Language 
Sample-Code. Arduino-Language möchte ich aber nicht nutzen auch wenn 
diese c-ähnlich oder was auch immer ist.

Meine konkrete Frage ist also wie ich programmiertechnisch auf die 
verschiedenen Register des Sensors zugreifen kann bzw. diese auslese und 
in Variablen abspeicher.

Simpelster Beispielcode in c wäre Klasse oder irgendwelche Hinweise wie 
ich mich darüber schlau lesen kann.

EDIT: Die grundsätzliche Kommunikation per SPI ist mir bekannt und hat 
auch schon mit einem anderen µC funktioniert, allerdings will ich nun ja 
verschiedene Register des Sensors auslesen bzw verändern, nur weiß ich 
nicht wie das funtioniert.
Anhang meiner bisherigen SPI-Kommunikation siehe SPI.c
Angehängte Dateien:
OP #2936428
Lesenswert?

Funktioniert Die Kommunikation mit dem Sensor vielleicht so, dass ich 
wenn ich das Ctrl_Reg1 auslesen will, dafür folgendes vom Master senden 
muss:

1      0           100000
Read | no incre. | Ctrl_Reg1

Daraufhin sendet mir der Sensor das Register und ich kann es aus dem 
SPDR auslesen?

Ich kenne mich mit SPI leider noch so gutt wie garnicht aus und möchte 
meinen Sensor nicht gleich mit dem ersten "Befehl" zerstören. Ich wäre 
sehr dankbar für eine Reaktion!
Gast #2936435
Lesenswert?

Florian K. schrieb:
> Ich kenne mich mit SPI leider noch so gutt wie garnicht aus

Also darfst du dich SELBST einarbeiten. Dauer: keine 15 Minuten. Im 
Datenblatt des Atmega ist ALLES piekfein beschrieben.

Florian K. schrieb:
> möchte
> meinen Sensor nicht gleich mit dem ersten "Befehl" zerstören

Also wenn du es schaffst, irrtümlich durch einen "falschen" Befehl den 
Sensor zu schrotten, dann kommst du in den "Hall of Flame" und ich kaufe 
dir einen neuen Sensor :-)

Jetzt aber im Ernst: nur Mut! Programmieren, testen, debuggen... so wie 
es auch die Großen machen.
OP #2936613
Lesenswert?

@Dennis: Danke für deine Motivation, leider schaffe ich es dennoch nicht 
alleine aus den Datenblättern heraus schlau zu werden, ich möchte auch 
garnicht eine fertige Lösung für eine konkrete Aufgabenstellung, mir 
würde schon reichen das WHO_AM_I Register auszulesen und in einer 
Variable abzuspeichern.

Mein Versuch sieht so aus und gibt mir leider nur 255 zurück, was dann 
wohl für 0b11111111 steht und nicht meinem WHO_AM_I Register entspräche! 
:(
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "MrLCD.h"
4
#include <stdlib.h>
5

6
void master_init (void);
7
void master_transmit (unsigned char data);
8

9
int WHO_AM_I = 0;
10
char WHO_AM_I_dez[8];
11

12
int main (void)
13
{
14

15
  master_init ();
16
  sei ();
17
  master_transmit(0b10001111);
18
  WHO_AM_I = SPDR;
19

20
  InitializeMrLCD();
21
  
22
  
23
  itoa(WHO_AM_I, WHO_AM_I_dez, 10);
24

25
  GotoMrLCDsLocation(1,1);
26
  Send_A_String(WHO_AM_I_dez);
27
  
28
  while(1)
29
  {  
30

31
  }
32
}
33

34
void master_init (void)
35
{
36
  DDRB |= 1 << (PB4) | 1 << (PB5) | 1 << (PB7);
37
  DDRB &= ~(1 << PB6);
38
  PORTB |= 1 << (PB4) | 1 << (PB7) | 1 << (PB0);
39
  SPCR |= 1 << (SPE) | 1 << (MSTR) | 1 << (SPR1);
40
  SPSR |= 1 << (SPI2X);
41
}
42

43
void master_transmit (unsigned char data)
44
{
45
  PORTB &= ~(1 << PB0);
46
  SPDR = data;
47
  while (!(SPSR & (1<<SPIF)));
48
  PORTB |= 1 << (PB0);
49
}

@Jo:  Ja ich bin sehr an Code interessiert :)
#2937191
Lesenswert?

Hallo Florian,
ich habe mal hier meine BASCOM-Dateien angehäng.

Was ich allerdings benutzt habe war das MinIMU-9 von Pololu
an ein PollinBoard mit ATmega88 drauf. Anschlüsse waren angelötet
mit 10kOhm Pullup-Widerständen gegen +5V.
Auf dem Board sind 3-Achsen Gyro L3G4200D und 3-Achsen Kompass / 
Beschleunigungssensor LSM303DLM.
Sollte mal für ein Mikrokopter sein, habe aber schon länger aus 
Zeitmangel
nichts mehr damit gemacht.

Ich hoffe du kannst was damit anfangen auch wenn es nur BASIC ist.

Und für alle anderen MitLeser:
-> Bitte verzeiht mein schlechten Programmierstil!
   (Aber es hat funktioniert!!)

Holger
Angehängte Dateien:
(Firma: Jo) #2938152
Lesenswert?

So jetzt aber. Die Datei einfach einbinden und dann in der Main 
folgendes aufrufen um die Sensorwerte auszulesen:
1
//Buffer für High und Low Bytes
2
volatile uint8_t low = 0;
3
volatile uint8_t high = 0;
4

5
//Gyro Output
6
volatile int l3g_erg_x = 0;
7
volatile int l3g_erg_y = 0;
8
volatile int l3g_erg_z = 0;
9

10

11
// Pins für SPI konfigurieren
12
init_spi_l3g();
13

14
// GYRO aktivieren und konfigurieren
15
config_l3g();
16

17
////////////////////// READ GYRO DATA IN MULTIPLE READ MODUS ////////////////////
18
    send_byte_l3g(232); 
19

20
    low = read_byte_l3g();
21
    high = read_byte_l3g();
22
    l3g_erg_x = (int)(low + (high << 8));
23

24
    low = read_byte_l3g();
25
    high = read_byte_l3g();
26
    l3g_erg_y = (int)(low + (high << 8));
27

28
    low = read_byte_l3g();
29
    high = read_byte_l3g();
30
    l3g_erg_z = (int)(low + (high << 8));
31

32
    complete_l3g();
33
    /////////////////////////////////////////////////////////////////////////////////
Angehängte Dateien:
(Firma: Jo) #2938191
Lesenswert?

Florian K. schrieb:
> Vielen Dank schon einmal ich werde es mir sofort anschauen! :)
> Was genau bedeutet diese Zeile Code?
>
1
> if ( byte & (1<<(7)) )
2
>

Ich schau mir das Bit Nummer 7 in der Variablen Byte an und setze 
demgemäß meinen Ausgangspin auf 1 oder 0 je nachdem ob das Bit 1 ist 
oder 0 ist. Das Ganze wird 8 mal durchgeführt bis das ganze Byze 
rausgesendet wurde. Der Code ist deshalb etwas lang geraten. Prinzipiell 
kann man den ganzen Spaß auch in einer For-Schleife machen, dann spart 
man sich eine Menge Zeilen.

PS:

Deine Ausgangspins musst du natürlich noch entsprechend an dein Design 
anpassen. Das vergaß ich oben zu erwähnen.
OP #2938213
Lesenswert?

Ok ich hab es verstanden, ich nahm naiver weise an, das der AVR am 
SPI-BUS zumindest die Chip-Select Leitung selbst steuert und ich direkt 
eine 8-BIT Zahl senden kann.

Naja aber vielen vielen dank! Du hast mir damit sehr geholfen, heute 
habe ich keinen Kopf mehr das anzupassen aber ich werde morgen versuchen 
die Register auszulesen und teile dann nochmal mein Ergebnis mit :)
Genau danach habe ich nun Zwei Tage gesucht :D
(Firma: Jo) #2938219
Lesenswert?

> Ok ich hab es verstanden, ich nahm naiver weise an, das der AVR am
> SPI-BUS zumindest die Chip-Select Leitung selbst steuert und ich direkt
> eine 8-BIT Zahl senden kann.

Zur Harware SPI des AVR kann ich nichts sagen. Der Code von oben ist 
Soft-SPI - d.h an allen Portpins verwendbar.

Auf jeden Fall viel Erfolg.
OP #2938915
Lesenswert?

@Eumel:
Ich meine überall zu lesen das folgende Zeilen ausreichen um ein Byte 
auzulesen:
1
char ReadByteSPI(char addr)
2
{
3
  SPDR = addr;      //Load byte to Data register
4
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete 
5
  addr=SPDR;
6
  return addr;
7
}

Wobei addr zum Beispiel = 0b10001111 ist um das Register WHO_AM_I 
auszulesen.
Und als Rückgabewert dann 0b11010011 ausgeben sollte

Ich erhalte allerdings immer als Rückgabewert 255.

@ Jo:
Ja ich möchte wirklich gerne den SPI-BUS verwenden!
Gast #2939031
Lesenswert?

Um es nochmal etwas deutlicher zu sagen. Du hast nocht nicht ganz 
verstanden wie SPI funktioniert. Deine Funktion ReadByteSPI sendet ein 
Byte an deinen Sensor und wartet, dass der Controller mit Senden fertig 
ist. Allerdings musst du danach noch ein Byte nachschieben. Dein Sensor 
verhält sich nämlich so wie jeder SPI slave. Die machen NICHTS von 
alleine.
Also: du schickst 0b10001111 an den Sensor. Der weiß jetzt: "Aha, er 
will mein WHO_AM_I Register auslesen" Der Sensor legt dann das 
entsprechende Byte in sein Schieberegister. Allerdings kommt das da von 
alleine nicht raus, der Master muss es rausschieben. Also sendest du 
noch ein Dummybyte hinter. Der Wert dieses Bytes ist EGAL, es dient nur 
dazu die von dir gewollten Daten aus dem Sensor rauszuschieben.
Richtig wäre also:

char ReadByteSPI(char addr)
{
  SPDR = addr;      //Load byte to Data register
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete
 SPDR = addr;      //Load byte to Data register, wir jetzt als Dummybyte 
benutzt!!!!!
  while(!(SPSR & (1<<SPIF)));   // Wait for transmission complete
  addr=SPDR;
  return addr;
}

das sollte funktionieren.
#2958688
Lesenswert?

Holger E. schrieb:
> Hallo Florian,
> ich habe mal hier meine BASCOM-Dateien angehäng.
> ....
>
> Ich hoffe du kannst was damit anfangen auch wenn es nur BASIC ist.
>
> Und für alle anderen MitLeser:
> -> Bitte verzeiht mein schlechten Programmierstil!
>    (Aber es hat funktioniert!!)
>
> Holger

Holger, genau dieses Beisp. für den minIMU-9 mit BASCOM hab ich gesucht!
Es funktioniert wunderbar!
DANKE!!!!!

Gruß
  Hans
Gast #3169586
Lesenswert?

Hi,

ich bin auch grad daran, den L3G4200D auszulesen. Mache das aber über 
I2C...
Hab alles korrekt angeschlossen und die Kommunikation gelingt auch. Also 
Das WhoAmI bekomm ich korrekt zurück.

Wenn ich aber nun die 3 Achsen auslesen möchte, erhalte ich nicht die 
erwarteten Wert zurück.

Hier zunächst mal der Code:
1
//*** IC starten ***
2
    L3G4200D_PowerUP(250);
3

4
//*** Achsen auslesen ***
5
    L3G4200D_GetAxis();
6

7
    //*** Temperatur auslesen ***
8
    L3G4200D_GetTemp();
9

10
//Konfig:
11
short L3G4200D_x, L3G4200D_y, L3G4200D_z;
12
short L3G4200D_Temp;
13

14
void L3G4200D_PowerUP (int scale) {
15
    I2C_WriteToDevice(i2c_fd, L3G4200D_REG_CTRL1, 0b00001111);      //PowerUP, Enable X, Y, Z
16
    I2C_WriteToDevice(i2c_fd, L3G4200D_REG_CTRL2, 0b00000000);      //HPF disable
17
    I2C_WriteToDevice(i2c_fd, L3G4200D_REG_CTRL3, 0b00001000);      //Date Ready
18
    switch (scale) {
19
        case 250:
20
            I2C_WriteToDevice(i2c_fd, L3G4200D_REG_CTRL4, 0b00000000);
21
            break;
22

23
        case 500:
24
            I2C_WriteToDevice(i2c_fd, L3G4200D_REG_CTRL4, 0b00010000);
25
            break;
26

27
        default:
28
            I2C_WriteToDevice(i2c_fd, L3G4200D_REG_CTRL4, 0b00110000);
29
            break;
30
        }
31

32
    I2C_WriteToDevice(i2c_fd, L3G4200D_REG_CTRL5, 0b00000000);
33
    usleep(1500);
34

35
}
36

37
//Daten holen:
38
void L3G4200D_GetAxis (void) {
39
    I2C_ReadFromDevice(i2c_fd, L3G4200D_REG_OUT_X_L, 1, i2c_buffer);
40
    short L3G4200D_x_l = i2c_buffer[0];
41
    //printf("0: %d\n", i2c_buffer[0]);
42

43
    I2C_ReadFromDevice(i2c_fd, L3G4200D_REG_OUT_X_H, 1, i2c_buffer);
44
    short L3G4200D_x_h = i2c_buffer[0];
45
    //printf("0: %d\n", i2c_buffer[0]);
46

47
    I2C_ReadFromDevice(i2c_fd, L3G4200D_REG_OUT_Y_L, 1, i2c_buffer);
48
    short L3G4200D_y_l = i2c_buffer[0];
49
    //printf("0: %d\n", i2c_buffer[0]);
50

51
    I2C_ReadFromDevice(i2c_fd, L3G4200D_REG_OUT_Y_H, 1, i2c_buffer);
52
    short L3G4200D_y_h = i2c_buffer[0];
53
    //printf("0: %d\n", i2c_buffer[0]);
54

55
    I2C_ReadFromDevice(i2c_fd, L3G4200D_REG_OUT_Z_L, 1, i2c_buffer);
56
    short L3G4200D_z_l = i2c_buffer[0];
57
    //printf("0: %d\n", i2c_buffer[0]);
58

59
    I2C_ReadFromDevice(i2c_fd, L3G4200D_REG_OUT_Z_H, 1, i2c_buffer);
60
    short L3G4200D_z_h = i2c_buffer[0];
61
    //printf("0: %d\n", i2c_buffer[0]);
62

63
    L3G4200D_x = (L3G4200D_x_h << 8) | L3G4200D_x_l;
64
    L3G4200D_y = (L3G4200D_y_h << 8) | L3G4200D_y_l;
65
    L3G4200D_z = (L3G4200D_z_h << 8) | L3G4200D_z_l;
66

67
    printf("X: %d\nY: %d\nZ: %d\n", L3G4200D_x, L3G4200D_y, L3G4200D_z);
68
}
69

70
//Temperatur holen
71
void L3G4200D_GetTemp (void) {
72
    I2C_ReadFromDevice(i2c_fd, L3G4200D_REG_OUT_TEMP, 1, i2c_buffer);
73
    L3G4200D_Temp = i2c_buffer[0];
74
    printf("T: %d\n", L3G4200D_Temp);
75
}

Als Ergenis bekomme ich dann:
X: -5
Y: -104
Z: 31
T: 17

X: -25
Y: -101
Z: 63
T: 17

X: 5
Y: -110
Z: 31
T: 17

X: 5
Y: -78
Z: 31
T: 17

X: -37
Y: -141
Z: 15
T: 17

X: -15
Y: -53
Z: 42
T: 17

X: -20
Y: -77
Z: 43
T: 17

X: -14
Y: -82
Z: 41
T: 17

X: 28
Y: -60
Z: 21
T: 16

X: -20
Y: -83
Z: 50
T: 17

X: 10
Y: -95
Z: 31
T: 17

Wie man sieht schwanken die Achsen ziemlich stark, was nicht sein kann, 
da der Sensor nur auf dem Tisch liegt. Die Temperatur ist zwar relativ 
stabil, jedoch viel zu niedrig...

Hat hierzu jemand eine Idee, was das Problem sein könnte?
In der Konfig ein Register vergessen oder ähnliches?
Gast #3170322
Lesenswert?

Hallo nochmal,

wie ich mittlerweile herausgefunden habe ist der Temperatursensor nicht 
für die Umgebungstemperatur, sondern für die IC-Temperatur gedacht.

Die Achsenwerte scheinen doch zu stimmen, da der Gyro die Werte in °/s 
ausgibt. Und wenn der Sensor nur liegt, bleiben die Werte natürlich 
gleich, bis auf die üblichen Schwankungen.

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