Hallo,

hab nun auch ein paar Tage frei, deshalb darf mein Tiny dran glauben

Wer sich mal versuchen will, ist die AppNote 312 als Bascom-Version.

Verändert werden sollte erstmal nix, ausser evtl. der Slaveadresse, und dem Soundausgang
Ansonsten kann für die Funktion nicht garantiert werden


Code:
' USI-I2C Testprogramm
' Slave @ $40
'
' mit Interrupt und ohne Timer

$regfile = "attiny2313.dat"
$crystal = 16000000
$baud = 9600
$hwstack = 40
'$framesize = 16
$swstack = 16

' Unterprogramme für die USI-Kommunikation
Declare Sub Usi_twi_slave_initialise()
Declare Sub Usi_twi_transmit_byte(zeichen As Byte)
Declare Function Usi_twi_receive_byte() As Byte

On Uci_start Usi_start_condition_isr , Nosave
On Uci_ovflw Usi_counter_overflow_isr , Nosave

' einige Aliases anlegen
Pout_usi_scl Alias Portb.7
Pin_usi_scl Alias Pinb.7
Ddr_usi_scl Alias Ddrb.7
Pout_usi_sda Alias Portb.5
Pin_usi_sda Alias Pinb.5
Ddr_usi_sda Alias Ddrb.5

Dim Usi_twi_errorstate As Byte                              ' eigener Fehlerstatus
' Array der Daten die übertragen werden
Dim Twi_txbuf(16) As Byte
Dim Twi_rxbuf(16) As Byte
' Zeiger auf Buffer
Dim Twi_rxhead As Byte
Dim Twi_rxtail As Byte
Dim Twi_txhead As Byte
Dim Twi_txtail As Byte

Dim Temp_usi As Byte
Dim Temp_usi_isr As Byte                                    ' Byte das in den ISRs verwendet wird
Dim Usi_twi_data_in_receive_buffer As Bit                   ' Flag ob Buffer Daten enthält
Dim Usi_twi_overflow_state As Byte

Const Twi_slaveaddress = &H40

' Möglichkeiten für Usi_twi_overflow_state
Const Usi_sl_check_address = 0
Const Usi_sl_send_data = 1
Const Usi_sl_req_reply_from_send_data = 2
Const Usi_sl_chk_reply_from_send_data = 3
Const Usi_sl_req_data = 4
Const Usi_sl_get_data_and_send_ack = 5

' Ausgänge für LEDs
Config Portb.6 = Output
Config Portb.2 = Output
Config Portb.1 = Output
Config Portb.0 = Output
Config Portd.6 = Output
Config Portd.4 = Output

Enable Interrupts                                           ' IRQs global erlauben

Call Usi_twi_slave_initialise

Waitms 500                                                  ' Sicherheitspause nach Reset

Sound Portd.5 , 300 , 450                                   ' BEEP

Print
Print "USI Slavetest"

' Hauptprogramm
Do

    Gosub Check_if_data_in_receive_buf
    If Usi_twi_data_in_receive_buffer = 1 Then
        Temp_usi = Usi_twi_receive_byte()

        ' Wert an LEDs anzeigen
        Portb.6 = Temp_usi.5
        Portb.2 = Temp_usi.4
        Portb.1 = Temp_usi.3
        Portb.0 = Temp_usi.2
        Portd.6 = Temp_usi.1
        Portd.4 = Temp_usi.0

        Temp_usi = Not Temp_usi
        Print Temp_usi
        'Usi_twi_transmit_byte(Temp_usi)
    Else
'        Print "nix"
        Waitms 100
    End If

'Print Twi_rxhead ;
'Print " ";
'Print Twi_rxtail ;
'Print " ";
'Print Twi_txhead ;
'Print " ";
'Print Twi_txtail

Loop

End


' Unterprogramme

' Initialise USI for TWI Slave mode.
Sub Usi_twi_slave_initialise()
    Gosub Flush_twi_buffers                                 ' Flushes the TWI buffers

    ' Direction Out
    Ddr_usi_scl = 1
    Ddr_usi_sda = 0                                         ' SDA Input
    ' Release SCL & SDA
    Pout_usi_scl = 1
    Pout_usi_sda = 1

    ' Preload dataregister with "released level" data.
    Usidr = &HFF

    ' Enable Start Condition Interrupt. Disable Overflow Interrupt.
    ' Set USI in Two-wire mode. No USI Counter overflow prior
    ' To First Start Condition(potentail Failure)
    ' Shift Register Clock Source = External , Positive Edge
    Usicr = &B10101000

    ' Clear flags, and reset counter.
    Usisr = &B11110000

End Sub

