PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TWI-slave ohne lib



linux_80
05.01.2006, 11:11
Hallo,
ich lese hier immer das man für das einsetzen des AVR als TWI-slave eine lib brauchen soll, wenn ich aber ins Datenblatt sehe, schaut das doch relativ einfach aus einen Slave ans laufen zu bekommen.
Deshalb hab ich mir vor Weihnachten noch schnell ein paar PCF8574 bestellt, und mich in das TWI-Thema eingelesen, da es im Wiki noch keine Seite dazu gab, diese auch noch angelegt und die ersten Infos reingeschrieben. -> TWI

Testumgebung: RN-control (Master), PCF8574 (zum testen ob Master auch richtig geht), RN-Mega8 (Slave).

Jetzt hab ich eine Quick dafür Dirty Version in Bascom gebaut, um zu sehen wie man den M8 als Slave hinbekommen kann, das Ergebnis ist dieses:

Am Master wird über den PC eine Zahl eingegeben, 0-255, die dann zum Slave gesendet wird und dort an PortD ausgegeben wird. (PortD weil hier alle Bits der Reihe nach an den LEDs zu sehen sind)

Master:

' TWI Testprogramm aus der Hilfe (abgespeckt)
' mit PCF8574

'The chip will work in TWI/I2C master mode
'Connected is a PCF8574 8-bits port extender

$regfile = "M32def.dat" ' the used chip
$crystal = 16000000 ' frequency used
$baud = 9600 ' baud rate

$lib "i2c_twi.lbx" ' we do not use software emulated I2C but the TWI

Config Twi = 100000 ' wanted I2C clock frequency
TWCR = &H04 ' TWEN

Dim B As Byte
Print "TWI master"
Do
Input B
I2csend &H40 , B ' send the value
Print B ;
Print " Error : " ;
Print Err ' show error status
Loop
End

Slave:

' TWI-slave test
' zum simulieren eines PCF8574

$regfile = "m8def.dat" ' the used chip
$crystal = 7372800 ' frequency used

Config Portd = Output ' kopletter PortD als Ausgang

Dim Twi_status As Byte
Dim Twi_data As Byte

Declare Sub Twi_init_slave
Declare Function Twi_wait() As Byte

Twi_data = 0
Call Twi_init_slave ' TWI aktivieren

' Hauptschleife
Do
Twi_status = Twi_wait()
If Twi_status = &H80 Then
Portd = Twi_data ' Daten auf PortD ausgeben
End If
Loop

End

' Unterprogramme

' TWI als slave aktivieren
Sub Twi_init_slave
Twsr = 0 ' status und Prescaler auf 0
Twdr = &HFF ' default
Twcr = &B00000100 ' erstmal nur TWI aktivieren
Twar = &H40 ' Slaveadresse setzen
Twcr = &B01000100 ' dann ACK einschalten
End Sub

' schauen ob was gekommen ist, Status zurückgeben, Daten in globale variable
Function Twi_wait() As Byte
Local Twcr_local As Byte
Twi_wait = &HF8
' warten bis TWINT gesetzt ist
Twcr_local = Twcr And &H80
If Twcr_local = &H80 Then
Twi_data = Twdr ' Daten sichern
Twi_wait = Twsr And &HF8 ' status zurückgeben
Twcr = Twcr Or &B10000000 ' TWINT löschen, erzeugt ACK
End If

End Function


Das lässt sich natürlich noch ausbauen, da mit diesem Testprogramm der Slave nur empfangen kann. Interupt wird auch nicht benutzt.

Torsten_G
05.01.2006, 11:49
Wie war das:

"Alle sagten, das geht nicht - bis einer kam, der das nicht wusste und es einfach tat..."

Mensch, ist ja Klasse!

Sollte man kaum glauben, dass es so einfach geht, da waren ja selbst die 5,00 Euro für die I2cSlave.lib fast noch zuviel... #-o

Muß ich unbedingt mal ausprobieren!

Besten Dank für die Info und viele Grüße

Torsten

ruediw
05.01.2006, 12:12
Zutrffendes bitte ausfüllen:

[ ] ich weiss was $lib "i2c_twi.lbx" bedeutet
[ ] ich weiss NICHT was $lib "i2c_twi.lbx" bedutet

MfH
Ruedi

Torsten_G
05.01.2006, 12:28
Nun, Ruedi, soweit mir bekannt, ist die i2c_twi.lbx für den Master, die i2cslave ist für den µC als Slave...

Worauf möchtest Du hinaus?

Grüße

Torsten

linux_80
05.01.2006, 15:24
Zum basteln hab ich ja nur die Demo von Bascom, und das hier ist mit der Demo möglich.

Ich wollte nur den Slave ohne lib verwenden, hier ist die lib beim Master und führt nur dazu, das das Programm kleiner wird (32 Byte), dann wird wohl Software-TWI gemacht, ansonsten Hardware. Hab das aber nicht genauer untersucht, will man die lib nicht einbinden, muss man diese Zeilen dafür einbauen:


