www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik TWI / I2C von 0 auf 255 gibt kein ACK


Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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))

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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...

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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>
int twi_Send(uint8_t data1,unint8_t data2, 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
data in data1 umbenannt: erstes Byte
  TWDR=data1;                  //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
data2 hinzugefügt: zweites Byte
  TWDR=data2;                  //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;
}

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.
while(dataindex < laenge) {
  TWDR=data[dataindex++);                  //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
}

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.

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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)

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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/Pr...
evtl. findest Du in dem Zip File was.

Ich kann mir das Verhalten dann auch nicht erklären :-(

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.