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.
Lesezeichen