LIST P=PIC16C84, R=HEX
  INCLUDE pic16f84.inc
  LIST
 
;pines
#define SDA PORTB,4
#define SDATRIS TRISB,4
#define SCL PORTB,5
#define SCLTRIS TRISB,5
 
;variables en RAM
  ORG    0C
 
CNT RES 1    ;CNT ... contador para la TX/RX de bytes!
CNT1 RES 1    ;CNT1 ... contador
cont2 RES 1    ;cont2 ... contador para la rutina de 5ms
cont3 RES 1    ;cont3 ... contador para la rutina de 5ms
ADDRESS RES 1    ;ADDRESS ... dirección donde se Lee/Escribe los datos
DATO RES 1    ;DATO ... dato donde se lee/escribe
I2CBUF RES 1    ;I2CBUF ...  buffer para enviar o recibir el dato
I2CDI RES 1    ;I2CDI ... Dato de entrada (bit)
I2CDO RES 1    ;I2CDO ... Dato de salida (bit)
I2CACKF RES 1    ;I2CACKF ... Registro de ACK
;fin de variables en RAM
 
  ORG 0
  GOTO INI
 
;******************************************************************************
;  RUTINAS DE COMUNICACION SERIE (MODULO I2C)
;******************************************************************************
;
; GENERA START BIT
;
START_I2C
  BSF   STATUS,RP0; selecciona banco1
  BCF  SDATRIS  ; SDA salida
  BCF  SCLTRIS  ; SCL salida
  BCF  STATUS,RP0; selecciono banco0
  BSF    SDA
  BCF    SCL    ; bajo clock
  NOP        ; 
  BSF    SCL    ; subo clock
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  NOP        ; 
  BCF    SDA    ; bajo datos
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  NOP        ; 
  BCF    SCL    ; y bajo clock para generar start bit
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  RETURN      ; 
;
; GENERA STOP BIT
;
STOP_I2C
  BSF   STATUS,RP0; selecciona banco1
  BCF  SDATRIS  ; SDA salida
  BCF  SCLTRIS  ; SCL salida
  BCF  STATUS,RP0; selecciono banco0
  BCF    SDA    ; bajo datos
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  BSF    SCL    ; subo clock
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  BSF    SDA    ; subo datos
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  BCF    SCL    ; bajo clock
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  RETURN      ; y retorno
;
; ENVIA UN BIT POR SDA
;
BITOUT_I2C
  BSF   STATUS,RP0; selecciona banco1
  BCF  SDATRIS  ; SDA salida
  BCF  SCLTRIS  ; SCL salida
  BCF  STATUS,RP0; selecciono banco0
  BTFSS    I2CDO,7  ; enviar un 1 ?
  GOTO    I2CBLO  ; no, envio un 0...
  BSF    SDA    ; pongo SDA en 1
  GOTO    CLKOUT    ; 
I2CBLO
  BCF    SDA    ; pongo SDA en 0
CLKOUT
  BSF    SCL    ; y clockeo
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  BCF    SCL    ; 
  RETURN      ; y salgo
;
; RECIBE UN BIT POR SDA
;
BITIN_I2C
  BSF    I2CDI,7  ; asumo que llega un 1
  BSF   STATUS,RP0; selecciona banco1
  BSF  SDATRIS  ; SDA entrada
  BCF  SCLTRIS  ; SCL salida
  BCF  STATUS,RP0; selecciono banco0
  BSF    SCL    ; subo clock
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  GOTO    $+1    ; 
  BTFSS    SDA    ; recibio un 1 ?
  BCF    I2CDI,7  ; no, es 0
  BCF    SCL    ; bajo clock
  RETURN      ; y salgo
;
; RUTINA DE TRANSMISION POR I2C
;
I2C_TX
  MOVLW    d'8'    ; son 8 bits a contar
  MOVWF    CNT    ; 
I2C_TXLP
  BCF    I2CDO,7  ; asumo que sale un 0
  BTFSC    I2CBUF,7; sacar un 0 ?
  BSF    I2CDO,7  ; no, sale un 1...
  CALL    BITOUT_I2C; envio bit
  RLF    I2CBUF,F; acomodo para sacar proximo bit
  DECFSZ  CNT,F    ; salieron los 8 ?
  GOTO    I2C_TXLP; no, continuo sacando...
  CALL    BITIN_I2C; leo bit de acknowledge
  BCF    I2CACKF,7  ; asumo que es 0
  BTFSC    I2CDI,7  ; es 0 ?
  BSF    I2CACKF,7  ; no, envio un 1
  RETURN      ; y salgo
;
; RUTINA DE RECEPCION POR I2C
;
I2C_RX
  CLRF    I2CBUF  ; borro buffer
  MOVLW    d'8'    ; son 8 bits a leer
  MOVWF    CNT    ; 
  BCF    STATUS,C  ; borro flag de carry