Config Scl = Portc.0 ' we need to provide the SCL pin name
Config Sda = Portc.1 ' we need to provide the SDA pin name
Config I2cdelay = 10

Dann klappts auch mit dem ...

Ratber
05.01.2006, 15:33
@Linux

Ja,nette Arbeit aber...........


Zum einen unterstützen die Megas Hardwaremäßig master und Slavemodi so das eh keine Lib nötig ist.(Siehe Datenblatt.Sonderfall M8 der ne Extrawurst braucht weil andersrum aber auch kein Akt).

Schau mal auf deiner Platte in das Samplesverzeichnis.
Da findeste die Datei "M8_twi_Slave.bas" die da schon seit einigen Jahren steht.

Mach mal zb. mit nem Tiny26 nen Slave dann weißte für was die Lib eigentlich gedacht ist. :wink:


Ja und was die einfache Progrsmierung unter Bascom angeht so solltest du nicht vergessen das Mcselec in den letzten 2 Versionen den I2C Support mächtig aufgebohrt hat.



Also kein Kunststück.(Nicht falsch verstehen.will deine Leistung nicht schlecht machen)

Aber vieleicht mal was greifbares für die die immer gleich hektisch alarm schreien wennes nicht klappt.

linux_80
05.01.2006, 15:59
@ratber,
ich kenne dieses Sample, aber ...
hast Du dieses Sample schon mal versucht zu compilieren, das geht nämlich nicht ohne eine gewisse i2c_twi-slave.lbx und diese habe ich nicht !

Ich wollte auch nur zeigen das so ein Datenblatt eines AVR recht viel hergibt, es will nur gelesen sein. Und kostet im prinzip nix, ausser man druckt es aus.

Ratber
05.01.2006, 16:31
Ich sagte ja ,bis auf den Sonderfall M8 ist es mit den Megas kein Akt einen Slave zu produzieren.

Du hast es ja auch ohne klimmzüge geschafft die Hardware zu aktivieren





Ich wollte auch nur zeigen das so ein Datenblatt eines AVR recht viel hergibt, es will nur gelesen sein. Und kostet im prinzip nix, ausser man druckt es aus.

Ja,mein Reden.
Leider sind die meisten zu faul.
Schau dich mal hier um.
über die hälfte der Fragen sind überflüssig wenn man nur eine ZE aufwendet. :wink:

linux_80
05.01.2006, 16:46
bis auf den Sonderfall M8 ist es mit den Megas kein Akt einen Slave zu produzieren.

Was ist beim M8 anders ?
Ich hab hier ja u.a. einen M8 verwendet, und es ging ganz normal !
Egal ob Master oder Slave. :-k

Ich hab hier immer alle möglichen Datenblätter rumliegen M8, M32 usw., hab noch nix besonderes gefunden.

Ratber
05.01.2006, 16:53
Ja da hab ich mich falsch ausgedrückt.

Hardwaremäßig ist da kein Unterschied.

Es ist nur etwas anders wenn man unbedingt die Lib nutzen will die Mcselec anbietet.

Für deine Sache ist das nicht relevant.

rapo
05.01.2006, 19:30
Hallo zusammen,
ich kann mich oberen Meinungen nur anschließen...
Hab auch keine Slave lib. etc. und geht bei mir auch mit allem drum und dran...
Und unter "Bastlern": Wenn ich einen TWI-Slave brauche, spielen dann die 1,50 € eine Rolle die zwischen einem AT90s, einem Tiny oder einem AVR mit Hardware-Twi liegen?
Und interessierte finden (fast) immer was, für dieses (fast) dachte ich eigentlich sei dieses Forum.

MFG RP

Ratber
05.01.2006, 21:35
Nö,die Kosten sind eher untertgeordnet solange man keine Massenproduktion anstrebt.
Was aber manchmal ne Rolle spielt ist die Größe.

90er und Tinys bekommt man auch als 8 Polige,die Megas fangen erst bei 28 Poligen Gehäusen an was auch als SMD manchmal schon zuviel platz kosten kann.
Da wünsch ich mir noch nen 8 oder 14 Poligen Mega.
Mal sehen,kommt vieleicht doch noch.

Zeroeightfifteen
06.01.2006, 19:34
@linux_80
wie kann ich denn mit deinem Programm etwas über die RS232 Schnittstelle senden, damit ich sehe ob ich was empfangen kann?
Der Master sendet über die RS232 immer Error : 1

PS: also hab ich mir die Lib umsonst gekauft so wie ich das verstehe

linux_80
06.01.2006, 19:57
Der Testaufbau für die oberen Programm ist dieser:

PC -> RS232 -> 1.Mega -> TWI -> 2.Mega -> anzeige auf LEDs

Wenn ich dem 1.Mega zahlen über RS232 eingebe, sendet dieser den Wert über TWI an den 2.Mega, dieser zeigt den Wert dann über PortD an den LEDs an, 8 Bit.
Beim Master wird noch ein Errorcode über RS232 ausgegeben, damit man sieht ob er den Wert senden konnte. 0 - OK, 1 - Fehler.