' Puts data in the transmission buffer, Waits if buffer is full.
Sub Usi_twi_transmit_byte(zeichen As Byte)

    Local Tmphead As Byte

    ' Calculate Buffer Index.
    Tmphead = Twi_txhead + 1
    Tmphead = Tmphead And &H0F

    ' Wait for free space in buffer.
    While Tmphead = Twi_txtail
    Wend

    Twi_txbuf(tmphead + 1) = Zeichen                        ' Store Data In Buffer.
    Twi_txhead = Tmphead                                    ' Store new index.

End Sub


' Returns a byte from the receive buffer. Waits if buffer is empty
Function Usi_twi_receive_byte() As Byte

    Local Tmptail As Byte

    ' warten bis etwas im Buffer steht
    While Twi_rxhead = Twi_rxtail
    Wend

    ' Tmptail =(twi_rxtail + 1 ) & Twi_rx_buffer_mask;
    ' Calculate buffer index
    Tmptail = Twi_rxtail + 1
    Tmptail = Tmptail And &H0F
    Twi_rxtail = Tmptail                                    ' Store new index

    Usi_twi_receive_byte = Twi_rxbuf(tmptail + 1)           ' Return data from the buffer.
End Function


' ISR für Startsequenz erkannt
Usi_start_condition_isr:
$asm
    PUSH    R16
    PUSH    R20
    PUSH    R24
    PUSH    R25
    PUSH    R26
    IN      R24,&H3F
    PUSH    R24
$end Asm
    ' Code
    Usi_twi_overflow_state = Usi_sl_check_address
    Ddr_usi_sda = 0                                         ' Enable SDA as input.

    ' Wait for SCL to go low.
    ' If a Stop condition arises then leave the interrupt to prevent waiting forever.
    While Pin_usi_scl = 1 And Usisr.5 = 0                   ' USIPF
    Wend

    ' Enable Overflow and Start Condition Interrupt. (Keep StartCondInt to detect RESTART)
    ' Set USI in Two-wire mode.
    ' Shift Register Clock Source = External, positive edge
    Usicr = &B11111000

    ' Clear flags, and reset counter.
    Usisr = &B11110000

$asm
    POP     R24
    Out &H3F , R24
    POP     R26
    POP     R25
    POP     R24
    POP     R20
    POP     R16
$end Asm
Return

' ISR für Counteroverflow
Usi_counter_overflow_isr:
$asm
    PUSH    R10
    PUSH    R16
    PUSH    R20
    PUSH    R24
    PUSH    R26
    IN      R24,&H3F
    PUSH    R24
$end Asm
    ' Code
    'Print Usi_twi_overflow_state
    Select Case Usi_twi_overflow_state

        ' -- Address mode --
        ' Check address and send ACK (and next USI_SL_SEND_DATA) if OK, else reset USI.
        Case Usi_sl_check_address :
            Temp_usi_isr = Usidr And &HFE                   ' 0. Bit ausblenden falls RW gleich 1
            If Temp_usi_isr = Twi_slaveaddress Then
                ' Read oder Write ? 1 - Master will was von uns haben
                If Usidr.0 = 1 Then
                    Usi_twi_overflow_state = Usi_sl_send_data
                Else
                    Usi_twi_overflow_state = Usi_sl_req_data
                End If
                Gosub Set_usi_to_send_ack
            Else
                Gosub Set_usi_to_twi_start_cond_mode
                'Print "nicht ich"
            End If

        ' -- Master write data mode --
        ' Check reply and goto USI_SL_SEND_DATA if OK, else reset USI.
        Case Usi_sl_chk_reply_from_send_data :
            ' If NACK, the master does not want more data.
            If Usidr = 0 Then
                Gosub Set_usi_to_twi_start_cond_mode
                Goto Fertig_usi_counter_overflow_isr
            Else
                ' From here we just drop straight into USI_SL_SEND_DATA if the master sent an ACK
                If Twi_txhead <> Twi_txtail Then
                    ' Twi_txtail = (twi_txtail + 1 ) And Twi_tx_buffer_mask
                    Temp_usi_isr = Twi_txtail + 1
                    Temp_usi_isr = Temp_usi_isr And &H0F
                    Twi_txtail = Temp_usi_isr

                    Usidr = Twi_txbuf(temp_usi_isr + 1)

                Else
                    ' If the buffer is empty then:
                    Gosub Set_usi_to_twi_start_cond_mode
                    Goto Fertig_usi_counter_overflow_isr
                End If

                Usi_twi_overflow_state = Usi_sl_req_reply_from_send_data
                Gosub Set_usi_to_send_data
            End If

        ' Copy data from buffer to USIDR and set USI to shift byte. Next USI_SL_REQ_REPLY_FROM_SEND_DATA
        Case Usi_sl_send_data :
            If Twi_txhead <> Twi_txtail Then
                ' Twi_txtail = (twi_txtail + 1 ) And Twi_tx_buffer_mask
                Temp_usi_isr = Twi_txtail + 1
                Temp_usi_isr = Temp_usi_isr And &H0F
                Twi_txtail = Temp_usi_isr

                Usidr = Twi_txbuf(temp_usi_isr + 1)

            Else
                ' If the buffer is empty then:
                Gosub Set_usi_to_twi_start_cond_mode
                Goto Fertig_usi_counter_overflow_isr
            End If

            Usi_twi_overflow_state = Usi_sl_req_reply_from_send_data
            Gosub Set_usi_to_send_data

        ' Set USI to sample reply from master. Next USI_SL_CHK_REPLY_FROM_SEND_DATA
        Case Usi_sl_req_reply_from_send_data :
            Usi_twi_overflow_state = Usi_sl_chk_reply_from_send_data
            Gosub Set_usi_to_read_ack

        ' -- Master read data mode --
        ' Set USI to sample data from master. Next USI_SL_GET_DATA_AND_SEND_ACK.
        Case Usi_sl_req_data :
            Usi_twi_overflow_state = Usi_sl_get_data_and_send_ack
            Gosub Set_usi_to_read_data

        ' Copy data from USIDR and send ACK. Next USI_SL_REQ_DATA
        Case Usi_sl_get_data_and_send_ack :
            ' Put data into Buffer
            ' Twi_rxhead = (twi_rxhead + 1 ) & Twi_rx_buffer_mask

            Temp_usi_isr = Twi_rxhead + 1
            Temp_usi_isr = Temp_usi_isr And &H0F
            Twi_rxhead = Temp_usi_isr

            Twi_rxbuf(temp_usi_isr + 1) = Usidr

            Usi_twi_overflow_state = Usi_sl_req_data
            Gosub Set_usi_to_send_ack


    End Select

