Hallo, Ich habe einen AT-Mega, an den ich ein PCF8574 (Portexpander) angeschlossen habe. Im Moment bin ich dabei nur Daten zum PCF zu senden. Das funktioniert jetzt alles ganz gut, es gibt nur einen sehr mysteriös Problem.. Ich sende eine Start Condition (TWSTA, TWEN, TWINT), dann die Adresse. Danach frage ich das Statusregister ab (TWSR) ob darin 18h steht (TW_MT_SLA_ACK). Dann sende ich die Daten und frage wieder das Statusregister ab und überprüfe ob 28h (TW_MT_DATA_ACK) darin steht. Dies ist bis auf exakt EINE Ausnahme der Fall. Wenn ich zuerst als Data eine 0 zum PCF sende und danach eine 255, ist im TWSR keine 28h sondern eine 0! Der PCF übernimmt aber beide Datenwerte ordnungsgemäß. Hat dies Phänomen schon mal jmd. gehabt oder hat jmd. ein paar Ideen woran das liegen könnte? (Die SCL Frequenz beträgt ziemlich genau 50kHz (gemessen))
0x00 Bus error due to an illegal START or STOP condition No TWDR action 0 1 1 X Only the internal hardware is affected, no STOP condition is sent on the bus. In all cases, the bus is released and TWSTO is cleared. Illegal Start oder Stop Condition? Poste mal den Code...
Das ist die Funktion die für das Seden zuständig ist: int twi_Send(uint8_t data, uint8_t address){ char string[4]; /* DDRC &= !((1<<DD0)|(1<<DD1)); //SCA und SCL: lesen.. PORTC= (1<<DD0)|(1<<DD1); //..und Pullups aktivieren*/ TWCR= ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN)); //TWI aktiveren und Start-Condition auslösen while(!(TWCR & (1<<TWINT))); //Warten auf Start-Condition if((TWSR & 0xF8) !=TW_START) uart_PutS("FEHLER: keine StartCond");//Wenn keine Start-Condition gesendet wurde, abbrechen TWDR=address & (0xFE); //Adresse mit Schreibbit (XXXXXXX0) in Datenregister laden.. TWCR= ((1<<TWINT)|(1<<TWEN)); //..und senden while(!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK if((TWSR & 0xF8) != TW_MT_SLA_ACK) uart_PutS("FEHLER: Slave reagiert nich");//Wenn kein Slave reagiert, abbrechen TWDR=data; //Byte in Datenregister laden.. TWCR= ((1<<TWINT)|(1<<TWEN)); //..und senden while(!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK if((TWSR & 0xF8) != TW_MT_DATA_ACK) uart_PutS("FEHLER: Slave akzeptiert nicht"); //Wenn nicht vom Slave akzeptiert, abbrechen TWCR= ((1<<TWINT)|(1<<TWSTO)|(1<<TWEN)); //Stop-Condition auslösen uart_PutS("STOP"); return 0; } p.s.: kann man das nicht irgendwie auch als code formatieren lassen?
Ich als "C-Neuling": probier ich mal Du sendest erst eine 0xFF als erstes Datenbyte und dann eine 0x00 als zweites Datenbyte. ZWISCHEN diesen beiden sendest Du STOP. KLar, dass dann 0x00 im TWSR steht. Code formatieren geht mit <Eckige KLammer auf> grosses C <eckige KLammer zu> Hier der code <Eckige KLammer auf> Schrägstrich grosses C <eckige KLammer zu>
1 | int twi_Send(uint8_t data1,unint8_t data2, uint8_t address){ |
2 | char string[4]; |
3 | /* DDRC &= !((1<<DD0)|(1<<DD1)); //SCA und SCL: lesen..
|
4 | PORTC= (1<<DD0)|(1<<DD1); //..und Pullups aktivieren*/
|
5 | |
6 | TWCR= ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN)); //TWI aktiveren und |
7 | Start-Condition auslösen |
8 | while(!(TWCR & (1<<TWINT))); //Warten auf Start-Condition |
9 | if((TWSR & 0xF8) !=TW_START) uart_PutS("FEHLER: keine |
10 | StartCond");//Wenn keine Start-Condition gesendet wurde, abbrechen |
11 | |
12 | TWDR=address & (0xFE); //Adresse mit Schreibbit (XXXXXXX0) |
13 | in Datenregister laden.. |
14 | TWCR= ((1<<TWINT)|(1<<TWEN)); //..und senden |
15 | while(!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK |
16 | if((TWSR & 0xF8) != TW_MT_SLA_ACK) uart_PutS("FEHLER: Slave reagiert |
17 | nich");//Wenn kein Slave reagiert, abbrechen |
data in data1 umbenannt: erstes Byte
1 | TWDR=data1; //Byte in Datenregister laden.. |
2 | TWCR= ((1<<TWINT)|(1<<TWEN)); //..und senden |
3 | while(!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK |
4 | if((TWSR & 0xF8) != TW_MT_DATA_ACK) uart_PutS("FEHLER: Slave |
5 | akzeptiert nicht"); //Wenn nicht vom Slave akzeptiert, abbrechen |
data2 hinzugefügt: zweites Byte
1 | TWDR=data2; //Byte in Datenregister laden.. |
2 | TWCR= ((1<<TWINT)|(1<<TWEN)); //..und senden |
3 | while(!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK |
4 | if((TWSR & 0xF8) != TW_MT_DATA_ACK) uart_PutS("FEHLER: Slave |
5 | akzeptiert nicht"); //Wenn nicht vom Slave akzeptiert, abbrechen |
6 | |
7 | |
8 | |
9 | TWCR= ((1<<TWINT)|(1<<TWSTO)|(1<<TWEN)); //Stop-Condition auslösen |
10 | uart_PutS("STOP"); |
11 | return 0; |
12 | }
|
man kann data auch als Zeiger übergeben und vorab als Array anlegen. Als Parameter könntest Du dann noch leaenge mit übergeben und in einer Schleife deine Daten rausschicken, bis laenge erreicht wurde. und ERST DANN das STOP schicken.
1 | while(dataindex < laenge) { |
2 | TWDR=data[dataindex++); //Byte in Datenregister laden.. |
3 | TWCR= ((1<<TWINT)|(1<<TWEN)); //..und senden |
4 | while(!(TWCR & (1<<TWINT))); //warten auf ACK oder NACK |
5 | if((TWSR & 0xF8) != TW_MT_DATA_ACK) uart_PutS("FEHLER: Slave |
6 | akzeptiert nicht"); //Wenn nicht vom Slave akzeptiert, abbrechen |
7 | }
|
laenge = 2 data[0]= 255 data[1]= 0 twi_Send(uint8_t laenge,unint8_t* data, uint8_t address) bin ich jetzt aber nicht sicher, wie das mit den Zeigern war ;-)) Daher, weil es ja immer zwei Bytes sind, würde ich einfach zweimal (wie oben gezeigt) die Daten rausschicken, bevor STOP rausgeht. Ich denke aber, das andere, die richtig Ahnung von C und Zeigern haben, da eher was zu sagen können, nicht wahr? ;-)) Viele Grüße AxelR.
Ersteinmal einen riesengroßen Dank für deine Mühe Axel! Aber ich glaube ich habe mich schlecht ausgedrückt. Ich will ja gar nicht direkt aufeinander folgend Bytes schicken sondern nur eines zur Zeit. Dann mach ich etwas anderes vllt, sogar mit einem anderen I2C Device "sprechen", und dann will ich erst ein weiteres Datenbyte senden. Wenn ich z.B. eine 1 sende wird die 1 am PCF angezeigt. dann mache ich etwas anders, dann sende ich an den PCF eine 255. Im TWSR steht 28h=ACK. Ich kann auch jede andere Zahl nehmen, die rüberschicken und danach 255 rüberschicken - Im TWSR steht 28h. NUR wenn ich zuerst eine 0 zum PCF sende (wird mit ACK bestätigt und kommt auch an) und danach eine 255 rüberschicke hab ich keine 28h im TWSR. Die 255 wird am PCF aber übernommen. Sende ich zuerst eine andere Zahl (s.o.) aber schon. (ich rufe einfach immer Obige Fkt. auf, d.h. es wird IMMER startcon, address, data, stopcon übertragen)
Korrektur von: Sende ich zuerst eine andere Zahl (s.o.) aber schon. nach: Sende ich zuerst eine andere Zahl (s.o.) steht aber die 28h im TWSR.
ICh habe das Datenblatt vom PCF nur überflogen, aber ich glaube man MUSS immer zwei Byte senden. Nee, musst Du nicht - hatte irgentwie einen 16Bit Portexpander angeklickt, naja... http://www.mikrocontroller.net/mc-project/Pages/Projekte/ICs/Port%20Expander/Portexpander%20Beispiel.zip evtl. findest Du in dem Zip File was. Ich kann mir das Verhalten dann auch nicht erklären :-(
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.