Was willst Du genau bauen, evtl. bekommen wir da was zusammen ?

schaumamoi

Zeroeightfifteen
06.01.2006, 20:08
ich möchte später mal einen LCD und eine Tastatur an dem 2. atmega dran hängen und dies dann an den 1. atmega senden oder auch von diesem empfangen.
Jetzt will ich nur einmal eine Verbindung zwischen den wei atmega32 herstellen und dies irgendwie sichtbar machen.
Also wenn er mir error 1 sendet dann ist ein fehler aufgetreten.
Ich weis aber nicht was ich noch falsch mache.
Ich habe die zwei Atmega32 nach der Grundbeschaltung miteinander verbunden. http://www.robotikhardware.de/bilder/schaltungstepmega16.gif
Außerdem hab ich dein Programm auf atmega32 umgeschrieben und den PortD auf PortA
Das Byte B hab ich einfach mal auf 200 gesetzt damit ich nichts über die RS232 eingabe falsch machen kann. Das müsste doch so funktionieren oder?

Master:
' TWI Testprogramm aus der Hilfe (abgespeckt)
' mit PCF8574

'The chip will work in TWI/I2C master mode
'Connected is a PCF8574 8-bits port extender

$regfile = "M32def.dat" ' the used chip
$crystal = 16000000 ' frequency used
$baud = 9600 ' baud rate

$lib "i2c_twi.lbx" ' we do not use software emulated I2C but the TWI

I2cinit ' we need to set the pins in the proper state

Config Twi = 100000 ' wanted clock frequency

Dim B As Byte
Print "TWI master"
Do
B = 200
I2csend &H40 , B ' send the value
Print B ;
Print " Error : " ;
Print Err ' show error status
Loop
End

Slave:
' TWI-slave test
' zum simulieren eines PCF8574

$regfile = "m32def.dat" ' the used chip
$crystal = 16000000 ' frequency used
$baud = 9600

Config Porta = Output ' kopletter PortD als Ausgang

Dim Twi_status As Byte
Dim Twi_data As Byte

Declare Sub Twi_init_slave
Declare Function Twi_wait() As Byte

Twi_data = 0
Call Twi_init_slave ' TWI aktivieren

' Hauptschleife
Do
Twi_status = Twi_wait()
If Twi_status = &H80 Then
Porta = Twi_data ' Daten auf PortD ausgeben

End If

Loop

End

' Unterprogramme

' TWI als slave aktivieren
Sub Twi_init_slave
Twsr = 0 ' status und Prescaler auf 0
Twdr = &HFF ' default
Twcr = &B00000100 ' erstmal nur TWI aktivieren
Twar = &H40 ' Slaveadresse setzen
Twcr = &B01000100 ' dann ACK einschalten
End Sub

' schauen ob was gekommen ist, Status zurückgeben, Daten in globale variable
Function Twi_wait() As Byte
Local Twcr_local As Byte
Twi_wait = &HF8
' warten bis TWINT gesetzt ist
Twcr_local = Twcr And &H80
If Twcr_local = &H80 Then
Twi_data = Twdr ' Daten sichern
Twi_wait = Twsr And &HF8 ' status zurückgeben
Twcr = Twcr Or &B10000000 ' TWINT löschen, erzeugt ACK
End If

End Function

Zeroeightfifteen
06.01.2006, 20:21
jetzt funktionierts ich hab im compiler die I2C SLC und SDA Port eingestellt. Jetzt müsste ich halt nur noch vom Slave aus senden können. brauch ich die zwei Pullups an SDA und SCL auch?

linux_80
06.01.2006, 21:16
Die Pullups insgesamt einmal pro Leitung, egal wo.

Funktionierts mit der Lib oder mit dem Testprogramm ?

Wenn der Slave senden soll, muss man in Twi_wait() nur den richtigen Status abfragen und darauf reagieren, dH. mind. ein Byte zurücksenden.
Jetzt wird nur das angekomme Byte gesichert.

Zeroeightfifteen
06.01.2006, 21:28
Ich habe dein Programm hergenommen und das funktioniert.
Wie geb ich da den Status in Twi_wait ein?
Was muss ich da im Master eingeben damit der empfangen kann?
Gibt es da auch gute Bücher oder im Internet Hilfethemen wo man das etwas nachlesen kann, denn ich steige in dieses Gebiet erst ein.

linux_80
06.01.2006, 21:43
Du kanst Dir die Datenblätter von Atmel angucken, zuerst die des Mega32, dann gibts ein paar AppNotes und zwar u.a. AVR311.

guckst Du hier:
http://www.atmel.com/dyn/products/app_notes.asp?family_id=607
dann nach TWI suchen, und PDF und Zip runterladen und aufsaugen :-)
Für Bascom dann etwas umbauen, denn die Beispiele sind in C und ASM, das sollte aber nicht das Problem sein.

