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:
Angepasst werden kann die Slaveadresse mit Eigene_slave_adr,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
und die max. Grösse des Paketes bei Maxanzahlbyte.
I2C-Master:
Angepasst werden muss nur die Slaveadresse bei Servom8w.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
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.







Zitieren

Lesezeichen