Hallo zusammen,
mit dem TWI-Bus möchte ich Daten aus einem Beschleunigungssensor
Auslesen.
jedoch stoße ich auf folgendes Problem: der Master lästen den Sensor
nach Übertragung der Slaveaddresse und Übertragung des Registers den
Slave nicht mehr antworten sondern Sendet sofort die Stoppbedingung.
Wenn ich jedoch diese aus meinem Code Rauslösche überträgt der Slave
noch das erste Byte bis es dazukommt das der Master eig. das ACK senden
müsste(kann er ja auch nicht).
Ich hänge von beiden Szenarien noch Bilder meines Oszilloskope dran.
meine Vermutung ist das der Master nicht erkennt das er Daten empfangen
soll und deshalb direkt die Stoppbedingung Sendet.
Die soll Übertragung ist laut Datenblatt des Sensors;
Start,Adresse/WRITE,Register,Stopp,Start;Adresse/READ, 6 Byte
Datenübertragung, Stopp
Auf den Bildern sind die Stoppbedingung zu Sehen und dann die
Adressübertragung, im bild ohne der stoppbedingung ist noch das erste
bayt der datenübertragung zu sehen“ 0x01“.
der Code Bezieht sich auf die Artikel
http://elk.informatik.fh-augsburg.de/da/da-21/Tutorial/tutorial.html
2.13 TWI
und
http://www.mikrocontroller.net/articles/AVR_TWI
ich würde mich sehr freuen wenn ihr mir helfen könnt den Fehler zu
finden
grüße
Sebastian
Basti schrieb:> meine Vermutung ist das der Master nicht erkennt das er Daten empfangen> soll
Das musst du ja auch selber Programmieren, das "weiß" der Master nicht
von sich aus. Nach einem Stop ist auf dem Bus die Kommunikation beendet,
da macht der Slave nichts mehr.
Neben Start und Stop gibt es daher auch noch repeat_start usw., mit
denen sich eine Kommunkation mit mehr als einem Byte aufbauen lässt.
Alle Infos gibts dazu, wie immer, per google im Netz.
Hilfreich ist auch die i2c-lib vonm Peter Fleury.
Oliver
mein problem ist ja nicht das der slave nicht weiß das er was senden
soll, das macht er ja auch(wen ich die stopp weglasse)
ich zitiere aus aus meiner erstequelle:
wert= TWDR;
Der Master sendet ein ACK zum Slave. Das TWINT-Bit wird wieder von der
Hardware gesetzt, es findet die Überprüfung statt, ob der Slave Daten
geschickt hat, TWINT wird in der Software gelöscht und der Master kann
das nächste Datenpaket aus dem TWDR-Register lesen. Dies wird solange
wiederholt, bis der Master das letzte Datenpaket empfangen hat. Dessen
Eingang muss er dann durch ein NACK (Not Acknowledged) bestätigen.
Danach sendet der Master die Stopbedingung und der Datenaustausch wird
beendet.
TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
ich verstehe das so das das alles in der TWI.h Bibliothek definiret ist
das mit der Kombi start stopp das der master weiß das es sich um eine
Master Receiver handelt?!
Basti schrieb:> Start,Adresse/WRITE,Register,Stopp,Start;Adresse/READ, 6 Byte> Datenübertragung, Stopp
Dann solltest Du es genau so programmieren.
Ich sehe in Deinem Programm aber nirgends eine Zählschleife bis 6, die
die Bytes einliest.
CPUs haben die komische Eigenschaft, genau das zu tun, was man
hinschreibt. Sie lesen nicht Deine Gedanken.
Peter
Basti schrieb:> wenn das Problem das wäre das der Controler nicht bis 6 zählen muss,> müste er ja nach meinem code wenigsten das erste byte Empfangen?
Nö.
Warum sollte er.
In dem Moment, in dem der Master den Stop generiert, ist die Sache mit
der Datenübertragung für den Slave Schnee von gestern.
Und genau das macht dein Code
Start generieren
Slave Adressieren
Stop generieren
Wie soll denn da der Slave jemals seine Daten loswerden?
1
....
2
while(!(TWCR&(1<<TWINT)));
3
TWDR=(0x02<<1)|TW_WRITE;
4
// ACK und Stop senden
5
TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
6
7
//somit sollte der Slave wissen auf welches Register ich zugreifen Will.
8
_delay_us(150);
Nö. Den Slave interessiert das alles nicht mehr. Dadurch dass du
1<<TWSTO gemacht hast, hast du die Kommunikation als beendet erklärt.
Hol dir die Fleury Lib.
okay das ist einleuchtend.
ich habe es jetzt mit der schleife versucht
for (i=0;0<5;i++)
int i;
for (i=0;0<5;i++)
{//wert auslesen
wert = TWDR;
//ACK senden
TWCR = (1<<TWINT) | (1<<TWEN);
}
TWCR = (1<<TWINT) | (1<<TWEN)|(1<<TWSTO);
}
der code Folgt direkt nach der 2 Übertragung der Slaveaddresse
ich weiß das der Slave mich verstanden hat, weil ich ja das erste byte
als Antwort kriege wenn ich die stopp weglasse.
mit dem neuen code erhalte ich jetzt eine antwort aber der master
schreibt das ack bit nicht
ich habe es mit verschiedenen Versionen aus dem Internet versucht:
TWCR = (1<<TWINT) | (1<<TWEN)|(1<<TWSTO);
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA)|(1<<TWIE);
TWCR =
(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)
;
jedoch wurde bei keiner dieser Codeschnippel ein ack gesendet.
Basti schrieb:> okay das ist einleuchtend.> ich habe es jetzt mit der schleife versucht> for (i=0;0<5;i++)>>> int i;> for (i=0;0<5;i++)> {//wert auslesen> wert = TWDR;> //ACK senden> TWCR = (1<<TWINT) | (1<<TWEN);> }
und wer wartet darauf, dass das eine Byte dann auch draussen ist, ehe es
weitergeht?
Ich kann mich nur wiederholen.
Hol dir die Fleury Lib.
Und sei es nur um zu studieren, wie er das gemacht hat.
> ich habe es mit verschiedenen Versionen aus dem Internet versucht:
Einfach irgndwelche Codeschnipsel (im konkreten Bits setzen) aus 'dem
Internet' zu verwenden ohne sie zu verstehen bzw., zu wissen warum und
wieso gerade diese Bits, ist sinnlos. So lernst du nix.
Wenn du dir was aus 'dem Internet' holst, dann hol dir eine fertige Lib,
stell sicher dass sie funktioniert und dann STUDIER den Code! So lernst
du. Die Zeiten, wo du nur die Bitnamen brauchtest und die dir irgendwie
zusammengesucht hast, sind offenbar vorbei. Jetzt geht es immer mehr um
Konzepte, die sich in ganzen Codesequenzen niederschlagen; in Abläufen.
Die kann man nicht mehr verstehen, indem man einfach irgendwelche Bits
setzt und die solange durchiteriert, bis es klappt.
hier der code der in der Fleury Lib. verwendet wird.
/***********************************************************************
**
Read one byte from the I2C device, request more data from device
Return: byte read from I2C device
************************************************************************
*/
unsigned char i2c_readAck(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
return TWDR;
}/* i2c_readAck */
und mein code:
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
TWDR = wert;
das Ergebis was mein Oszilloskop ausgibt ist das gleiche :das ACK wird
nicht gesendet!
der unterschied ist das das eine veröffentlichte Bibliothek ist und das
2 von mir geschrieben wurde.
damit soll der bus ausgelesen werden.
das ack soll von gesetzt werden wenn der master alles empfangen hatt und
das sollte er selbstständig machen wenn das byte versendet wurde!
und das wird doch hier gesagt:
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
oder irre ich mich?
ich wollte darauf hinaus, dass:
>> return TWDR;
hier TWDR gelesen wird und hier
>> TWDR = wert;
TWDR gesetzt wird.
Damit ist Dein Code schon mal signifikant anders als der
veröffentlichte.
natürlich ist er vom äußeren anders.
aber inhaltlich ist er mit dem was das auslesen identisch.
und ein ack wird mit der Fleury Lib auch nicht gesendet.
ich habe jetzt den Code so umgeschrieben das das der slave die 6byts
senden kann.
der Master sendet zwar immer noch keine ACKs aber ich kriege jetzt alles
zugesendet.
eine frage habe ich jetzt jedoch
{_delay_us(50);
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
}
das ist die Routine die 6mal wiederholt wird. muss ich in der Routine
jeweils eine Variable mit twdr Beschreiben oder kann ich auch den
gesamten
TWDR in einem Schwung am ende Raus holen ?
vielen dank schon mal
Basti schrieb:> muss ich in der Routine> jeweils eine Variable mit twdr Beschreiben oder kann ich auch den> gesamten> TWDR in einem Schwung am ende Raus holen ?
Warum hast Du so große Angst vor Datenblättern?
Oder steht darin irgendwo, daß TWDR 48 Bit groß ist?
Du solltest Dir wirklich erstmal die Beschreibung des I2C durchlesen.
Peter