Zeroeightfifteen
06.01.2006, 22:26
ob mir diese datenblätter von atmel etwas helfen weis ich noch nicht. C sieht ja wieder ganz anderst als Bascom aus. Findest du dass das AVR Lehrbuch von Roland Walter einige Informationen enthält, die mir weiter helfen können? ich hab ja schon das AVR Risk Mikrokontroller, doch da steht nicht viel über TWI drin.

Zeroeightfifteen
06.01.2006, 23:10
dein programm ist aber irgendwie anderst aufgebaut wie die meisten beispiele. Du schreibst z.B. Twar = &H40 in einem anderem Thread steht Config Twislave = &H40 , Btr = 1 , Bitrate = 400000

linux_80
07.01.2006, 00:08
Buch hab ich keines zum AVR oder µC, kann deswegen auch keine Tipps geben, hab nur alles aus dem Inet, bzw. halt den Datenblättern.

Programmieren in diese Richtung kenne ich aber schon von früher her aus C64 Zeiten, da hat mich damals schon mehr interresiert was unter der Haube ist und rumgebastelt, ziemlich viel in ASM. Das kommt den µC schon ziemlich nahe.

Dann zu Config TWIslave, das kann man nur verwenden wenn man die berühmte Lib für Bascom hat.
Deswegen muss/kann man auch die gewünschte Geschwindigkeit angeben, was beim Slave normalerweise nicht gebraucht wird, weil das mit der Lib auch in Software möglich ist, und Bascom sich wohl einen Timer einstellt um an der Clock und Datenleitung zu lauschen.
Ist aber nur eine Vermutung.

Wenn ich am Wochenende mal Zeit/Lust habe, probier ich mal mein Testprogramm etwas aufzubohren. :-k :-k

Zeroeightfifteen
07.01.2006, 12:40
wenn ich aber twislave eingeba dann meldet bascom mir immer Unknown Interrupt TWI Error : 117

Zeroeightfifteen
07.01.2006, 13:45
In deinem Programm kenn ich mich irgendwie gar nicht aus. Wo empfängst du das Byte? gibts da nich solche Befehle Receive?

Edit: Könntest du mir noch zeigen wie ich vom Slave auch senden kann? Die Hilfe in Bascom kann man da ja vergessen.
Ich hab jetzt dieses Programm hergenommen:

$regfile = "M32def.dat" ' the used chip
$crystal = 16000000 ' frequency used
$baud = 9600 ' baud rate


$lib "i2c_twi.lbx" ' we do not use software emulated I2C but the TWI


Config Scl = Portc.0 ' we need to provide the SCL pin name
Config Sda = Portc.1 ' we need to provide the SDA pin name

'On the Mega8, On the PCF8574A
'scl=PC5 , pin 28 pin 14
'sda=PC4 , pin 27 pin 15


I2cinit ' we need to set the pins in the proper state


Config Twi = 100000 ' wanted clock frequency
'will set TWBR and TWSR
'Twbr = 12 'bit rate register
'Twsr = 0 'pre scaler bits

Dim B As Byte , X As Byte
Print "TWI master"
Do
Input B ' increase value
I2csend &H40 , B ' send the value
Print "Error : " ; Err ' show error status
I2creceive &H41 , X ' get a byte
Print X ' show error
Print "Error" ; Err
Waitms 500 'wait a bit
Loop
End

Doch wenn ich X empfangen will empfängt er nur 65 doch Err ist 0. Das bedeutet doch dass kein fehler aufgetreten ist?
Das Byte B finde ich im Slave ja gar nicht. Wie empfängt der denn das?

Wie kommst du denn aus der Hauptschleife wieder heraus?
Ich habe das Programm mal Simuliert. Der hüpft ja kreuz und quer durchs Programm. Was soll denn dann das Do Loop in der Hauptschleife?

Twcr = &B00000100
Twcr = &B01000100
das ist wohl auch doppelt oder?

Welche Adresse hat denn der Master?

So das waren jetzt etwas viel Fragen aber sonst blick ich da nie durch.

linux_80
07.01.2006, 15:45
Im Slave wird das Byte direkt aus dem register TWDR geholt, siehe Kommentar.

Wie ich schon beschrieben habe, kann der SlaveCode so wie er jetzt ist, nichts senden, weil das da nicht vorgesehen ist.

Warum soll ich aus der Hauptschleife heraus, es gibt sonst nix zu tun ?
Die schleife wird immer durchlaufen und überprüft ob TWI-seitig was anliegt, wenn über TWI ein Byte angekommen ist, wird das Byte an PortD angezeigt.

Der Master hat keine Adresse, weils eben der Master ist.

Lese Dir mal im Wiki die I2C Seiten durch, sonst muss ich hier alles nochmal erzählen.

Wenn du eine Eierlegende Wollmilchsau in Sachen I2C haben willst, musst Du die Lib von Bascom ans laufen bekommen, dann muss man nicht denken, und alles läuft fast von selber, und es gibt schöne funktionen zum aufrufen.

