MPU6050 mit Mikrocontroller TWI

OP #6236791
Lesenswert?

Hallo Community,

bin neu hier und habe gleich mal eine Frage. Ich versuche über TWI eine
Verbindung zwischen meinen uC (ATmega8) und meinen MPU6050 herzustellen.
Ich versuche die Daten aus einem der vielen Register zu lesen, doch das
funktioniert leider nicht wie gewollt. Es wird nur einmal ein Wert
zurückgegeben und der ist 0. Habe herausgefunden, dass er beim erneuten
Auslesen in der Funktion "twi_start()" hängen bleibt. Vielleicht könnt
ihr mir hier weiterhelfen. Mir wurde gesagt, dass hier viele Leute sind
die sich sehr gut mit den AVRs auskennen. Hoffe ihr könnt mir helfen.
Die Daten gebe ich übrigens über die UART Schnittstelle am Computer aus,
die funktioniert einwandfrei ;)

#include <avr/io.h>
#include <avr/delay.h>
#include "uart.h"
#define MPU6050_ADDRESS 0b11010000
#define REG 0x46
unsigned char twi_read_byte(void);
unsigned char twi_read(uint16_t address);
void twi_write_byte(uint16_t byte);
void twi_write(uint16_t address, unsigned char data);
void iniz_twi(void);
void twi_start(void);
void twi_stopp(void);

void iniz_twi(void)
{
    TWBR = 10;
    TWSR = 1;
}
void twi_start(void)
{
    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
    while(!(TWCR & (1 << TWINT)));
}
void twi_stopp(void)
{
    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}
unsigned char twi_read(uint16_t address)
{
    unsigned char data;
    unsigned char _register;

    twi_start();
    twi_write_byte(address);
    twi_write_byte(REG);

    address |= (1 << 0); //LSB auf write setzen

    twi_start();
    twi_write_byte(address);
    TWCR = (1 << TWINT) | (1 << TWEN);
    while(!(TWCR & (1 << TWINT)));
    data = twi_read_byte();
    twi_stopp();

    return data;
}
unsigned char twi_read_byte(void)
{
    unsigned char data;
    data = TWDR;
    TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN);
    while(!(TWCR & (1 << TWINT)));
    return data;
}
void twi_write(uint16_t address, unsigned char data)
{
    twi_start();
    twi_write_byte(address);
    twi_write_byte(REG);
    twi_write_byte(data);
    twi_stopp();
}
void twi_write_byte(uint16_t byte)
{
    TWDR = byte;
    TWCR = (1 << TWINT) | (1 << TWEN);
    while(!(TWCR & (1 << TWINT)));
}
int main(void)
{
    unsigned char _str[255] = "";
    char value;
    uart_iniz();
    iniz_twi();
    while(1)
    {
        value = twi_read(MPU6050_ADDRESS);
        itoa(value, _str, 10);
        write_string(_str); //Uart
        _delay_ms(200);
    }
    return 0;
}
Gast #6236864
Lesenswert?

Auch mit geänderter Betreffreihenfolge ist mir, als I²C-Laien, seit 
gestern nicht viel eingefallen. Außer, dass ich mir die Status- bzw. 
Errorcodes in TWSR anschauen würde. Und dass das Programm im start 
hängenbleibt, ist merkwürdig, als würde der Slave den Bus nicht 
freigeben.
(Firma: matzetronics) #6237133
Lesenswert?

Wolfgang schrieb:
> Michael A. schrieb:
>> address |= (1 << 0); //LSB auf write setzen
> Was soll das eigentlich für ein Konstrukt sein. Eine 0-malige
> Verschiebung eines Bitmusters ist relativ wirkungslos.

Das kann man schon machen, aber es ist genau verkehrt herum im Programm. 
Ein gesetztes Bit ist eine I²C Read Adresse und ein gelöschtes Bit ist 
eine I²C Write Adresse.
Wenn der MPU6050 also die Grundadresse 0xD0 hat, ist diese die Write 
Adresse und 0xD1 die zum Lesen.
Gast #6237282
Lesenswert?

