Stefan U. schrieb:
> Die TWI Schnittstelle ist recht kompliziert zu benutzen. Ich denke, es
> kann sehr hilfreich sein, zumindest bei den ersten Versuchen das I²C
> Protokoll "manuell" zu implementieren, indem du zwei IO Pins direkt
> ansteuerst (Bit-Banging).
>
> Bei mir hat das bisher immer so gut geklappt, dass ich den Code danach
> gar nicht mehr auf TWI ändern wollte. Ich habe ca. 15 Projekte mit
> Bit-Banging gemacht, aber nur 2 mit TWI.
Natürlich geht das "manuell" besser, weil entscheidende Aktionen auf dem
TWI damit übergangen werden können und eine Fehlermeldung dafür dann
nicht existiert. Das funktioniert zwar bei den meisten I2C-Chips, jedoch
nicht immer. Ist also nicht wirklich eine Lösung.
Der TWI ist eigentlich gar nicht so kompliziert wie er aussieht. Die TWI
Schnittstelle im ATmega ist sehr brauchbar. Alle Aktionen die auf dem
TWI Bus stattfinden werden durch das TWINT Flag gemeldet. Am besten ist,
den Interrupt TWIE in TWCR setzen. Jedes mal wenn auf dem TWI eine
Aktion stattfindet, wird dann ein Interrupt ausgelöst. In der Interrupt
Routine lädst du das Statusregister TWSR und blendest die ersten 3 Bit´s
aus. Weil diese ersten 3 Bit´s andere Aufgeben haben! Also Bit0, Bit1
und Bit2 ausblenden! Dann bleibt ein Wert in den restlich verbliebenen
Bit´s übrig, der dann eine Art "Hausnummer" für die gerade erkannte
Aktion auf dem TWI darstellt. Ein Beispiel:
Bleibt nach Ausblenden der unteren 3 Bit´s hexadezimal 60 (also 0x60) im
TWSR Register übrig, dann wurde die Adresse für Schreiben empfangen und
wenn die empfangene Adresse mit dem Wert im Adressregister TWAR
übereinstimmt, wird ein ACK zur Bestätigung vom TWI automatisch
generiert. Würde aber z.B. im Statusregister TWSR der Wert 0x80 übrig
bleiben, so wären Daten empfangen wurden, die nun aus dem TWDR Register
ausgelesen werden können und es wurde ein ACK gesendet, was bedeutet, es
waren noch nicht die letzten Daten. Bei dem Wert 0x88 wären dann Daten
empfangen wurden die aber kein ACK hatten. Das wäre der Fall wenn der
Master damit das Ende des Datensendens kenntlich macht.
Also du siehst, es ist gar nicht so schwer, wenn man es verstanden hat.
Sobald eine Aktion auf dem TWI stattfindet, dann wird ein IRQ ausgelöst,
nachgesehen welcher Wert im TWSR Register steht und dann anhand dieses
Wertes in die entsprechend benötigte Routine gesprungen, die dann z.B.
dem Datenregister TWDR das benötigte Byte übergibt, oder in einer
anderen Routine den empfangenen Wert aus dem TWDR Register holt.
Wichtig bei dem TWI ist es aber immer, nach dem setzen des TWINT Flags
durch eine Aktion auf dem TWI Bus, dieses auch wieder per "Hand" zu
löschen. Also eine "1" darauf schreiben! Denn das TWINT wird nicht
automatisch zurück gesetzt.
Wenn du den TWI nutzt, dann kannst du auch alles was sich I2C nennt auch
anschließen! Mehr Informationen über die Werte in dem TWSR Register und
deren Bedeutung findest du in den Datenblättern und auch hier im Forum.
Noch ein Tipp. Wenn man den TWI soweit programmiert hat und ein
"Testprogramm" erstellt, wo gleich nach dem "Stop" sofort wieder ein
neues "Start" folgt, kann es sein, das der TWI das "Stop" noch gar nicht
fertig abgearbeitet hat, weil der Clock des TWI nur 100kHz oder 400kHz
beträt, der Takt für den ATmega aber 8MHz oder mehr und der neue "Start"
noch nicht generiert werden kann. Deshalb sollte man bei einem solchen
"Testprogramm" immer das Timing des TWI nicht aus den Augen verlieren!
Auch gibt es den "Restart" der nicht umsonst existiert und in manchen
Protokollen auch dringend benötigt wird!