linux_80
07.01.2006, 15:52
Twcr = &B00000100
Twcr = &B01000100
das ist wohl auch doppelt oder?

Doppelt ist etwas, wenns zweimal dasgleiche ist, ist hier aber nicht der Fall !

Man kann sich evtl. darüber streiten wie man das macht, hier ist es schön der Reihe nach eingestellt.

Zeroeightfifteen
07.01.2006, 16:13
zum thema I2C steht in der Wiki nicht viel drin. Da wird ja nur beschrieben wie das mit SCL und SDA ist aber solche sachen wie Twar, Twcr, Twdr nicht dran. Wie kann dann der Atmega die Unterprogramme (TWi als Slave aktivieren, Schaun ob was gekommen ist, warten bis TWINT gesetzt ist) aufrufen? Die muss er ja auch verarbeiten?

linux_80
07.01.2006, 17:37
In jedem Datenblatt von Atmel zu den AVR Megas steht ausführlich drinnen wie man mit den Registern umgeht, Kapitel Two Wire Serial Interface kurz -> TWI . Das ist bei allen Megas gleich.

hier die Seite der Datasheets, einfach eins nehmen von einem Mega der TWI hat (M8, M16, M32, ...):
http://www.atmel.com/dyn/products/datasheets.asp?family_id=607#760

Zeroeightfifteen
09.01.2006, 17:18
Danke für den Link aber Englisch ist nicht meine stärke. Ich bestell mir jetzt mal das Buch von Roland Walter. Vielleicht steht da etwas brauchbares drin.

Sven04
11.01.2006, 21:16
Hi Leute,

bin so newby bei dem Thema TWI aber könnt ihr mir ma sagen ob ich mit euren programmcodes jetzt einfach die scl und sda leitungen meiner atmega32 verbinden kann und loslegen senden oder brauch ich noch irgendwelche anderen bauteile dazu?


Mfg
Sven

linux_80
11.01.2006, 23:18
Es braucht dazu nur 2 Widerstände um die Leitungen mit 'nem Pullup zu versehen. ansonsten mind. drei Kabel um zwei I2C Bauteile miteinander zu verbinden.

linux_80
15.01.2006, 23:16
Hallo,

zum Thema TWI habe ich wieder eine Seite gebaut:
https://www.roboternetz.de/wissen/index.php/TWI_Praxis

Darin enthalten sind erstmal nur die Grundkommunikationsarten, an einem der folgenden Wochenenden wird das wieder erweitert.

patti16
19.01.2006, 11:51
also klappt das jetzt reintheoretisch nur mit dem chip den du da hast ?

linux_80
19.01.2006, 21:27
Warum theoretisch ?
Bei mir gehts auch praktisch,
ich hab einen Mega 32 und einen Mega8 zusammengehängt,
geht in beide Richtungen, also egal wer der Slave/Master ist.

Wenns mehr als 2 Teilnehmer werden sollen, muss man nur auf die Slaveadressen achten, damit da schon keine doppelt ist, gibt ansonsten keine Probleme.

Verwenden kann man das mit allen AVR Megas die TWI haben:
http://www.atmel.com/dyn/products/param_table.asp?family_id=607&OrderBy=part_no&Direction=ASC

Wenn man die Codeschnipsel von dieser Seite richtig zusammenbringt, kann man alle möglichen kombinationnen der I2C-Kommunikation damit in einem Programm machen:
https://www.roboternetz.de/wissen/index.php/TWI_Praxis
So wie die Programme auf der Seite jetzt sind, kann man nur das machen wie's dort dabei steht.

patti16
19.01.2006, 22:01
ja das ist schon klar wollte das nur nochmal hören ok

gut gut werde das dann auch mal probieren

patti16
23.01.2006, 20:31
hallo

praktisch könnte man bei dem master dann doch das input y weg lassen und es würde doch trotzdem klappen oder?

und wie sieht das aus dem Slave könnte ich da öfters Twdr und INCR schreiben nur mit anderen buchstaben die dann andere zahlen ausgibt müsste doch klappen oder muss man das anders hinschreiben?

etwa so
Twdr = C
Twdr = D
Twdr = E ' neue Daten ausgeben
Incr E
Incr D
Incr C



oder so




i2cinit
i2cstart
i2cwbyte(slaveid)
i2cwbyte(wert1)
i2cwbyte(wert2)
i2cstop

gruß
patrick

linux_80
23.01.2006, 20:41
Du kannst immer nur ein Byte senden, wenn das TWDR ein paar mal hintereiander beschrieben wird, stört das zwar nicht, wird aber deshalb noch nicht übertragen, erst wenn man im TWCR das Bit setzt, wird ein Byte gesendet, dann muss man warten auf den nächsten Status, dann kann das nächste Byte kommen.
Man kann sich da also eine schleife bauen, die man beliebieg oft wiederholen kann um ein Byte zu senden, aber nur solange der Status nach jedem einzelnen Byte stimmt.

