Agrego una que hice yo solo para recepcion de datos como exclavo, por interrupcion de flaco de RB0.- Adjunto un posible hardware y el diagrama de flujo de la recepcion por interrupcion.-
List p=16f84a
#include <p16f84a.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
; Cristal de 10 MHz !!!
; Dispositivo Maestro I2C configurado a 100 kHz.-
;**********************************************
; Declaracion de Registros
;**********************************************
CONTADOR equ 0x0C ;registro utilizado para conteo
PDel0 equ 0x10 ;registro utilizado en demoras
PDel1 equ 0x11 ;registro utilizado en demoras
PDel2 equ 0x12 ;registro utilizado en demoras
FLAGS equ 0x13 ;registro utilizado en carga de banderas para control de I2C
DATO_I2C equ 0x14 ;registro utilizado para el guardado del byte recibido por I2C
TEMP_W equ 0x15 ;registro temporario para guardado de W
STATUS_TEMP equ 0x16 ;registro temporario para guardado de STATUS
;**********************************************
; Declaracion de Bit
;**********************************************
SCL equ 0 ;pin SCL de comunicacion I2C, en este caso usamos RA0
SDA equ 0 ;pin SDA de comunicacion I2C, Debe ser siempre el Rb0, para deteccion de flanco x interrupcion
PFULL equ 0 ;si es 1 pila completa
SLAVE_OK equ 1 ;si es 1 se ha direccionado el esclavo correcto
KBHIT equ 2 ; Control de recepcion de datos
DIRE equ 3 ; Se recibe direccion I2C
;**********************************************
org 0x00
goto inicio
;******************************************
; Interrupcion
;******************************************
org 0x04
btfsc INTCON,INTF
goto interrupcion_rb0
goto salida_interrupcion
;******************************************
; Interrupcion RB0
;******************************************
; se genero interrupcion, posible envio de Start para la comunicacion.-
interrupcion_rb0
btfss PORTA,SCL ; si es 1 entonces se ha generado condicion de start
goto salida_interrupcion
movwf TEMP_W
swapf TEMP_W,1
movf STATUS,w
movwf STATUS_TEMP
clrf STATUS ;Bank0
bcf INTCON,GIE
movlw 0x08
movwf CONTADOR
;*******************************************
espera_bit btfsc PORTA,SCL ; esperamos que SCL=0
goto $-1
espera_clock btfss PORTA,SCL ; esperamos que SCL=1 para leer bit.
goto $-1
bcf DATO_I2C,0 ; cargo 0
btfsc PORTB,SDA ; si es 0 salta, sino carga 1
cargo_1 bsf DATO_I2C,0 ; cargo 1
consulta decfsz CONTADOR ; determina si ya llegaron los 8 bit's
goto $+2 ; no se cargaron
goto espera_ack
rlf DATO_I2C,1 ; rotamos a la izquierda
goto espera_bit
;*******************************************
espera_ack
bsf STATUS,RP0 ; Bank1
bcf TRISB,SDA ; SDA como salida
bcf STATUS,RP0 ; Bank0
bcf PORTB,SDA ; envio ack
btfsc FLAGS,PFULL ; determino si estoy en condiciones de recibir dato (PFULL=0 Si)
bsf PORTB,SDA ; envio un nack
btfss PORTA,SCL ; espero a que SCL=1
goto $-1
call demora_6us
bsf PORTB,SDA
bsf STATUS,RP0 ; Bank1
bsf TRISB,SDA ; ya se envio ack o nack, reconfiguro SDA como entrada.
clrf STATUS ; Bank0
;*******************************************
call grabar_dato
movlw 0x08
movwf CONTADOR ; por si se recibe otro byte
;*******************************************
btfss PORTA,SCL ; determinamos si es un stop u otro byte
goto $-1
btfsc PORTB,SDA ; si es 0 puede ser un stop
goto cargo_1 ;no es stop, se carga el byte, MSB es 1
nop ;demora de 5us.
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
btfsc PORTA,SCL ; pregunta si el SCL esta generando clock.
goto salida_interrupcion ; si no genera clock, entonces STOP
bcf DATO_I2C,0 ; si se genera clock, se carga byte, MSB=0
decf CONTADOR,1
rlf DATO_I2C,1
goto espera_clock
;******************************************
salida_interrupcion
bcf FLAGS,SLAVE_OK
bcf INTCON,INTF
bsf INTCON,GIE
movf STATUS_TEMP,w
movwf STATUS
swapf TEMP_W,w
retfie
;__________________________________________________________________
;******************************************
; Grabar Dato
;******************************************
; La recepcion fue creada como para recibir varios datos consecutivos y en este caso
; hay que crear un buffer (No expuesto para facilitar entendimiento), en este ejemplo
; solo se pueden recibir 1.-
grabar_dato
btfss FLAGS,DIRE ; Se recibio Direccion del Exclavo?
goto guardo_direccion ;no, lo verifico.-
bsf FLAGS,PFULL ;Se lleno el Buffer, para no recibir mas
bsf FLAGS,KBHIT ;Se recibio dato y queda guardado en DATO_I2C
return
guardo_direccion
movlw 0xAA ; Direccion de mi exlavo.-
subwf DATO_I2C,w ; verifico si es la correcta
btfss STATUS,Z
goto salida_interrupcion ; no lo es, salgo.-
bsf FLAGS,DIRE ; Si es, lo indico seteando DIRE
return
;-------------------------------------------------------------------------
;******************************************
; Programa Principal
;******************************************
inicio
movlw b'00000001' ;configurar el puerto a como xxxsssse
banksel TRISA ;cambiar a banco 1
movwf TRISA
movlw b'00000001' ;configurar el puerto b como ssssssse
movwf TRISB
bcf OPTION_REG,INTEDG ;interrupción rb0 por flanco descendente
banksel PORTB
clrf FLAGS
;**********************************************
; Activacion de interrupciones
;**********************************************
bsf INTCON,GIE ;activar habilitador general de interrupciones.
bsf INTCON,INTE ;activar interrupción por rb0.
;**********************************************
clrf FLAGS
clrf PORTA
;**********************************************
; Estado de espera
;**********************************************
Espera
btfss FLAGS,KBHIT ; Llego dato de I2C?
goto $-1 ; No
clrf FLAGS
; En DATO_I2C tenemos el byte enviado por el Dispositivo Maestro
; para posterior manejo, como enviarlo a un LCD, etc. No lo expuse
; para no complicar el entendimiento
goto Espera ; bucle infinito.-
;**********************************************
;** Subrutinas Demoras
;**********************************************
;**********************************************
demora_6us movlw .2
movwf PDel0
PLoop0_6 nop
decfsz PDel0, 1
goto PLoop0_6
PDelL1_6 goto PDelL2_6
PDelL2_6
return
;**********************************************
end