Wie schon gesagt, ich bin Laie. Frage mich aber, weshalb in 
twi_read_byte nach dem 'Single-Byte Read' (data=TWDR) ein weiterer 
Transfer, diesmal mit ACK, gestartet wird - ich hätte gedacht, da käme 
nur noch ein stop.
OP #6237619
Lesenswert?

Hallo Matthias, könntest du mir genau sagen, wo mein Fehler liegt 
(möglicherweise habe ich etwas vertauscht :) ), denn so weit ich mein 
Programm beurteilen kann, ist die Addresse zunächst auf write (11010000) 
und wird anschließend auf read (11010001) gesetzt.
Freue mich auf deine Antwort ;)

PS. Ich habe im Anhang ein Bild der Single Byte Read Sequence angehängt
Angehängte Dateien:
Gast #6237730
Lesenswert?

> Hallo Matthias, könntest du mir genau sagen, wo mein Fehler liegt

In Vertretung von Matthias S.: das Programm ist an dieser Stelle 
richtig, aber der Kommentar ist falsch:
1
    address |= (1 << 0); //LSB auf write setzen
(Firma: matzetronics) #6238712
Lesenswert?

Michael A. schrieb:
> warum MEIN Code
> nicht wie gewollt funktioniert.

Z.B. ignorierst du völlig das Status Register, das dir schon mal sagen 
könnte, ob da irgendwelchen grundlegenden Komm. Probleme sind.
Hier mal auszugsweise aus der o.a. Lib:
1
// nach der Startcondition
2
  twst = TW_STATUS & 0xF8;
3
  if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
4
// nach dem Senden eines Bytes
5
  twst = TW_STATUS & 0xF8;
6
  if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
Warum man das Rad allerdings neu erfinden will, ist mir nicht klar.
OP #6241310
Lesenswert?

Naja es gab Probleme beim wiederstarten der TWI, weshalb ich diesmal 
einfach die Stopbedingung weggelassen habe und nur mit Restarts arbeite, 
also ganz gelöst ist es nicht und ist auch nicht sehr professionell, 
aber ein Schritt in die richtige Richtung, werde in den nächsten Tagen 
versuchen auch mit der Stop-Bedingung zu arbeiten ;) . Wenn man aber nur 
EINMAL diesen Code ausführt
    twi_start();
    twi_write_byte(address);
    twi_write_byte(REG);
und man anschließend den folgenden Code in einer Schleife ausführt 
bekommt man eine Reihe von brauchbaren Werten zurück. ACHTUNG: Keine 
Stop-Bedingung schicken, da es (aus noch ungeklärten Gründen) ein 
Problem beim Starten des TWI nach einer Stop-Bedingung gibt.
    address |= (1 << 0);
    twi_start();
    twi_write_byte(address);
    TWCR = (1 << TWINT) | (1 << TWEN);
    while(!(TWCR & (1 << TWINT)));
    data = twi_read_byte();


z.B.

void main(void)
{
    twi_iniz();
    twi_start();
    twi_write_byte(MPU6050_ADDRESS);
    twi_write_byte(REG);
    address |= (1 << 0);
    while(1)
    {
      twi_start();
      twi_write_byte(address);
      TWCR = (1 << TWINT) | (1 << TWEN);
      while(!(TWCR & (1 << TWINT)));
      data = twi_read_byte();
    }
}
Man erkennt, dass ich keine Stopbedingung verwende, sondern immer wieder 
mit dem Restart arbeite. Habe jeden einzelnen TWI-Befehl mittels 
TWSR-Register überprüft, bin aber zu keinem Ergebnis gekommen.

Noch etwas ist wichtig zu wissen. Die ersten paar Werte des MPU6050 sind 
immer "0", anschließend gibt er brauchbare Werte aus. Daher, dass ich 
anfangs nur einen Wert zurückbekam ("0"), kam mir das sehr seltsam vor 
und ich nahm an, dass dies ein Fehler ist. Jetzt bin ich aber beruhigt 
und kann sagen, dass dies kein Fehler ist.

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