Fertig_usi_counter_overflow_isr:
$asm
    POP     R24
    Out &H3F , R24
    POP     R26
    POP     R24
    POP     R20
    POP     R16
    POP     R10
$end Asm
Return

' Einstellungen für Read und Write

'
Set_usi_to_twi_start_cond_mode:
    ' Enable Start Condition Interrupt. Disable Overflow Interrupt
    ' Set USI in Two-wire mode. No USI Counter overflow hold.
    ' Shift Register Clock Source = External, positive edge
    Usicr = &B10101000

    'Clear all flags, except Start Cond
    Usisr = &B01110000

Return

'
Set_usi_to_send_ack:
    Usidr = 0                                               ' Prepare ACK
    Ddr_usi_sda = 1                                         ' Set Sda As Output

    ' Clear all flags, except Start Cond
    ' Set Usi Counter To Shift 1 Bit
    Usisr = &B01111110

Return

'
Set_usi_to_read_ack:
    Ddr_usi_sda = 0                                         ' Set Sda As Intput

    Usidr = 0                                               ' Prepare ACK

    ' Clear all flags, except Start Cond
    ' set USI counter to shift 1 bit
    Usisr = &B01111110

Return

'
Set_usi_to_send_data:
    Ddr_usi_sda = 1                                         ' Set Sda As Output

    ' Clear all flags, except Start Cond
    ' set USI to shift out 8 bits
    Usisr = &B01110000

Return

'
Set_usi_to_read_data:
    Ddr_usi_sda = 0                                         ' Set Sda As Intput

    ' Clear all flags, except Start Cond
    ' set USI to shift out 8 bits
    Usisr = &B01110000

Return

'
Check_if_data_in_receive_buf:
    If Twi_rxtail <> Twi_rxhead Then
        Usi_twi_data_in_receive_buffer = 1
    Else
        Usi_twi_data_in_receive_buffer = 0
    End If
Return

' hauwech
Flush_twi_buffers:
    Twi_rxtail = 0
    Twi_rxhead = 0
    Twi_txtail = 0
    Twi_txhead = 0
Return
Der Testaufbau schaut so aus:
Die LEDs links auf dem RN-Control, sind von oben die ersten beiden für den I2C-Bus, der Rest ist für die Anzeige der Daten, die vom RN-Mega8 gesendet werden.

Der Mega8 liest die Temperatur vom DS1621, und gibt den Wert an einen PCF8574 weiter, der Tiny2313 spielt eben diesen vor, und gibt den Wert an den 6 LEDs aus.
Das Muster ist dasselbe wie auf dem RN-M8 LEDs unten.

Testprogramm auf dem RN-M8 ist dieses vom Wiki:
https://www.roboternetz.de/wissen/in...it_und_Receive


€dit:
Ich hab die If-Abfrage (Zeile 236-237) umgebaut, da der Slave nicht auf ein Master-Read reagiert hat, so geht das jetzt auch. (Falls was im Puffer steht)