I2C_RXLP
  RLF    I2CBUF,F; roto un bit a la izquierda
  CALL    BITIN_I2C; y leo bit enviado
  BTFSC    I2CDI,7  ; llego un 0 ?
  BSF    I2CBUF,0; no, escribo un 1 en el buffer
  DECFSZ  CNT,F    ; llegaron los 8 bits ?
  GOTO    I2C_RXLP; no, sigo reciviendo...
  BCF    I2CDO,7  ; 
  BTFSC    I2CACKF,7  ; 
  BSF    I2CDO,7  ; 
  CALL    BITOUT_I2C; envio bit de acknowledge
  RETURN      ; y salgo
;
; LECTURA DE LA MEMORIA 24Cxx
;
RD24CXX
  CALL    START_I2C; envio condicion de start
  MOVLW    0A0    ; traigo direccion de esclavo
  MOVWF    I2CBUF  ; y cargo en buffer
  CALL    I2C_TX  ; direcciono memoria
  MOVFW    ADDRESS  ; traigo direccion a leer
  MOVWF    I2CBUF  ; 
  CALL    I2C_TX  ; y envio a memoria
  CALL    START_I2C; envio condicion de start
  MOVLW    0A1  ; direcciono memoria para lectura
  MOVWF    I2CBUF  ; cargo en buffer
  CALL    I2C_TX  ; y envio
  BCF    I2CACKF,7  ; preparo para acknowledge en 0
  CALL    I2C_RX  ; y leo byte direccionado
  CALL    STOP_I2C; genero condicion de stop
  MOVFW    I2CBUF  ; cargo dato leido en
  MOVWF    DATO    ; registro de datos de memoria
  RETURN      ; y salgo
;
; ESCRITURA DE LA MEMORIA 24Cxx
;
WR24CXX
  CALL    START_I2C; genero bit de start
  MOVLW    0A0    ; cargo direccion del esclavo
  MOVWF    I2CBUF  ; en buffer
  CALL    I2C_TX  ; envio...
  MOVFW    ADDRESS  ; cargo direccion a escribir
  MOVWF    I2CBUF  ; en buffer
  CALL    I2C_TX  ; envio...
  MOVFW    DATO    ; cargo dato a escribir
  MOVWF    I2CBUF  ; en buffer
  CALL    I2C_TX  ; envio...
  CALL    STOP_I2C; genero bit de stop
  MOVLW    d'60'    ; 
  MOVWF    CNT1    ; 
WR24POLL
  CALL    START_I2C; 
  MOVLW    ADDRESS  ; 
  MOVWF    I2CBUF  ; 
  CALL    I2C_TX  ; 
  BTFSS    SDA    ; 
  GOTO    WR24P_EXIT; 
  DECFSZ  CNT1,F  ; 
  GOTO    WR24POLL; 
  RETLW    0xFF    ; 
WR24P_EXIT
 
  CALL DEL5MS; espero 10 mseg para dar tiempo a memoria
  CALL DEL5MS
 
  RETLW    0x00    ; y salgo
;
; Retardo de 5MS
;
DEL5MS  MOVLW     d'6'    ; 1 set numero de repeticion  (B)
        MOVWF     cont2    ; 1 |
PLoop1  MOVLW     d'207'  ; 1 set numero de repeticion  (A)
        MOVWF     cont3    ; 1 |
PLoop2  CLRWDT            ; 1 clear watchdog
        DECFSZ    cont3, 1; 1 + (1) es el tiempo 0  ? (A)
        GOTO      PLoop2  ; 2 no, loop
        DECFSZ    cont2, 1; 1 + (1) es el tiempo 0  ? (B)
        GOTO      PLoop1  ; 2 no, loop
PDelL1  GOTO      PDelL2  ; 2 ciclos delay
PDelL2  CLRWDT            ; 1 ciclo delay
        RETURN            ; 2+2 Fin.
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*;
;
; RUTINA QUE MUESTRA EN EL PUERTO B
;
MOSTRAR
  BSF   STATUS,RP0; selecciona banco1
  CLRF  PORTB  ; SDA entrada
  BCF  STATUS,RP0; selecciono banco0
  MOVFW  DATO
  MOVWF   PORTB
  RETURN  
;*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*;
;
; PRINCIPAL
;
INI  
  MOVLW   47  ;
  MOVWF   DATO  ;inicializamos las variables del dato a meter y
  MOVLW   05   ;también la dirección inicial
  MOVWF   ADDRESS  ;
  CALL   WR24CXX
  CALL   RD24CXX
  CALL  MOSTRAR
  GOTO  $
  END;