-
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
-
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 .
-
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
-
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.
-
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:
Code:
$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:
Code:
$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.
-
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
-
Hallo,
ich verwende auch das Grundprogramm aus den RN-Wissen.
Im Slave mache ich das so:
Code:
'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:
Code:
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).
-
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
-
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