Ein einfaches Beispiel für einen TWI / I2C Master und Slave. Es werden 2 Daten-Bytes an den Slave gesendet und anschließend zwei Daten-Bytes vom Slave empfangen. Es ist kein fertiges Projekt, aber es hilft hoffentlich, die Grundmechanismen schneller zu erkennen. z.B: - Initialisierung - Adressvergabe - Interrupt-Handling - mögliche Error-Routinen - TWSR / TWCR - Auswertung Die LEDs vom MASTER zeigen den Zustand der Datenübertragung (z.B. erfolgreicher START) an und die LEDs vom SLAVE, welcher TWSR Zustand anliegt, wenn der TWI-Interrupt aufgerufen wird. Absichtlich habe ich alle Vorgänge stark durch Warteschleifen und eine sehr niedrige SCL Frequenz gebremst, damit man besser nachvollziehen kann, wann was und wo passiert. Bernhard
Hallo, finde ich echt ne super sache das du das mal online gestellt hast, werde es sofort mal ausprobieren. Eine Frage hätte ich jedoch noch mit was für einem programm hast du den Plan gezeichnet?
@Thorran Microlovic >finde ich echt ne super sache das du das mal online gestellt hast, Danke, ich hoffe, dass dieses kleine Beispiel bei den Grundlagen etwas weiter hilft. >mit was für einem programm hast du den Plan gezeichnet? mit sPLAN 4.0, ist ein sehr einfaches und leicht zu bedienendes Programm mit vielen interessanten Spezialfunktionen.
Hey super ! Danke das du das Programm online gestellt hast. Möchte das selbe Programm in C-realisieren ! Nun habe ich von Assembler nicht so den Plan! Kann mir jemanden einen Tipp geben?
Hallo.. ich bin begeistert - genau das habe ich schon lange gesucht. Jetzt habe ich begonnen, das ganze für mein eigenes Programm abzuändern, und bin da auf ein Problem gestossen. Es gibt da 2 Sachen die ich nicht verstehe. Das ist die Abfrage des TW_INT_FLAG. WANN und von WEM wird es gesetzt oder gelöscht? Die andere Sache ist der Check des Status-Registers (TWSR) - dieses Register hat sehr unterschiedliche Werte. Ich möchte gern wissen, wie sich die einzelnen Werte zusammensetzen? Also der Wert im Register addiert mit 0xF8 ergibt einmal 0x08 oder 0x18 oder 0x40 usw. Könnte man das mal zum besseren Verständnis in einer Tabelle darstellen? Gruss Uwe
@Uwe Ortmann (Schwede) >Das ist die Abfrage des TW_INT_FLAG. >WANN und von WEM wird es gesetzt oder gelöscht? Gesetzt wird es, ganz allgemein ausgedrückt, wenn ein Ereignis am TWI registriert wird. z.B. -eine bestimmte Aktion (zB. Start) durchgeführt wurde -wenn ein Slave von einem Master angesprochen wird -ein Zeichen vom Master gesendet wurde -ein "Error" auftrat Gelöscht wird es, in dem es auf "1" gesetzt wird >Die andere Sache ist der Check des Status-Registers (TWSR) - dieses >Register hat sehr unterschiedliche Werte. Ich möchte gern wissen, wie >sich die einzelnen Werte zusammensetzen? Also der Wert im Register >addiert mit 0xF8 ergibt einmal 0x08 oder 0x18 oder 0x40 usw. Der Wert des Registers wird nicht mit 0xF8 addiert, sondern die untersten 3Bit auf 0 gesetzt (2xVorteiler und 1xReserviertes-Bit), sie werden sozusagen ausgeblendet. Die Werte und die Bedeutungen findest Du ab Seite 177 im Datenblatt. Anmekung: Für viele Anwendungen empfielt es sich, wenn man nach einem INT-Flag-Interrupt prüft, warum dieses INT-Flag gesetzt wurde. Ich hoffe, ich habe Dir etwas weiter helfen können? Demnächst werde ich hier ein sehr interessantes "RS232-TWI-Interface" veröffentlichen, dort sind die einzelnen Funktionen detaillierter angewendet worden. Gruß Bernhard
Hallo... erstmal Danke für die Tipps, haben mir sehr viel geholfen. Allerdings machen mir noch 2 Sachen "Kopfschmerzen". Ein kleines Problem: Ich takte meinen mega8 mit 16MHz - das macht dann pro Zyklus 60 ns. Wie baut man am besten eine Zählschleife auf, um eine Pause von 6 ms zu bekommen? Das grössere Problem: Ich möchte einen externen Interrupt an Int0 auswerten (also ein Unterprogramm starten). Ich bekomme das einfach nicht hin. Könnte ich ein wenig Hilfe bekommen? Gruss Uwe
@UWE >Wie baut man am besten eine Zählschleife auf, um eine Pause von 6 ms >zu bekommen? Du hast es schon richtig formuliert, mit einer Zählschleife, bei 16MHz Takt vergehen 0.0625µs pro Takt, d.h. Du müsstest den µC mit 96.000 Takten mit sich selbst beschäftigen, um eine Pause von 6ms zu erzeugen. Schau mal bitte nach unter: http://www.mikrocontroller.net/forum/read-4-57760.html# >Ich möchte einen externen Interrupt an Int0 auswerten (also ein >Unterprogramm starten). Vor langer Zeit habe ich hier mal einen kleinen Beitrag dazu geschrieben: http://www.mikrocontroller.net/forum/read-4-156657.html Vielleicht hilft es Dir etwas weiter? Bernhard
Hallo... nachträglich noch vielen Dank, hat mir weitergeholfen. Bei einer Sache muss ich allerdings noch mal nachfragen, damit ich da nichts falsch verstehe. Im Programm ganz oben ist der Vorteiler für das TWI mit 0, 4, 16 und 64 angegeben. Ist die 64 der grösst mögliche Teilungsfaktor? Denn wenn ich meinen Mega8 mit vollen 16MHz takte dann hätte ich auf dem TWI noch 250 KHz - also deutlich zu viel. Da wäre es wohl besser ich takte den Controller mit 1MHz. Da komme ich auf ca. 15KHz, was für eine längere Busleitung von Vorteil ist. Habe ich das so richtig verstanden? Gruss Uwe
@UWE >Ist die 64 der grösst mögliche Teilungsfaktor? >Da wäre es wohl besser ich takte den Controller mit 1MHz Ja das ist er und zusätzlich kannst Du auch die Bitrate ändern, um die SCL-Frequenz zu verändern, aber sie sollte größer als 11 sein, da es ansonsten zu Problemen bei der Busverbindung kommen kann. Ich stell Euch mal eine Excel-Tabelle zur Verfügung, womit man die SCL-Frequenz berechnen kann. Bernhard
Hallo, kämpfe gerade mit TWI und bin dan hierauf gestoßen. Da ist mir was aufgefallen: Die Berechnung der TWI-Bitrate funktioniert laut Atmel-Datenblättern so: CPU Clock frequency SCL frequency = ---------------------------- 16 + 2(TWBR) x 4 ^ TWPS In dem Excel-Sheet steht aber: =Fcpu/(16+(2*TWBR)*TWPS) Also, wenn ich die Frequenz für zwei gleich hoch getaktete Controller berechne wird das vielleicht gehen, aber bei verschiedenen Frequenzen? Oder übersehe ich was ganz entscheidendes?
@Ingo >In dem Excel-Sheet steht aber: > =Fcpu/(16+(2*TWBR)*TWPS) >Also, wenn ich die Frequenz für zwei gleich hoch getaktete Controller >berechne wird das vielleicht gehen, aber bei verschiedenen >Frequenzen? Oder übersehe ich was ganz entscheidendes? Du hast Recht, hab's auch gerade gesehen. In der euen Excel-Tabelle habe ich meinen Berechnungs-Fehler behoben. Danke für den Hinweis. Bernhard
@Mareike >Möchte das selbe Programm in C-realisieren ! Nun habe ich von >Assembler nicht so den Plan! Kann mir jemanden einen Tipp geben? ...wo drückt denn der Schuh ?
Hätte da eine Frage: Aus der Slave.asm: "TWSI_TW_SR_DATA_ACK: ; x80 10000000 (die vorher adressierten (SLA+W) Daten wurden empfangen; ACK wurde zurückgesendet cbi PORTB,4 in DATA, TWDR ; DATA rjmp TWSI_w" Ich will über TWI dem Slave einfach Daten zusenden. Seh ich das recht das ich an obiger Stelle die Empfangenen Datennn auswerten kann? Also sagen wir mal ich sende vom Master 0xFA an den Slave, und an der stelle wird dies empfangen? Und kann ich dann einfach alle LED ausgaben Auskommentieren oder ist noch mher nötig? Der Slave braucht auch nichts zurückzusenden, soll nur Daten empfangen.
@Läubi >Ich will über TWI dem Slave einfach Daten zusenden. >Seh ich das recht das ich an obiger Stelle die Empfangenen Datennn >auswerten kann? >Also sagen wir mal ich sende vom Master 0xFA an den Slave, und an der >stelle wird dies empfangen? Ja das ist korrekt, das empfangene Byte vom Master liegt nun im "DATA" zur weiteren Verarbeitung bereit >Und kann ich dann einfach alle LED ausgaben Auskommentieren oder ist >noch mher nötig? Der Slave braucht auch nichts zurückzusenden, soll >nur Daten empfangen. Die LEDs müssen nicht unbedingt sein, sie dienen nur dazu, zu zeigen, welchen Wert gerade das "TWSR" - Register gehabt hat. Bernhard
Hallo! Ich weiß dass ich einen ziemlich alten, aber nützlichen Beitrag hier entstaube. Ich habe dazu mal eine Frage: Ich brauche für einen Aufbau den I2C Bus. Ich habe mir mal dieses Beispiel heruntergeladen und ausprobiert. Es funktioniert, nur eben sehr langsam (ist ja auch oben gesagt). Also habe ich mir gedacht: Unnötige Wait-Befehele wegfallen lassen und die Prescaler und Bitrate-Werte so einrichten, dass die Übertragung recht schnell gehen müsste. Anhand der LEDs in den I2C-Leitungen kann man erkennen, dass die Datenübertragung recht schnell läuft (nur ganz kurzes aufblinken). Dennoch ist nach der Übertragung noch eine recht lange Pause, ehe die nächste Übertragung (neues Aufblinken) stattfindet. Hat jemand eine Idee, woran das liegen könnte? Vielen Dank schonmal für eure Hilfe!
Hallo Martin,
>Dennoch ist nach der Übertragung noch eine recht lange Pause
Ich vermute, dass noch irgendwo ein rcall wait_xxx sein unwesen treibt.
Entferne doch mal spaßenshalber komplett die wait Routinen ?
Gruß
Bernhard
Gesagt...getan...und eine äußerst verblüffende Antwort: Es gab in der Master-datei 2 wait-Zugriffe: - der erste nach der Initialisierung, den hatte ich vorher da gelassen weil der ja nur einmal durchlaufen wird und nicht stört. - der zweite im Abschnitt "TWI_ERROR". Das verwundert mich sehr, weil ich daraus schließe, dass nach jeder Übertraung anscheinend auch ein Fehler auftritt. Darf das sein? Ich meine es läuft jetzt schnell, also so wie gewünscht, aber es ist doch irgendwie ein komisches Gefühl zu wissen dass da immer ein Fehler drin ist. Oder ist das normal so?
>dass nach jeder Übertraung anscheinend auch ein Fehler auftritt. Darf das >sein ?
Nein, das darf natürlich nicht sein.
Also, Ursache suchen.
Vielleicht SCL-Takt zu hoch? Adresse falsch? usw...
Vielleicht gibts im Slave noch ein wait, so das das Antwort-Bit nicht
bereitgestellt wird?
Hm da habe ich sicher was zu suchen, weil ich im Grunde genommen deine möglichen Fehlerquellen ausschließen kann: SCL-Takt: Habe mit Bitrate 255 und Prescaler 64 bis zu Bitrate 11 und Prescaler 1 allerlei Tests gemacht, also bei 255/64 kann er ja nicht mehr zu hoch sein^^. Adresse kann nicht falsch sein, da der IC dann ja gar nicht angesprochen würde. Anhand von LEDs erkennt man ja dass er angesprochen wird, nur eben auch dass er wegen der langen Pause die Fehler-Routine aufruft. Im Slave ist kein Wait mehr vorhanden. Nunja ein Glück geht es ja schonmal jetzt sehr schnell - wofür ich sehr dankbar bin - der Fehler wird sich wohl im Laufe der Zeit und mit einer noch genaueren Vertiefung in den Bus hoffentlich finden.
Hallo alle zusammen, ich bin gerade auf der Suche nach I2C-Beiträgen auf diesen Artikel gestoßen. Oben ist dieses klasse Assembler-Programm gepostet. Leider habe ich von Assembler fast gar keine Ahnung und beschäftige mich gerade mit C für eine einfache Sende-Empfangs-Routine zwischen zwei AVR. Das Ding läuft leider noch nicht und langsam gehen mir die Ideen aus. 1. Frage: Hat schon einmal jemand den i2c.h Header in CodeVisionAVR benutzt? Nachdem mein selbst geschriebenes Programm Probleme macht, dachte ich versuche ich den mal zu verwenden. Hat da jemand zufällig ein kurzes Codebeispiel? Bei mir hakt es nämlich noch, der Slave versteht aus irgendeinem Grund nicht, dass er angesprochen wird... 2. Frage: Existiert ein diesem Assembler-Programm ähnliches C-Programm? Für eine C-Anfängerin wie mich wäre das nämlich echt hilfreich, da es ewig dauert, bis man ein laufendes Programm gebastelt bekommt (mit Datasheets, Atmel-Beispielen für andere Anwendungen, etc.)... Danke und viele Grüße!!! Xine.
Hi Xine, beschäftige mich auch grade mit TWI/I2C in C. Habe es mit der Procyon avrlib zum Laufen bekommen (Tastatur und Display). Schick mir doch mal genauere Angaben - welche Slaves willst du ansteuern, wie ist dein Aufbau, etc. Ich kann Dir dann meine Codebeispiele schicken. seventh_son@gmx.de
Ich suche im Forum seit Stunden nach so einem Beispiel in C ( =>negativ :-( ) Hat jemand vielleicht das Beispiel hier in C übersetzt? Kann jemand ähnliches Beispiel in C geben? Gruß Siem
@siem: Ich habe heute sowas hier in Codesammlung gestellt. Gruss Manni
Hallo. Ich beschäftige mich erst seit ein paar Tagen mit Microcontrollern und bin bei der Suche nach Hilfe zur TWI Schnittstelle in diesem Thread fündig geworden. Erste Versuche haben mit dem (gering modifizierten) Code auch schon geklappt (nur Daten senden an einen PCF8575 I/O Extender). Nun wollte ich den den Code etwas aufräumen und in handliche Unterprogramme zerlegen und bin dabei über zwei Stellen gestolpert. 1. Warum wird beim Senden der Stardbedingung für den Receiver Teil das TWEA Bit gesetzt? Wenn ich das richtig verstanden habe wird dadurch doch ein ACK ausgeführt, was an der stelle eigentlich gar nicht passieren sollte. Die Startbedingung sollte doch bei MR und MT Teil identisch sein, oder nicht? 2. Ich habe in den Beiträgen weiter oben etwas über multiple Fehlermeldungen bei der Kommunikation gelesen. Diesbezüglich hätte ich eine Vermutung. Angenommen der Slave antwortet nicht, weil z.B. die Adresse falsch ist, dann würde, weil kein ACK kommt der Errorhandler ausgeführt. Dieser stoppt und initialisiert das TWI neu. Springt dann aber wieder in die abgebrochene Kommunikation zurück: TWI_ERROR: .... ; TWI INITIALISIERUNG rcall TWI_INI rcall wait_1s sbi PORTD,0 ret <<< Diesen Rücksprung meine ich Als nächstes sollen Daten empfangen/gesendet werden , dabei fehlen Start und SLA+R, also gibt es wieder eine Fehlermeldung. Solange bis der Code mit dem STOP durch ist und wieder von vorne anfängt. So zumindest verstehe ich den Code. Kann das jemand bestätigen bzw. mir das TWEA Bit erklären? Danke im Voraus. MfG Hendrik
>Kann das jemand bestätigen bzw. mir das TWEA Bit erklären?
Ich lese Quelltexte von dieser Website nie, weil sie sehr oft fehlerhaft
sind und totalen Schwachfug enthalten, aber den zweiten Wunsch kann ich
dir erfüllen:
TWEA sorgt dafür, dass beim nächsten TWINT eines Empfangs auch direkt
ein ACK gesendet wird, ergo ist es die "Empfangsbestätigung" über TWI.
Hallo Bernhard Schulz, möchte mich bei dir für das einwandfreie Beispiel bedanken!!! Ständig erhielt ich nach SLA+R -- NACK($48), erst nachdem ich das Programm vom Mega 16 zu Mega 8 portierte ist dieser Fehler verschwunden. Etweder hat mein Mega 16 einen TWI- Bug oder alle M16 sind verbuggt(keine Ahnung). Dann konnte ich keine Daten auslesen erst mit deiner MR_LeseRoutine ist es mir gelungen Daten aus’m DS1307 auszulesen, was für ein tolles Gefühl :-) Davor habe ich mich 3 Tage mit TWI rumgeplagt. Nochmals vielen Dank ! Mit freundlichen Grüßen gtf
hey.. ich plage mich jetzt schon fast eine Woche mit TWI rum. Ich hab genau das Beispiel aufgebaut. 2 ATMega8 mit Leds am PORTB usw. Das einzige was ich geändert habe ist, das ich vom Master aus nur 1 Bit sende und der Slave es empfangen soll. Außerdem habe ich das ganze in C gemacht. Trotzdem ist vom Aufbau alles gleich. Mein Problem: Adresse wird gesendet und Master erhält ACK. Danach sendet er aber keine Daten sondern macht sofort Stop. ich poste auch mal meine Programme. Vllt findet jemand auf die schnelle ein Fehler?
Versuch's mal mit meinen Routinen, die bei mir seit langer Zeit absolut stabil laufen. [[Beitrag "AVR TWI Master und Slave Funtionen in C"]] Gruss Manni
Ich hab die Routinen ausprobiert. und siehe da.. es klappt! Frag mich aber trotzdem was mit meinen nicht stimmte?
Und schon wieder einen Baster zufrieden gestellt, ja das freut doch auch mich :-) Gruß Manni
Hallo zusammen, ich werd hier noch wahnsinnig. Ich kapier die Funktion des TWINT-Flags einfach nicht, drum wollte ich mal vorsichtig nachfragen, ob mir einer helfen kann (obwohl der Beitrag schon etwas älter ist). In dem Beispiel von Bernhard S. heißt es in der MASTER.ASM unter TWI-MASTER-RECEIVER:
1 | TWI_MASTER_RECEIVER: |
2 | ; LEDs aus |
3 | ldi temp,255 |
4 | out PORTB,temp |
5 | ; START |
6 | ldi temp, (1<<TWINT | 1<<TWEA | 1<<TWSTA | 1<<TWEN ) |
7 | out TWCR, temp |
8 | ; warten, bis TWINT wieder = 1 |
9 | rcall TWI_TWINT_wait |
10 | cbi PORTB,0 |
LED's aus is noch ok, aber dann: ins 'temp'-Register kommt bei TWINT ne "1" rein, und geb das ganze ins TWCR aus. Und dann warte ich, bis TWINT wieder "1"??? Es wurde doch grad ne 1 reingeschoben, also steht da auch gleich ne 1 drin, oder? Oder wird das TWINT-Flag dann sofort auf 0 gezogen und kommt erst wieder auf 1, wenn die Aktion fertig ist? Wär echt nett, wenn mich einer auf den richtigen Weg leitet... Danke euch! mfg Foikei P.S.: wenn mein 30-Kanal-Temperatur-Logger fertig ist, stelle ich ihn euch vor...wenn ich es denn schaffe, das TWI zu kapieren ;-)
Es gibt einige Flags bei den Atmels, die gelöscht werden, indem man sie
auf "1" setzt.
> Oder wird das TWINT-Flag dann sofort auf 0 gezogen und kommt erst wieder > auf
1, wenn die Aktion fertig ist?
Yep, durch Schreiben von 1 in TWINT wird es auf 0 gesetzt.
Habe mir vorgestern nen Layout nach dem Schaltplan gemacht)
Hmpf garnicht bemerkt, das die LEDs garnicht in der Reihenfolge sind - aber ist wiegesagt auf die Schnelle geschehen.. Anbei der Assembler Code von Bernhard von der 1. Seite 1zu1 in C uebersetzt. gruss
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.