Hallo,
ich bin dabei eine Wandfackel zu konstruieren, die sich über den I2C bzw. TWI steuern lässt. Um die verschiedenen Modi auszuwählen ist es teilweise nötig meherer Bytes zu übertragen.
Beispiel: Lichtfarbe + Blinkfrequenz im Stroboskopmodus.
Zu diesem Zweck habe ich mich in die RN Artikel zu den Thema eingelesen und auch einen funktionsfähigen Code geschrieben bzw. umgeschrieben:
TWI Slave:
Code:
' Wandfackel Bacom
$regfile = "m16def.dat" ' the used chip
$crystal = 8000000 ' frequency used
' $baud = 9600 ' keine baud rate angeben !
Config Timer2 = Timer , Prescale = 1024
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down , Prescale = 64
'Die Timer starten
On Timer2 Timer_ir
Enable Interrupts
Enable Timer1
Enable Timer2
Start Timer1
Start Timer2
Timer2 = 247
Dim Temp As Byte
Dim Twi_control As Byte ' Controlregister lokale kopie
Dim Twi_status As Byte
Dim Twi_data As Byte
Dim Count As Byte ' Testwert, jedes mal +1
Dim Timer_preload As Byte
Dim Control As Byte ' Flag, bestimmt die aktuelle Aktion
Dim Color_management As Byte
Red Alias Pwm1a
Green Alias Pwm1a
Blue Alias Pwm1a
'###############################################################################
'Abschnitt linear Fader
Dim Linfade_count As Byte
Dim Linfade_waitms As Byte
Dim Linfade_counter As Byte
'Default Settings
Linfade_count = 255 ' VCC/255 Helligkeitsstufen
Linfade_waitms = 5 'Wartet nach jeder Helligkeitsstufe 5 ms
'Abschnitt Zufallsfader
Declare Sub Cycle(farbe_start As Byte , Farbe_end As Byte)
Dim I As Byte 'Zaehlvariable
Dim Indfade_area As Byte 'Zaehlvariable
Dim Indfade_waitms As Byte 'Warteschleife
Dim Farbe_out As Byte
Dim Indfade_begin As Byte 'Anfangsfarbe
Dim Indfade_end As Byte 'endfarbe
'Default Settings
Indfade_area = 255 ' Anzahl der PWM Abstufungen da 8 bit nur 255 Abstufungen mglich
Indfade_waitms = 5 'Pause zwischen den einzelnen Schritten (in mS)
'Abschnitt Stroboskop
Dim Strobo_ontime As Byte
Dim Strobo_offtime As Byte
Dim Strobo_helligkeit As Byte
'Default Settings
Strobo_helligkeit = 255
Strobo_ontime = 50
Strobo_offtime = 100
'Dimmen
Dim Dim_helligkeit As Byte
'Default Settings
Dim_helligkeit = 126
'###############################################################################
Declare Sub Twi_init_slave
' Werte zurcksetzen
Count = 0
Twi_data = 0
Call Twi_init_slave ' TWI aktivieren
Timer_preload = 247
Color_management = 1
' Hauptschleife
Do
Select Case Control 'Fader aktivieren: aus-->an-->aus-->an usw.
' Linearfader
Case 1: '255: 100 %
For Linfade_counter = 0 To Linfade_count Step 1 '0 : 0 %
Select Case Color_management
Case 1 : Red = Linfade_counter
Case 2 : Green = Linfade_counter
Case 3 : Blue = Linfade_counter
End Select
Waitms Linfade_waitms
Next
For Linfade_counter = Linfade_count To 0 Step -1
Select Case Color_management
Case 1 : Red = Linfade_counter
Case 2 : Green = Linfade_counter
Case 3 : Blue = Linfade_counter
End Select
Waitms Linfade_waitms
Next
' Zufallsfader
Case 2:
Indfade_begin = Indfade_end 'Startfarbe ist immer die alte Zielfarbe
Indfade_end = Rnd(indfade_area) 'Zielfarbe ist immer Zufall
For I = 0 To Indfade_area
Call Cycle(indfade_begin , Indfade_end)
Select Case Color_management
Case 1 : Red = Farbe_out
Case 2 : Green = Farbe_out
Case 3 : Blue = Farbe_out
End Select
Waitms Indfade_waitms
Next
'Stroboskop
Case 3:
Select Case Color_management
Case 1 : Red = 0
Case 2 : Green = 0
Case 3 : Blue = 0
End Select
Waitms Strobo_ontime
Select Case Color_management
Case 1 : Red = Strobo_helligkeit
Case 2 : Green = Strobo_helligkeit
Case 3 : Blue = Strobo_helligkeit
End Select
Waitms Strobo_offtime
'Anschalten
Case 4:
Select Case Color_management
Case 1 : Red = 0
Case 2 : Green = 0
Case 3 : Blue = 0
End Select
'Ausschalten
Case 5:
Select Case Color_management
Case 1 : Red = 255
Case 2 : Green = 255
Case 3 : Blue = 255
End Select
'Helligkeit Dimmen
Case 6:
Select Case Color_management
Case 1 : Red = Dim_helligkeit
Case 2 : Green = Dim_helligkeit
Case 3 : Blue = Dim_helligkeit
End Select
End Select
Loop
End
' Unterprogramme
' TWI als slave aktivieren
Sub Twi_init_slave
Twsr = 0 ' status und Prescaler auf 0
Twdr = &HFF ' default
Twar = 11 ' Slaveadresse setzen
Twcr = &B01000100 ' TWI aktivieren, ACK einschalten
End Sub
Timer_ir:
Timer1 = Timer_preload
' schauen ob TWINT gesetzt ist
Twi_control = Twcr And &H80 ' Bit7 von Controlregister 10000000
If Twi_control = &H80 Then '10000000
Twi_status = Twsr And &HF8 ' Status /11111000
' wurde ein Byte geschickt
If Twi_status = &H80 Or Twi_status = &H88 Then '10000000 // 10001000
Twi_data = Twdr ' neue Daten merken
If Twi_data = 1 Then
Control = 2
Twi_data = 0
End If
If Twi_data = 4 Then
Control = 5
Twi_data = 0
End If
End If
' TWINT muss immer gelscht werden, damit es auf dem Bus weiter geht
Twcr = &B11000100 ' TWINT lschen, mit ACK
End If
Return
'Farbverlauf
Sub Cycle(farbe_start As Byte , Farbe_end As Bit Byte)
Local Temp1 As Single
Local Temp2 As Single
Temp1 = I / Indfade_area
Temp2 = Temp1
Temp1 = 1 - Temp1
Temp1 = Temp1 * Farbe_start
Temp2 = Temp2 * Farbe_end
Farbe_out = Temp1 + Temp2
End Sub
TWI Master:
Code:
$regfile = "M32def.dat" ' the used chip
$crystal = 8000000 ' frequency used
$baud = 9600 ' baud rate
'I2C Read and Write
Declare Function Twi_read_byte(byval Slave As Byte) As Byte
Declare Sub Twi_send_byte(byval Slave As Byte , Zeichen As Byte)
'Twi Variablen
Dim Twi_control As Byte ' Controlregister lokale kopie
Dim Twi_status As Byte
Dim Twi_data As Byte
'Variablen fr Main loop
Dim B As Byte ' Zeichen von UART
Dim X As Byte
Dim Error As Byte ' Fehlermerker
Dim F As Byte
Dim Id As Byte
Dim Action As Byte
Dim I2csent As Byte
Dim Flag As Byte
' TWI Init
Twcr = &B00000100 ' erstmal nur TWI aktivieren
Twsr = 0 ' Status und Prescaler Register
Twbr = 32 ' Bit Rate Register, 100kHz
'##############################################################################
'##################### Main Loop ##############################################
'##############################################################################
Do
' Eingang RS232
B = Inkey()
If B = 49 Then
Print 99
End If
If B = 50 Then
Action = 1
Call Twi_send_byte(11 , Action)
End If
If B = 51 Then
Action = 11
Call Twi_send_byte(11 , Action)
End If
If B = 52 Then
Action = 12
Call Twi_send_byte(11 , Action)
End If
If B = 53 Then
Action = 13
Call Twi_send_byte(11 , Action)
End If
Loop
End
'##############################################################################
'##################### Twi send_byte ##########################################
'##############################################################################
' sendet ein Byte und schliesst die bertragung ab
Sub Twi_send_byte(byval Slave As Byte , Zeichen As Byte)
Error = 0 ' Fehler zurcksetzen
' Startbedingung
Twcr = &B10100100 ' TWINT
' warten bis TWINT gesetzt ist
Gosub Twi_wait_int
'################# Slave Adresse Senden ########################################
' wenn Zugriff auf den Bus erlaubt, Slaveadresse ausgeben
If Twi_status = &H08 Or Twi_status = &H10 Then
Twdr = Slave And &HFE ' slave adresse + Write
Twcr = &B10000100 ' TWINT lschen, Byte senden
' warten bis TWINT gesetzt ist
Gosub Twi_wait_int
'##################### Daten Senden ############################################
' Slave hat sich gemeldet
If Twi_status = &H18 Or Twi_status = &H20 Then
Twdr = 1 ' Daten
Twcr = &B10000100 ' TWINT lschen, Byte senden
' warten bis TWINT gesetzt ist
Gosub Twi_wait_int
' Zeichen wurden gesendet
If Twi_status = &H28 Or Twi_status = &H30 Then
Error = 0
Flag = 1 ' kein Fehler
Else
Error = Twi_status ' Fehler
End If
Else
' kein slave
Error = Twi_status ' Fehler
End If
If Flag = 1 Then 'falls daten erfolgreich gesendet
Twdr = 4 ' Daten
Twcr = &B10000100 ' TWINT lschen, Byte senden ' Wurde das erste Byte erfolgreich bertragen
Gosub Twi_wait_int
' Zeichen wurden gesendet
If Twi_status = &H28 Or Twi_status = &H30 Then
Error = 0 ' kein Fehler
Else
Error = Twi_status ' Fehler
End If
End If
'###############################################################################
' STOPbedingung kommt hier immer im Ablauf, egal welcher Status
Twcr = &B10010100 ' TWINT lschen, STOP senden
' nach einem STOP wird TWINT nicht mehr gesetzt,
' man darf/kann also nicht darauf warten !
'###############################################################################
Else
' Bus belegt, wird er wieder freigegeben
Twcr = &B10000100 ' TWINT lschen, Bus freigeben
Error = Twi_status ' Fehler
End If
End Sub
'##############################################################################
'##################### Twi init ###############################################
'##############################################################################
Twi_wait_int:
Do
Twi_control = Twcr And &H80
Loop Until Twi_control = &H80
Twi_status = Twsr And &HF8 ' status
' status nur zu Debugzwecken ausgeben, weil Bus sehr langsam wird !
' Print "Err " ; Hex(twi_status)
Return
Dies funktioniert bereits wunderbar, dennoch ein paar Fragen.
1. In den RN-Artikel wird der Inhalt des Status Registers eingelesen (TWSR) beziehungsweise die Bits 3-7. Mich würde interessieren, ob es irgendwo eine Aufstellung gibt, welche Bedeutung die einzelne Konstellation hat.
like: &H28 oder &H30 --> Zeichen wurde erfolgreich gesendet
Im Datenblatt des Atmega 32 habe ich leider keine Erklärung gefunden
Hat da evtl. jemand einen Tipp?
2. Bis beide Bytes bei meinem Beispiel gesendet wurden, vergehen etwa 1 Sekunde.
Mir ist bewusst, dass die Waitroutinen in der Main Schleife und der Aufruf der TWI Abfrage über den Timer (im ms-Takt) den Code ein wenig ausbremsen. Aber 1 Sekunde? Dauert es wirklich so lange bis der Slave sein Ack sendet?
3. Das TWINT Bit im Control Register (TWCR) wird ja gesetzt, wenn die Aktion "z.B. ein Byte senden" erfolgreich ausgeführt wurde. Setzt dies auch voraus, dass der Slave sein Ack gegeben hat. Ja oder???
Falls mir einer bei einen meiner Fragestellungen helfen könnte wäre ich ihm sehr dankbar.
Ich möchte hiermit ebenfalls den Autoren der RN-Artikel meinen herzlichen Dank aussprechen: Super Arbeit =D>
Grüße + fröhliche Weihnachten
hdtvfreak
Lesezeichen