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