Hey Ich bin seit einer Woche dran, einen TWI Bus zwischen 2 ATMega8 zu programmieren (in C mit Code::Blocks). Und ich verzweifle fast. Das Prinzip habe ich verstanden. Aber es geht nicht. Es kommt nicht mal ein Takt auf dem SCL an. Ich habe externe Pull up Widerstände von 2,2 kOhm. An meinem PortB habe ich 8 LEDs angeschlossen um den Status des TWI anzuzeigen. Nun sehe ich, dass der Master 0xF8 und der Slave 0x00 im TWSR hat. Was hat das zu bedeuten? Meine Programme habe ich angehängt! Bitte helft mir! Ich bin verzweifelt!
Die Fehler sind lt. TWI.h: /* no state information available */ #define TW_NO_INFO 0xF8 /* illegal start or stop condition */ #define TW_BUS_ERROR 0x00 Ausserdem glaub ich mal, dass _delay_ms(1000); in der Start-Funktion nix zu suchen hat. Der Timeout der TWI-Hardware beisst da zu, noch bevor delay überhaupt in den 2-Stelligen ms-Bereich kommt. Raus damit. Das Senden von Start-Kondition, Slave-ID, Daten, Stop-Kondition sollte möglichst in einer Funktion OHNE delays erfolgen.
Ok. Ich hab die delay Funktion rausgeschmissen. Und siehe da, es funktioniert! aber leider nur teilweise! Beim Senden das DATA Bytes bricht es ab und bekommt als Status die 0x58 . Das bedeutet laut datenblatt:Databyte has been received, ACK has been returned d.h. ich habe den Master nicht im "sende"modus sondern im "empfangs"modus! Muss ich beim Senden der Slaveadresse das R/W Byte 0 oder 1 machen damit ich daten schicken kann?
Dass er abbricht, ist sozusagen normal. 0x58 heisst, dass vom Slave ein NACK zurückgekommen ist, d.h. der Slave will keine weiteren Daten mehr. Wenn er mehr will, muss mit ACK geantwortet werden. R/W-Byte: Zum Senden Master=>Slave: 0, fürs Auslesen eines Slaves: 1.
ok..also ich habe jetzt mal beim Master das Datenbyte einfach hochzählen lassen nach jedem senden und dann beim Slave das Datenbyte auf den PORTB gelegt. Es ändert sich nichts. Es wird immer nur der Startwert (0) des Datenbytes angezeigt. D.h. der Slave empfängt noch keine Daten. Ich verstehen das nicht. Die Adresse wird richtig übermittelt aber er erkennt dann nicht das Datenbyte! So ein S....!!! Habt ihr vielleicht noch eine Idee für mich! Ich hänge noch mal den überarbeiteten Quelltext an. Danke schon mal für eure schnelle Hilfe!
Flo S. schrieb:
> Ich hänge noch mal den überarbeiteten Quelltext an.
Als ich das hier:
1 | if(help==0x60) TWSI_TW_SR_SLA_ACK(); //x60 |
2 | if(help==0x68) TWSI_TW_SR_ARB_LOST_SLA_ACK(); //x68 |
3 | if(help==0x70) TWSI_TW_SR_GCALL_ACK() ; //x70 |
4 | if(help==0x78) TWSI_TW_SR_ARB_LOST_GCALL_ACK(); //x78 |
5 | if(help==0x80) Data=TWSI_TW_SR_DATA_ACK(); //x80 |
6 | if(help==0x88) Data=TWSI_TW_SR_DATA_NACK (); //x88 |
7 | if(help==0x90) TWSI_TW_SR_GCALL_DATA_ACK(); //x90 |
8 | if(help==0x98) TWSI_TW_SR_GCALL_DATA_NACK(); //x98 |
9 | if(help==0xA0) TWSI_TW_SR_STOP(); //xA0 |
10 | if((help!=0x60)|(help!=0x68)|(help!=0x70)|(help!=0x78)|(help!=0x80)|(help!=0x88)|(help!=0x90)|(help!=0x98)|(help!=0xA0)) error(); |
in slave.c ziemlich weit oben sah, habe ich aufgehört, weiterzulesen. Nehmen wir mal an, dass help == 0x60 ist, dann: 1. ... muss der arme µC trotzdem noch weitere 9 if-Statements durchchecken, weil Du das "else" vor allen weiteren ifs vergessen hast. Optimal wäre übrigens ein case-switch. 2. ... dann ist die Bedingung "(help != 0x68)" TRUE und es wird nach error() gesprungen. Übrigens wird - egal, welcher Wert help tatsächlich hat, immer nach error() gesprungen! Denn mindestens 8 Deiner 9 Bedingungen, die Du mit dem Operator "|" verknüpfst, sind immer gegeben! Bedingungen verknüpfen macht man nicht mit "|" oder "&", sondern mit "||" bzw. "&&". Lerne bitte die Unterschiede zwischen logischen und bitweisen Operatoren. Du hättest hier "&&" statt "|" nehmen müssen. Aber das letzte if-Statement ist sowieso für die Tonne, denn bei "else" braucht man das nicht:
1 | if(help==0x60) TWSI_TW_SR_SLA_ACK(); //x60 |
2 | else if(help==0x68) TWSI_TW_SR_ARB_LOST_SLA_ACK(); //x68 |
3 | else if(help==0x70) TWSI_TW_SR_GCALL_ACK() ; //x70 |
4 | else if(help==0x78) TWSI_TW_SR_ARB_LOST_GCALL_ACK(); //x78 |
5 | else if(help==0x80) Data=TWSI_TW_SR_DATA_ACK(); //x80 |
6 | else if(help==0x88) Data=TWSI_TW_SR_DATA_NACK (); //x88 |
7 | else if(help==0x90) TWSI_TW_SR_GCALL_DATA_ACK(); //x90 |
8 | else if(help==0x98) TWSI_TW_SR_GCALL_DATA_NACK(); //x98 |
9 | else if(help==0xA0) TWSI_TW_SR_STOP(); //xA0 |
10 | else error(); // alle anderen erzeugen Fehler! |
Deine Hausaufgabe wäre nun, das Ding auf einen case-switch umzuschreiben. Ist schneller, kompakter und lesbarer. Ob noch mehr Köpse in Deinem Source sind, kann ich nicht beurteilen. Wie gesagt, ich habe danach aufgehört, weiterzulesen. Gruß, Frank
Danke Frank! ich werde es gleich ändern! Hab die switch case fallunterscheidung total vergessen!
Ich hab es verbessert. Aber leider hat sich rein gar nichts geändert! der slave hat zuerst 0x60 im TWSR (bedeutet das er die Adresse empfangen hat und ACK zurück geendet hat) und danach gleich 0xA0(bedeutet das Stop gesendet wurde). Das heißt es kommen keine Daten an! Aber ich habe beim Master doch alles so programmiert, wie es im Datenblatt steht und alle anderen es auch machen! :-(
Also nen weiteren Fehler find ich da jetzt nicht. Nur sind mir einige Dinge aufgefallen, die zwar jetzt nicht falsch sind, aber früher oder später für Probleme sorgen könnten. Die SlaveID wird immer direkt angegeben, idealerweise als Hex-Wert (z.B. bei I2C-EEPROMS 0xA0). Nicht als ungerade Zahl und dann verdoppeln durch Shift. Und Punkt 2, in der Init-Funktion:
1 | TWCR |= ((1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE)); |
Wie sicher bist du dir bei dieser Zeile, dass z.B. das Bit TWST0 auch wirklich 0 ist? (Tip: Was ist, wenn es vor dieser Zeile 1 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.