patti16
23.01.2006, 20:52
hmmmmm............ haste ein beispiel wie sone schleife aussehen könnte mir würde im moment nur so was einfallen:


Twdr = E
Incr E

waitms 10

twdr = d
incr d

meinste sowas?

stehe im moment etwas auf dem schlauch

gruß
patrick

linux_80
23.01.2006, 21:17
Da schleift noch nix !

Schleife hab ich grad keine da.

So wie Du oben mit den i2c-befehlen gemacht hast sollte es für den Master gehen.

Und wait gehört da auf keine Fall hin, denn das Blockiert dann den ganzen Bus für die Zeit ! [-X

Und wie gesagt, wenn man nur ein paarmal hintereinander ins TWDR schreibt passiert sonst noch nix, es wird so nix versendet!
Damit der Wert in TWDR auch raus geht muss in TWCR das Bit TWINT gesetzt werden, und dann wieder warten bis es wirklich draussen ist, dann Status abfragen, usw.

patti16
23.01.2006, 21:19
ok mal sehen wie ich das hin bekomme wenn nicht melde ich mich nochmal.

gruß
patrick

HansHans
30.08.2006, 12:26
Hallo,
das mit dem Hardware TWI unter Bascom geht ja mit diesem Programm
so gut das ich mich frage warum ich die I2C_TWI.LBX bestellt habe ....

Aber ich wollte das abholden der Daten mit Interrupts machen ,
das müsste ja gehen (mega8), da in der m8def.dat
TWI angelegt ist, aber bei mir funktioniert es leider nicht
eine Idee ?
Was mache ich falsch ?
oder ist der TWI Interrupt doch gesperrt das man die TWI slave library kaufen muss ?
Danke für eine Hilfe

so versuche ich es (wir auch so von Bascom angenommen und ohne Fehlermeldung kompiliert):


On Twi Twi_isr
Enable Twi
Enable Interrupts
.
Program:
.
.
Goto Program



Twi_isr:
.
Wird leider nie aufgerufen
.
.
Return

HansHans
03.09.2006, 19:33
Hallo,
mein Problem ist gelöst, ich habe meinen Fehler gefunden .
Habe übersehen das an anderer stelle im Prog das TWIE im TWCR
zurückgesetzt wird .
Hab’s korrigiert und jetzt läuft der Aufruf per Interrupt so wie er soll .

coCo
03.12.2006, 17:32
Hi,
tut mir Leid, dass ich noch in diesen alten Thread etwas poste, aber ich hab ne Frage. Wenn ich das ganze über Interrupt laufen lassen will, so wie HansHans, muss ich dann in der ISR einfach das TWDR Register auslesen oder muss da noch etwas anderes passieren (TWSR zurücksetzen oder so)? Ich habe ein Programm geschrieben, das in der ISR einfach das TWDR Register ausliest. Allerdings erhalte ich dadurch nicht die gesendeten Werte, sondern jedes mal den Wert "64".

Hoffe mir kann jemand helfen.

MfG

linux_80
03.12.2006, 20:02
Normalerweise TWSR auslesen und anhand des Status drauf reagieren,
so ähnlich wie in den Beispielen im Wiki,
wenn ein Byte gekommen ist, dieses erst auslesen aus TWDR,
zum Schluss, und damit es auch weitergeht, muss man zB. noch ein ACK oder NACK ausgeben, in dem man das entsprechende Flag in TWCR setzt, oder eben nicht,
incl. das Flag TWINT, denn erst wenn TWINT gesetzt wird gehts wirklich weiter, auf dem I2C-Bus.

linux_80
21.01.2007, 14:52
Hallo,

da die Beispiele im Wiki wohl nicht immer so ganz optimal für Einsteiger zu überschauen sind, bzw. für den weiteren Ausbau etwas zu einfach gehalten sind, hab ich ein Beispiel zusammengebaut, in dem das RN-Mega8 I2C-Slave ist, und das RN-Control Mega32 der Master.
Der Master ist per UART mit dem PC verbunden, über den man Daten eingeben kann, die dann zum I2C-Slave gesendet werden.
Am RN-Mega8 habe ich 2 Servos hängen, die entsprechend den Werten die man am PC eingibt positioniert werden.

I2C-Slave:

$regfile = "M8def.dat" ' the used chip
$crystal = 16000000 ' frequency used
'$baud = 9600 ' brauchen wir nicht

Waitms 100

' TWI init
Gosub Twi_init_slave

Config Servos = 2 , Servo1 = Portb.1 , Servo2 = Portb.2 , Reload = 8

' Ports für Servo auf Ausgang
Config Portb.1 = Output
Config Portb.2 = Output
Config Portd = Output

' Musik, wegen Stimmung usw. :-)
Sound Portb.0 , 300 , 450 ' BEEP

Servo(1) = 100
Servo(2) = 100

Const Maxanzahlbyte = 10 ' Wenn mehr Zeichen kommen werden diese verworfen !
Dim Messagebuf(maxanzahlbyte) As Byte
Dim Anzahlbuf As Byte ' Anzahl Zeichen die gesendet wurden

Dim Neuemsg As Byte ' zeigt an wenn eine neue Message gültig ist

Dim Twi_control As Byte ' Controlregister lokale kopie
Dim Twi_status As Byte
Dim Twi_data As Byte

Const Eigene_slave_adr = &H40 ' Adresse evtl. Anpassen

' wegen der Servos, TWI braucht das hier nicht
Enable Interrupts

Twi_data = 0
Neuemsg = 0 ' Paket ungültig
Anzahlbuf = 0 ' Anzahl empfangener Bytes

Portd = &HFF ' alle LEDs aus

'Print "M8 servo test"
Do

' schauen ob TWINT gesetzt ist
Twi_control = Twcr And &H80 ' Bit7 von Controlregister

If Twi_control = &H80 Then
Twi_status = Twsr And &HF8 ' Status

Portd = Not Twi_status ' test auf die LEDs

Select Case Twi_status

' Slave Adress received, wir sind gemeint !
Case &H60 :
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK
Anzahlbuf = 0
Neuemsg = 0 ' Flag für Message ungültig

' Byte mit ACK
Case &H80 :
If Anzahlbuf < Maxanzahlbyte Then
Incr Anzahlbuf ' zähler +1
Messagebuf(anzahlbuf) = Twdr
End If
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK

' Stop oder restart empfangen
Case &HA0 :
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK
' es müssen 3 Byte sein, damit das Paket OK ist
If Anzahlbuf = 3 Then
Neuemsg = 1 ' Flag für Message gültig
Else
Neuemsg = 0 ' Flag für Message ungültig
End If

' letztes Byte mit NACK, brauchen wir nicht
Case &H88 :
Case &HF8 :
' Fehler, dann reset TWI
Case &H00 :
Twcr = &B11010100 ' TWINT löschen, reset TWI

' was anderes empfangen, sollte nicht vorkommen
Case Else :
Twcr = &B11000100 ' TWINT löschen, erzeugt ACK

End Select

End If

' ein gültiges Paket angekommen
If Neuemsg = 1 Then
Neuemsg = 0 ' Flag wieder löschen
' nur wenn das erste Zeichen ein "S" ist tun wir was damit !
If Messagebuf(1) = "S" Then
Servo(messagebuf(2)) = Messagebuf(3)
Sound Portb.0 , 300 , 450 ' Roger-BEEP
End If
End If

Waitms 10

Loop

End

' TWI als slave aktivieren
Twi_init_slave:
Twsr = 0 ' status und Prescaler auf 0
Twdr = &HFF ' default
Twar = Eigene_slave_adr ' Slaveadresse setzen
Twcr = &B01000100 ' TWI aktivieren, ACK einschalten
Return
Angepasst werden kann die Slaveadresse mit Eigene_slave_adr,
und die max. Grösse des Paketes bei Maxanzahlbyte.

I2C-Master:

$regfile = "M32def.dat" ' the used chip
$crystal = 16000000 ' frequency used
$baud = 9600

$lib "i2c_twi.lbx" ' Für Hardware TWI

Waitms 100

Config Twi = 400000 ' setzt die TWI-Register
' Twsr = 0 ' Status reset
' Twbr = 12 ' Bus Geschwindigkeit 400kHz @ 16MHz
TWCR = &B00000100 ' TWI Modul aktivieren, nur TWEN

Dim Nr As Byte ' Servo-Nr
Dim Position As Byte ' Position

Const Servom8w = &H40 ' Slaveadresse
Const Servom8r = &H41

Sound Portd.7 , 300 , 450 ' BEEP

' Startausgabe
Print
Print "TWI Master Servo einstellen"

Print "Nr. und Wert fuer Servo eingeben :"

Do

Print "Nr : " ;
Input Nr
Print "Position : " ;
Input Position

' Es gibt nur 2 Servos mit Nr 1 und 2
If Nr > 0 And Nr < 3 Then

I2cstart
I2cwbyte Servom8w
I2cwbyte &H53 ' "S" Kennzeichen für Servo ansteuern
I2cwbyte Nr
I2cwbyte Position
I2cstop

' Fehler-Flag ausgeben, sollte immer 0 sein, dann war kein Fehler
Print "Err " ; Err
End If

Loop

End
Angepasst werden muss nur die Slaveadresse bei Servom8w.
Da vom Slave nichts gelesen werden kann braucht man die Lese-Adresse eigentlich nicht.
Evtl. kann man die Busgeschwindigkeit bei TWBR ändern, falls andere Quarz- oder Busfrequenzen gewünscht sind. Verwendet man Config TWI = .. rechnet das Bascom für einen aus, Anhand der Angabe bei $crystal.

Das Telegramm-Paket, dass der Master zum Slave sendet ist so aufgebaut:
1. Zeichen: ein "S" (grosses S) als Kennzeichen das ein Servo angesteuert werden soll, alle anderen werden verworfen,
2. Zeichen: die Servo-Nr
3. Zeichen: die Position des Servos, theoretisch von 0 bis 255, aber je nach Servo meistens im Bereich von 50 bis 200 !

Die Funktion des Slave nochmal als Text:
In der Do..Loop-Schleife wird immer das Flag TWINT geprüft, das anzeigt, dass Daten über TWI angekommen sind, anschließend wir der Status aus TWSR ausgelesen, und per Select..Case entsprechend verzweigt, da wir hier nur einen Slave-Receiver haben, braucht man nur die hier angegebenen Statuscodes verwenden.
Wird nach einer Start-Sequenz die eigene Slaveadresse angesprochen wird der Zähler für die Anzahl der empfangenen Zeichen auf 0 zurückgesetzt.
Es wird grundsätzlich jedes Byte mit ACK quittiert egal ob der Puffer schon voll ist oder nicht, ist der Puffer voll werden die nachfolgenden Bytes verworfen !
Wird ein STOP oder RESTART empfangen, wird ein weiteres Flag gesetzt (Neuemsg) falls die Paketgrösse passt, ansonsten ist das Pakte ungültig und wird verworfen. Will man unterschiedliche Paketgrössen empfangen, muss man diese Abfrage natürlich hier rausnehmen, und kann sich zB. nur an das 1. Zeichen im Paket halten was zu tun ist.
Ist das Flag Neuemsg auf 1, wird in der nächsten If-Abfrage die Auswertung des empfangenen Pakets gestartet, und das Flag wieder zurückgesetzt.
Beginnt das Paket mit einem "S" ist es für uns interessant, und wir stellen den entsprechenden Servo (aus Byte 2) auf den neuen Wert (aus Byte 3).
Jetzt ist die Schleife beendet, und es beginnt alles wieder von vorne, solange das Flag TWINT nicht gesetzt ist, muss sich der AVR nur um die PWM-Ausgabe für die Servos kümmern, das geschieht per ISR, und deshalb können wir hier die Do..Loop-Schleife endlos laufen lassen.

shurikn
16.03.2010, 07:44
Hallo Leute!

Erstmal muss ich sagen, dass ich hier viel über die TWI und auch allgemein über µC gelernt habe. Danke
Auch tut es mir Leid, dass ich ein 3 Jahre altes Thema wieder hervor nehme und eine Frage darüber stelle.

Schon seit 2 Tagen versuche ich es fertig zu bringen, dass mein atmega88 als Slave 2 oder mehrere Byte an meinem atmega32 Master über TWI zu versenden. Ein Byte konnte ich bisher erfolgreich, dank rn-wissen.de und dieses Thema, machen.

Ich bin wirklich verzweifelt, da wirklich viel darüber gelesen habe aber leider nichts darüber gefunden habe und ich nicht weiss ich das realisieren kann. (bin noch ein Anfänger)

Ich hoffe, dass ihr mir hier kurz einen Tipp, oder eine Anleitung dazu geben könnt, wie ich den Slave, evtl auch den Master programmieren muss, damit mehrere Bytes vom Slave versendet, bzw vom Master empfangen werden können.

Für eure Unterstützung bedanke ich mich bei euch.

Gruss
shurikn

StevieL
16.03.2010, 09:41
Hallo,

ich verwende auch das Grundprogramm aus den RN-Wissen.
Im Slave mache ich das so:



'Master will Byte haben
Case &HA8:
Twdr = Vers
Twcr = &B11000100
I = 0
'Master will weiteres Byte haben
Case &HB8:
Select Case I
Case 0
Twdr = Portstate
Case 1
Twdr = Proz
End Select
Incr I
Twcr = &B11000100


Im Master:


Dim Buf(3) As Byte
buf(1) = 0

I2creceive Slaveadr , Buf(1) , 1 , 3


Im Array Buf stehen danach meine Werte von Vers, Portstate und Proz aus dem Slave. Das "Select Case I" kannst du natürlich noch erweitern, je nach dem, wieviel Bytes du übertragen willst. Das Array buf müsste dann von der Länge her noch entsprechend angepasst werden und auch der letzte Parameter bei I2Creceive (Anzahl der zu empfangenden Bytes).

shurikn
16.03.2010, 15:09
Hallo StevieL

Danke für deinen Tipp! Ich werde morgen mal versuchen, dein Code zu verstehen und abzukupfern.

So, dann gehe ich mal ins Bett :D

Freundliche Grüsse aus Japan
Shurikn

shurikn
17.03.2010, 06:25
Hallo StevieL!

Das hat wunderbar geklappt, danke. Was bei mir jedoch nicht funktionierte ist, dass wenn ich Twcr = &B11000100 im Case habe (so wie bei deinem Code). Als ich den Twcr=&B11000100 heraus nahm und nach dem end select gesetzt habe funktioniert alles bestens.

Nochmals danke viel mals für deinen wertvollen Tipp.

Gruss
Shurikn