Forum: Mikrocontroller und Digitale Elektronik ADXL auslesen


von Theo W. (antheo)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich arbeite mich gerade in C ein und bin am I2C mit einem ATMega128P 
dran. Hier würde ich gern den Beschleunigungssensor ADXL345 via I2C 
anbinden.
Das Grundgerüst vom I2C steht auch bereits. Chip konfigurieren klappt 
auch aber es hadert beim auslesen der Werte.
Ich vermute, ich setze irgendein Leseregister nicht bzw. nutze die 
falsche Leseadresse. Könnte sich das mal jemand ansehen?
1
#define _DVK501_M128_EX_ 1
2
#define F_CPU 8000000UL
3
#include <avr/io.h>
4
#include "ws_lcd_ST7920_port.h"
5
#include <util/delay.h>
6
#define BAUD 9600
7
#include <util/setbaud.h>
8
#include "twi_config.h"
9
10
11
/*=========================================================================
12
    ADXL
13
    -----------------------------------------------------------------------*/
14
  #define ADXL_ADDRESS    0x53 << 1  //ADXL Adresse
15
    #define ADXL_DEVID      0x00    // Device ID
16
  #define ADXL_DATA_FORMAT  0x31  // Auflösung
17
  #define ADXL_BW_RATE    0x2c  // Bandbreite
18
  #define ADXL_POWER_CTL    0x2d  // Power Control
19
  #define ADXL_ACC_Data    0x32  // Erstes ACCL Register
20
21
typedef enum
22
{
23
  ADXL_Enable_Measure      = 0x08,    // Messung einschalten  
24
  ADXL_sleep          = 0x04,    // Sleep Modus    
25
  ADXL_DATARATE_100_HZ    = 0b1010,  //   50Hz 
26
  ADXL_DATARATE_50_HZ      = 0b1001,  //   25Hz 
27
  ADXL_DATARATE_25_HZ      = 0b1000,  // 12.5Hz 
28
  ADXL_DATARATE_12_5_HZ    = 0b0111,  // 6.25Hz 
29
  ADXL_RANGE_16_G        = 0b11    // +/- 16g
30
} defs;
31
32
//Variablen
33
34
unsigned char adxlvalue[];
35
int i;
36
37
void ADXL_Init(void)
38
{
39
  i2c_init();
40
  
41
  //Auflösung setzen
42
  i2c_start();
43
  i2c_write(ADXL_ADDRESS);
44
  i2c_write(ADXL_DATA_FORMAT);
45
  i2c_write(ADXL_RANGE_16_G);
46
  i2c_stop();
47
48
  //Bandbreite setzen
49
  i2c_start();
50
  i2c_write(ADXL_ADDRESS);
51
  i2c_write(ADXL_BW_RATE);
52
  i2c_write(ADXL_DATARATE_12_5_HZ);
53
  i2c_stop();
54
  
55
  // Messung starten
56
  i2c_start();
57
  i2c_write(ADXL_ADDRESS);
58
  i2c_write(ADXL_POWER_CTL);
59
  i2c_write(ADXL_Enable_Measure);
60
  //i2c_write(ADXL_sleep);
61
  i2c_stop();  
62
63
}
64
65
int main(void)
66
{
67
    ADXL_Init();
68
    uart_init();
69
    while (1) {
70
        i2c_start();
71
        i2c_write(ADXL_ADDRESS);
72
        i2c_write(ADXL_ACC_Data);
73
        i2c_stop();
74
        i2c_start();
75
        i2c_write(ADXL_ADDRESS);
76
77
        for(i=0; i<5; i++) {
78
          i2c_read(adxlvalue[i]);
79
        }
80
        i2c_stop();
81
          
82
        for (i = 0; i < 5; i++)
83
        {
84
          if (i > 0) uart_puts(":");
85
          uart_puts(" ", adxlvalue[i]);
86
        }
87
        uart_puts("\r\n");
88
89
      _delay_ms(2000);
90
    }
91
92
}

Die UART Routinen hab ich jetzt mla weggelassen, die TWI Config Datei 
angehangen.

EDIT: Habe es auch hiermit probiert:
1
adxlvalue[i]=i2c_read(1);
lg
Theo

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Theo W. schrieb:
> Chip konfigurieren klappt auch aber es hadert beim auslesen der Werte.
Was erwartest du und was bekommst du stattdessen?

von Theo W. (antheo)


Lesenswert?

zurück kommt nichts. Das Array wird nicht befüllt. Erwarten würde ich 6 
Integer werte jeweils 8 Bit H/L. Aber soweit bin ich jetzt noch garnicht 
gewesen. Ich wollte quasi nur erstmal die Register auslesen.

lg
Theo

von Theo W. (antheo)


Lesenswert?

Ich habe jetzt nochmla was am Code geändert. Write und Read Adresse 
müssten jetzt stimmen. Leider kommt immernoch nichts zurück.

