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; }
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.
Da Du keine Interrupt-Routine verwendest, musst Du vor einem neuen Befehl das Interrupt-Register selbst zurücksetzen, sonst überrennst Du den I2C im AVR, da Deine Warteschleifen sofort zurückkehren.
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.
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.
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.
Danke S. Landolt für den Hinweis, das schaue ich mir gleich nochmal genauer an.
Kai danke für deine Antwort, allerdings glaube würde das nicht die unklaren Werte erklären, welche ich bekomme oder?
Hallo Wolfgang, bei dieser Operation wir ein Bit in das LSB der 8-Bit Variable addresse geschrieben. Aus 0b11010000 wird 0b11010001. Hoffe, dass erklärt die kleine Unklarheit ;)
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
> 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 |
S. Landolt schrieb: > aber der Kommentar ist falsch So isses. Falls es immer noch nicht funktioniert, empfehle ich Peter Fleurys Lib für I²C. Damit hatte ich bis jetzt immer Erfolg: http://www.peterfleury.epizy.com/avr-software.html
Danke für den Vorschlag,aber ich würde gerne wissen, warum MEIN Code nicht wie gewollt funktioniert.
Michael A. schrieb: > Danke für den Vorschlag,aber ich würde gerne wissen, warum MEIN Code > nicht wie gewollt funktioniert. Dann guck dir mit dem LA an, an welcher Stelle nicht das erwartete Signal auf dem Bus liegt.
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.
:
Bearbeitet durch User
Hallo Matthias, bin grundsätzlich ein neugieriger Mensch, der wissen möchte, warum etwas so ist, wie es ist. Programmiere später auch in Assemler, weshalb das richtige Verständnis der Dinge spätestens dann sehr wichtig ist..Danke für den Hinweis mit dem Status Register;)
> ... Hinweis mit dem Status Register ...
Pardon, aber so weit waren wir schon vor anderthalb Tagen.
Hallo zusammen, konnte das Problem lösen und somit passt das mitlerweile. Danke für die Hilfe
Michael A. schrieb: > Danke für die Hilfe Es wäre sicher mal sinnvoll, die Lösung zu posten - kann ja sein, das du nicht der einzige bist.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.