Subversion Repositories group.electronics

Rev

Blame | Last modification | View Log | RSS feed

  list        p=16F84A
    include    "p16F84a.inc"
 
;***** CONFIGURATION
           __CONFIG _PWRTE_ON & _HS_OSC & _WDT_OFF
 
; pin assignments
    #define SDA         0           ; Pin 0
    #define SCL         1           ; Pin 1
    #define TRIS_SDA    TRISB,SDA
    #define TRIS_SCL    TRISB,SCL
    #define I2C_SDA     PORTB,SDA
    #define I2C_SCL     PORTB,SCL
    #define LED         PORTB,2
 
    #define I2C_SLAVE1 0x27
 
    CBLOCK     0CH
        counter
 
        _I
        byte_send
        i2c_addr
 
        i2c_ret         ; I2C Return Value
 
        dly_loop1       ; Loops for delays
        dly_loop2
    ENDC
 
    ORG 0
    goto start           ; jump over to main routine
 
;***** Initialisation
start
        ; configure ports
        clrw                    ; configure PORTB and PORTC as all outputs
        tris    PORTB
        clrf    PORTB
 
        movlw   b'00000000'     ; Init our counter
        movwf   counter
 
;***** Main loop
main_loop
        bsf     LED
        call    SendCount
        bcf     LED
 
        goto    main_loop
 
SendCount
 
        movlw   I2C_SLAVE1      ; 7-bit address of dev
        bcf     STATUS,C        ; Use Write mode ('0')
        call    I2C_Start       ; Start a transmission
        call    ReadAck         ; Wait for Ack from slave
        movf    i2c_ret         ; Check return value
        btfss   STATUS,Z        ; Goto SendEnd on NACK
        goto    SendErr
 
        movfw   counter         ; Copy byte to write (counter) to w
        call    I2C_Write       ; Write the byte to the line
        call    ReadAck            ; Should read byte from bus here
                                ;  checking that its a Nack
 
        call    I2C_End         ; End the packet
        bcf     LED
        incf    counter,f
        call    Delay_Short
        return
 
SendErr
        call    I2C_End
 
        ;call    Delay_Long      ; Wait a while before resend
        return
 
I2C_Start
        movwf   i2c_addr        ; Save the address in W
        rlf     i2c_addr,f      ; Attach '0' to 8th bit
        call    Start           ; Start the Trans
        movfw   i2c_addr
        call    I2C_Write       ; Write byte to port
        return
 
I2C_End
        call    Stop
        return
 
I2C_Write
        movwf   byte_send
        movlw   .8              ; 8 bits to send
        movwf    _I
_WriteBit
        rlf     byte_send,f        ; Move highest bit to C
        btfss   STATUS,C        ; If 'C' is clear
        call    SDA_Low         ;   -> Set data low
        btfsc   STATUS,C        ; If 'C' is set
        call    SDA_High        ;   -> Set data high
 
        call    SCL_Pulse
 
        decfsz  _I,f        ; Decrement counter, if not clear
        goto    _WriteBit         ;   -> Send next bit
        call    SDA_Low         ; Set low to allow slave to write
        return
 
Nack                            ; Clock a high SDA
        call    SDA_High
        call    SCL_Pulse
        return
 
Ack                            ; Clock a high SDA
        call    SDA_Low
        call    SCL_Pulse
        return
 
ReadAck
        call    SCL_High
        clrf    i2c_ret
        btfsc   I2C_SDA
        bsf     i2c_ret,0
        call    SCL_Low
        return
 
Start
        call    SDA_High
        call    SCL_High
        call    SDA_Low
        call    SCL_Low
        return
 
Stop                            ; Bring SDA high while Clock high
        call    SCL_Low
        call    SDA_Low
        call    SCL_High
        call    SDA_High
        return
 
SCL_Pulse
        call  SCL_High
        call  SCL_Low
        return
 
SDA_High
        bsf     STATUS,RP0      ; Bank 1
        bsf     TRIS_SDA        ; Make SDA pin input
        bcf     STATUS,RP0      ; Back to bank 0
        call    Delay_Short
        return
 
SDA_Low
        bcf     I2C_SDA
        bsf     STATUS,RP0
        bcf     TRIS_SDA        ; Make SDA pin output
        bcf     STATUS,RP0
        call    Delay_Short
        return
 
SCL_High
        bsf     STATUS,RP0      ; Bank 1
        bsf     TRIS_SCL        ; Make SDA pin input
        bcf     STATUS,RP0      ; Back to bank 0
        call    Delay_Short
        return
 
SCL_Low
        bcf     I2C_SCL
        bsf     STATUS,RP0
        bcf     TRIS_SCL        ; Make SDA pin output
        bcf     STATUS,RP0
        call    Delay_Short
        return
 
Delay_Short                 ; 25us delay
        movlw   .5
        movwf   dly_loop2
Delay_Short_1
        nop
        decfsz  dly_loop2,f
        goto    Delay_Short_1
        return
 
Delay_Long
        movlw   .250        ; 250ms delay
        movwf   dly_loop1
Outer
        movlw   .110        ; Close to 1ms when set to .110
        movwf   dly_loop2
Inner
        nop
        nop
        nop
        nop
        nop
        nop
        decfsz  dly_loop2,f
        goto    Inner
        decfsz  dly_loop1,f
        goto    Outer
        return
 
END