Was auch sehr seltsam ist: Im Terminal bekomme ich alle 2 Sekunden den 
"Init". Das dürfte ja eigentlich garnicht passieren, da er die while 
Schleife ja garnciht verlassen dürfte und das "Init" ja davor steht.
1
/*=========================================================================
2
    ADXL
3
    -----------------------------------------------------------------------*/
4
  #define ADXL_ADDRESSW    0xA6  //ADXL Adresse Schreiben
5
  #define ADXL_ADDRESSR    0xA7  //ADXL Adresse Lesen
6
    #define ADXL_DEVID      0x00    // Device ID
7
  #define ADXL_DATA_FORMAT  0x31  // Auflösung
8
  #define ADXL_BW_RATE    0x2c  // Bandbreite
9
  #define ADXL_POWER_CTL    0x2d  // Power Control
10
  #define ADXL_ACC_Data    0x32  // Erstes ACCL Register
11
12
typedef enum
13
{
14
  ADXL_Enable_Measure      = 0x08,    // Messung einschalten  
15
  ADXL_sleep          = 0x04,    // Sleep Modus    
16
  ADXL_DATARATE_100_HZ    = 0b1010,  //   50Hz 
17
  ADXL_DATARATE_50_HZ      = 0b1001,  //   25Hz 
18
  ADXL_DATARATE_25_HZ      = 0b1000,  // 12.5Hz 
19
  ADXL_DATARATE_12_5_HZ    = 0b0111,  // 6.25Hz 
20
  ADXL_RANGE_16_G        = 0b11    // +/- 16g
21
} defs;
22
23
//Variablen
24
25
int8_t adxlvalue[5];
26
int16_t x;
27
int16_t y;
28
int16_t z;
29
int i;
30
31
32
void ADXL_Init(void)
33
{
34
  i2c_init();
35
  
36
  //Auflösung setzen
37
  i2c_start();
38
  i2c_write(ADXL_ADDRESSW);
39
  i2c_write(ADXL_DATA_FORMAT);
40
  i2c_write(ADXL_RANGE_16_G);
41
  i2c_stop();
42
43
  //Bandbreite setzen
44
  i2c_start();
45
  i2c_write(ADXL_ADDRESSW);
46
  i2c_write(ADXL_BW_RATE);
47
  i2c_write(ADXL_DATARATE_12_5_HZ);
48
  i2c_stop();
49
  
50
  // Messung starten
51
  i2c_start();
52
  i2c_write(ADXL_ADDRESSW);
53
  i2c_write(ADXL_POWER_CTL);
54
  i2c_write(ADXL_Enable_Measure);
55
  //i2c_write(ADXL_sleep);
56
  i2c_stop();  
57
58
}
59
60
int main(void)
61
{
62
    ADXL_Init();
63
    uart_init();
64
    uart_puts("Init");
65
    while (1) {
66
        i2c_start();
67
        i2c_write(ADXL_ADDRESSW);
68
        i2c_write(ADXL_ACC_Data);
69
        i2c_stop();  
70
        i2c_start();
71
        i2c_write(ADXL_ADDRESSR);
72
73
  adxlvalue[0]=i2c_read(1);
74
  adxlvalue[1]=i2c_read(1);
75
  adxlvalue[2]=i2c_read(1);
76
  adxlvalue[3]=i2c_read(1);
77
  adxlvalue[4]=i2c_read(1);
78
  adxlvalue[5]=i2c_read(0);
79
        i2c_stop();
80
        x = (int16_t)((((int)adxlvalue[1]) << 8) | adxlvalue[0]);
81
        y = (int16_t)((((int)adxlvalue[3]) << 8) | adxlvalue[2]);
82
        z = (int16_t)((((int)adxlvalue[5]) << 8) | adxlvalue[4]);
83
84
        uart_puts("X=", (char) x);
85
        uart_puts(" Y=", (char) y);
86
        uart_puts(" Z=", (char) z);    
87
        uart_puts("\r\n");
88
89
      _delay_ms(2000);
90
    }
91
92
}

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

Theo W. schrieb:
> zurück kommt nichts.

Was genau passiert auf dem Bus? Bekommt der ATMega ein Ack vom Sensor 
oder ist der vielleicht noch beschäftigt?

von Achim S. (Gast)


Lesenswert?

Theo W. schrieb:
> Leider kommt immernoch nichts zurück.

Was heißt "es kommt nichts zurück"? Bleibt die Funktion i2cread hängen? 
Liefert sie den Wert 0 zurück?

Ansonsten folgende Fragen:
Ist der ADXL überhaupt für I2C konfiguriert? (Andernfalls macht er SPI)?
Hast du dir den Ablauf auf dem Bus für ein Register-Read schon mal 
angeschaut (Fig. 41 in 
http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf)?

Für ein single Byte Read brauchst du:
- eine Startcon
- ein Write mit der Deviceadresse
- ein Write mit der gewünschten Registeradresse
- eine neue Startcon
- ein Read mit der Registeradresse
- acht weitere SCL-Flanken zum Einlesen der Read-Daten
- eine Stopcon

Läuft das tatsächlich alles nacheinander ab, wenn du einfach 
adxlvalue[0]=i2c_read(1); in deinen Code schreibst?

Hier ein Link zu einer Application-Note samt Beispielcode zur Nutzung 
des TWI
http://www.microchip.com//wwwAppNotes/AppNotes.aspx?appnote=en591794

von Theo W. (antheo)


Lesenswert?

Hallo zusammen,

also von vorn:

Der ADXL ist für I2C konfiguriert.
Wie oben geschrieben, läuft die Konfiguartion sauber durch und bleibt 
auch nicht hängen. Feststellen lässt sich das leicht am Stromverbrauch. 
Setze ich das Powerregister auf Sleep habe ich 30uA, beim´der normalen 
Konfig gut 100uA. Ebenso beim verändern von Abtastraten.
Der I2C Bus läuft also.

 @Achim

Ich habe oben meinen Code gepostet. Dort ist folgendes zu sehen:
1
  i2c_start();
2
  i2c_write(ADXL_ADDRESSW);
3
  i2c_write(ADXL_ACC_Data);
4
  i2c_stop();  
5
  i2c_start();
6
  i2c_write(ADXL_ADDRESSR);
7
  adxlvalue[0]=i2c_read(1);
8
  adxlvalue[1]=i2c_read(1);
9
  adxlvalue[2]=i2c_read(1);
10
  adxlvalue[3]=i2c_read(1);
11
  adxlvalue[4]=i2c_read(1);
12
  adxlvalue[5]=i2c_read(0);
13
  i2c_stop();

Das entspricht exakt deiner angegebenen Reihenfolge.

Kleine Unklarheit: Muss ich nach der zweiten Startcon die Leseadresse 
Lesen oder Schreiben? Aktuell Schreibe ich das Leseregister auf den Bus 
und gehe dann in i2c_Read.

Und wie sollte das nicht direkt nacheinander ablaufen?

Vielleicht hat jemand die Muße die i2C_read Funktion mal kurz anzusehen? 
(Angehangen an den ersten Post)

Ich habe leider kein Oszi hier um direkt auf den Bus zu gucken.

Mit "zurück kommt nichts" meine ich, dass die Read Funktion keine Werte 
zurückgibt, die Funktion an sich aber durchläuft. Da der Code auf ein 
Ack wartet wenn ich das richtig interpretiert habe, muss ja auch 
eigeltich was passieren.

Darüber hinaus: Hat jemand beim Code eine Idee wie es sein kann, dass 
der aus der While Schleife rausspringt und das "Init" erneut macht?

lg
Theo

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

> Der I2C Bus läuft also.

Okay, auch wenn es eher nach einem Softwareproblem aussieht, trotzdem: 
wie groß bzw. klein sind die Pull-ups?

von Wolfgang (Gast)


Lesenswert?

Theo W. schrieb:
> Ich habe leider kein Oszi hier um direkt auf den Bus zu gucken.

Dann habe ich einen Vorschlag für dich:
Nutze die Zeit, wo du hier auf Antwort wartest, und bestelle dir über 
eBay o.ä. einen kleinen Logikanalysator. Kostet dich keine 7€ und hilft 
beim nächsten Mal ungemein.
Suchbegriff z.B. "USB Logic Analyzer 8CH 24MHz"

von Wolfgang (Gast)


Lesenswert?

Theo W. schrieb:
> Darüber hinaus: Hat jemand beim Code eine Idee wie es sein kann, dass
> der aus der While Schleife rausspringt und das "Init" erneut macht?

Läuft vielleicht dein Watchdog Timer?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Theo W. schrieb:
> Im Terminal bekomme ich alle 2 Sekunden den "Init". Das dürfte ja
> eigentlich garnicht passieren, da er die while Schleife ja garnciht
> verlassen dürfte und das "Init" ja davor steht.
Ja, sieht nach Watchdog aus...

von Theo W. (antheo)


Lesenswert?

Hallo zusammen,

also als erstes: Ich wusste garnicht, dass es Logik Analyzer für ein 
Paar Euros gibt....sofort bestellt.

Zu allem anderen:

Ich habe festgestellt, dass sobald ich eine bestimmte Uart Zeile 
auskommentiere ich nicht mehr aus der While Schleife springe.

Daraufhin, habe ich die gesamten Uart Funktionen in eine separate header 
Datei ausgelagert. Und schon gibt der Compiler Fehler aus. Hauptsächlich 
lag es daran, dass das I2C lief, aber die Ausgabe nicht.

Da ich von Basic (Bascom) komme kann man alles in einen Print Befehl 
schmeißen. Hier muss sauber konvertiert werden (itoa). Wieder was 
gelernt.

Dennoch vielen Dank an alle und ein schönes Wochenende.

-----Closed------

: Bearbeitet durch User
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.