Si además quieres enviarnos un Artículo para el Blog y redes sociales, pulsa el siguiente botón:
hola a 😮 a todos los interesados del protocolo I2C.
soy nuevo en el foro, mi nick es wallen. No encuentro donde tengo que pinchar para enviar un nuevo mensaje, así que respondo a este en este foro I2C
Si hay algún genio del I2C al otro lado del foro espero que me ayude:
Esoty trabajando mucho sobre el I2C y he conseguido comunicar perfectamente un master y un slave. Es decir, el Master TRANSMITE y el Slave RECIBE.......o bien el Master RECIBE y el Slave TRANSMITE.
De momento los programas están en ensamblador (.asm). Aqui os dejo las rutinas de enviar_I2C y recibir_I2C (funcionan a la perfección) y algunas explicaciones al respecto
Mi problema se presenta cuando quiero establecer comunicacion entre tres microcontroladores pic 16f876, un Master y dos Slaves pic 16f876.
El programa es muy simple, el Master lee de un Slave (SLAVE TRANSMITE un byte) su puerto B y el byte obtenido lo manda por el BUS al Slave (SLAVE RECIBE el byte del BUS) y escribe el resultado por el puerto B.
Después de la primera rutina de lectura (que funciona correctamente mas que probada) el Master al pasar por la rutina de escritura pierde definitivamente el control del BUS. El problema debe estar en la trama serie START, ADRESS, ACK , DATO, ACK, ....., pero a la hora de cambiar de direccíon ...puf se jode todo, perdemos el I2C y no se porqué.
Aqui adjunto las rutinas que funcionan, pero de momento solo MASTER y un Slave (usando dos microcontroladores PIC16F876)
;*******************************************************************
;SUBRUTINA PARA TRANSMITIR DATOS1 EN MODO MASTER DEL I2C
Envia_i2c
BCF STATUS,RP0 ; Restore Bank0 ................DEN BUS ÜBERNEHMEN
BCF PIR1,SSPIF ; Clear the interrupt flag before RX
BSF STATUS,RP0 ; SSPCON2: is in Bank1
BCF STATUS,RP1
BSF SSPCON2,SEN ; envia bit START
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; START finalizado?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF ; Clear the interrupt flag before RX
MOVF DIREC,W ;...............................DIE ADRESSE SENDEN
MOVWF SSPBUF ; carga direccion
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF ; Clear the interrupt flag before RX
MOVF Dato,W ; carga dato....................DIE DATEN SENDEN
MOVWF SSPBUF
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no espera
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1................DEN BUS WIEDER FREIGEBEN
BCF STATUS,RP1
BSF SSPCON2,PEN ; Envia bit de stop
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; STOP finalizado?
GOTO $-1 ; no espera
BCF PIR1,SSPIF
RETURN
;*********************************************************************
;SUBRUTINA PARA RECIBIR DATOS1 EN MODO MASTER DEL I2C
;*********************************************************************
Recibe_i2c
BCF STATUS,RP0 ; Restore Bank0......... DEN BUS ÜBERNEHMEN
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1
BCF STATUS,RP1
BSF SSPCON2,SEN ; envia bit START
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; START finalizado?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
movf DirSlave,W ;Dirección esclavo
iorlw b'00000001' ;con orden de lectura
; MOVF DIREC,W ; ........................DIE ADRESSE SENDEN
MOVWF SSPBUF ; carga direccion
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1
BCF STATUS,RP1
BSF SSPCON2,RCEN ; activa modo receptor....DATEN EMPFANG EINSCHALTEN
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
MOVF SSPBUF,W ; carga dato
MOVWF MensajeIn
; BSF STATUS,RP0 ; Restore Bank1...........EIN ANDERES BYTE SOLL GELESEN WERDEN
; BCF STATUS,RP1
; BSF SSPCON2,ACKEN ; Genera ACK
; BCF STATUS,RP0 ; Restore Bank0
BSF STATUS,RP0 ; Restore Bank1...........DEN BUS WIEDER FREIGEBEN
BCF STATUS,RP1
BSF SSPCON2,PEN ; Envia bit de stop
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; STOP finalizado?
GOTO $-1 ; no espera
BCF PIR1,SSPIF
RETURN
hay un link muy bueno en alemán sobre el protocolo I2C:
http://www.sprut.de/electronic/pic/grund/i2c.htm#pic
Las direcciones empleadas para ambos Slaves son:
Slave ESCRITURA: b'01111000'
Slave LECTURA: b'01111100'
Para programar el Slave bajarse el programa del siguiente enlace
Alejandro Alonso Puig - mundobot.com, utliza un interrupt Handler muy bueno para I2C
copia directamente el contenido del asm en el post, si no sabes ponerlo como codigo no te preocupes que yo lo editare para que salga correctamente
vale pero va a salir demasiado grande el post...en cuanto llegue a
casa lo envio
hola,
aqui pongo el código asm del Master (lee del slave1 y escribe sobre el slave2) y los códigos de ambos Slaves
Master:
;Definición de constantes
#define ClockValue d'9' ;(100khz) valor para cálculo de vel. I2C que pasará a SSPADD
;Definición de variables
cblock 0x20
MensajeIn ;Contendrá el dato recibido por I2C del slave
MensajeOut ;Contendrá el dato a enviar por I2C al slave
DirSlave ;Dirección del Slave
BkStatus ;Backup del registro STATUS
BkW ;Backup W
BDel0 ;Usada en retardos. Usada por subr "HacerTiempo"
BDel1 ;Usada en retardos. Usada por subr "HacerTiempo"
BDel2 ;Usada en retardos. Usada por subr "HacerTiempo"
Pausa ;Pausa en centesima de sg. Usada por subr "HacerTiempo"
PDel0
PDel1
PDel2
Dato
endc ;Fin de definiciones
org 0
goto INICIO
org 4
;-------------------------------------------------------------------------------
INICIO ;Inicio del cuerpo del programa
banksel TRISD ;Apunta a banco 1
movlw b'00000000' ;Salida (Leds)
movwf TRISD ;
MOVLW b'11101111'
MOVWF OPTION_REG
MOVLW b'00000110'
MOVWF ADCON1
banksel PORTD ;Apunta a banco 0
clrf PORTD
call init_i2c_Master ;Configuración para uso de i2c
clrf MensajeIn
clrf MensajeOut
movlw d'10' ;Pausa de 10 centésimas de segundo para que en...
movwf Pausa ;...el arranque de tiempo a los slaves a quedar...
call HacerTiempo ;..configurados adecuadamente.
MLoop
;PETICION DE UN BYTE DE DATOS AL SLAVE
;Se ha de la dirección del Slave en "DirSlave". Tras esto solo hay que llamar
;a la subrutina "Recibir" y se obtendrá el dato en "MensajeIn"
movlw b'01111000' ;Establece dirección de solicitud..
movwf DirSlave ;..es decir, dirección del slave
call Recibir ;Toma dato del Slave...
movf MensajeIn,W ;... a través de "MensajeIn"...
movwf PORTD ;...y lo muestra por PORTB (Leds)
CALL PDelay
MOVLW b'11111111' ; encendemos todos los bombillos
MOVWF Dato
MOVLW b'01111100'
MOVWF DirSlave
CALL Enviar
CALL PDelay
MOVLW b'10101010' ; alternamos el encendido
MOVWF Dato
MOVLW b'01111100'
MOVWF DirSlave
CALL Enviar
CALL PDelay
goto MLoop
;---------------------------------------------------------------------------------
;SUBRUTINA PARA RETARDO DE 4 SEGUNDO
PDelay movlw .62 ; 1 set number of repetitions (C)
movwf PDel0 ; 1 |
PLoop0 movlw .63 ; 1 set number of repetitions (B)
movwf PDel1 ; 1 |
PLoop1 movlw .255 ; 1 set number of repetitions (A)
movwf PDel2 ; 1 |
PLoop2 clrwdt ; 1 clear watchdog
decfsz PDel2, 1 ; 1 + (1) is the time over? (A)
goto PLoop2 ; 2 no, loop
decfsz PDel1, 1 ; 1 + (1) is the time over? (B)
goto PLoop1 ; 2 no, loop
decfsz PDel0, 1 ; 1 + (1) is the time over? (C)
goto PLoop0 ; 2 no, loop
PDelL1 goto PDelL2 ; 2 cycles delay
PDelL2 clrwdt ; 1 cycle delay
return ; 2+2 Done
;-------------------------------------------------------------------------------
init_i2c_Master ;Inicializa valores para uso de I2C en Master
;Ha de ser llamado tras definir TRISC y un valor para
;ClockValue. Para frecuencia SCL=Fosc/(4x(ClockValue+1))
;-------------------------------------------------------------------------------
;Guardamos copia de algunos registros
movwf BkW ;Hace copia de W
movf STATUS,W ;Hace copia de registro de estado
banksel PORTA
movwf BkStatus
;Configuramos I2C
banksel TRISC ; Pasamos a direccionar Banco 1
movlw b'00011000' ; Establece líneas SDA y SCL como entradas...
iorwf TRISC,f ;..respetando los valores para otras líneas.
movlw ClockValue ; Establece velocidad I2C segun...
movwf SSPADD ; ...valor de ClockValue
bcf SSPSTAT,6 ; Establece I2C input levels
bcf SSPSTAT,7 ; Habilita slew rate
banksel SSPCON ; Pasamos a direccionar Banco 0
movlw b'00111000' ; Master mode, SSP enable, velocidad segun...
movwf SSPCON ; ... Fosc/(4x(SSPADD+1))
bcf PIR1,SSPIF ; Limpia flag de eventos SSP
bcf PIR1,7 ; Limpia bit. Mandatorio por Datasheet
;Restauramos las copias de los registros
movf BkStatus,W ;Restaura las copias de registros
movwf STATUS ;registro de estado
movf BkW,W ;registro W
return
;---------------------------------------------------------------------------------------
HacerTiempo ;realiza una pausa del numero de centesimas de segundo especificadas en "Pausa"
;---------------------------------------------------------------------------------------
movf Pausa,W ;Coloca el valor de pausa en BDel2...
movwf BDel2 ;...para no alterar su contenido
;............................................................
; Generado con PDEL ver SP r 1.0 el 24/02/03 Hs 18:31:22
; Descripcion: Delay 10000 ciclos (1 centésima de segundo)
;............................................................
BCiclo movlw .8 ; 1 set numero de repeticion (B)
movwf BDel0 ; 1 |
BLoop1 movlw .249 ; 1 set numero de repeticion (A)
movwf BDel1 ; 1 |
BLoop2 nop ; 1 nop
nop ; 1 ciclo delay
decfsz BDel1, 1 ; 1 + (1) es el tiempo 0 ? (A)
goto BLoop2 ; 2 no, loop
decfsz BDel0, 1 ; 1 + (1) es el tiempo 0 ? (B)
goto BLoop1 ; 2 no, loop
BDelL1 goto BDelL2 ; 2 ciclos delay
BDelL2 nop ; 1 ciclo delay
;............................................................
decfsz BDel2,F ;Repite tantas veces el ciclo de una decima de segundo...
goto BCiclo ;..como se lo indique ADel2
return ; 2+2 Fin.
;*******************************************************************
;SUBRUTINA PARA TRANSMITIR DATOS1 EN MODO MASTER DEL I2C
;****************************************************************
Enviar
MOVF DirSlave,W ;...............................DIE ADRESSE SENDEN
MOVWF SSPBUF ; carga direccion
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF ; Clear the interrupt flag before RX
MOVF Dato,W ; carga dato....................DIE DATEN SENDEN
MOVWF SSPBUF
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no espera
BCF PIR1,SSPIF
banksel SSPCON2
bsf SSPCON2,RSEN
I2C.Restart.Wait
btfsc SSPCON2,RSEN
GOTO I2C.Restart.Wait
BCF STATUS,RP0
RETURN
;******************************************************************
;SUBRUTINA PARA RECIBIR DATOS1 EN MODO MASTER DEL I2C
;******************************************************************
Recibir
BCF STATUS,RP0 ; Restore Bank0......... DEN BUS ÜBERNEHMEN
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1
BCF STATUS,RP1
BSF SSPCON2,SEN ; envia bit START
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; START finalizado?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
movf DirSlave,W ;Dirección esclavo
iorlw b'00000001' ;con orden de lectura
; MOVF DIREC,W ; ........................DIE ADRESSE SENDEN
MOVWF SSPBUF ; carga direccion
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1
BCF STATUS,RP1
BSF SSPCON2,RCEN ; activa modo receptor....DATEN EMPFANG EINSCHALTEN
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
MOVF SSPBUF,W ; carga dato
MOVWF MensajeIn
; BSF STATUS,RP0 ; Restore Bank1...........EIN ANDERES BYTE SOLL GELESEN WERDEN
; BCF STATUS,RP1
; BSF SSPCON2,ACKEN ; Genera ACK
; BCF STATUS,RP0 ; Restore Bank0
banksel SSPCON2
bsf SSPCON2,RSEN
I2C.Restart.Wait
btfsc SSPCON2,RSEN
GOTO I2C.Restart.Wait
BCF STATUS,RP0
RETURN
END
Slave1 - TRANSMITE EL BYTE AL MASTER
;Definición de constantes
#define DirNodo b'01111000' ;Dirección I2C de este nodo
;Definición de variables
cblock 0x20
MensajeIn ;Contendrá el dato recibido por I2C del master
MensajeOut ;Contendrá el dato a enviar por I2C al master
BkStatus ;Backup del registro STATUS
BkW ;Backup W
Temp ;Variable Temporal usada para evaluación de eventos I2C
endc ;Fin de definiciones
org 0
goto INICIO
org 4
;-------------------------------------------------------------------------------
Interrupcion ;RUTINA DE INTERRUPCIÓN. Se ocupa de los eventos I2C
;-------------------------------------------------------------------------------
;Guardamos copia de algunos registros
movwf BkW ;Hace copia de W
movf STATUS,W ;Hace copia de registro de estado
banksel PORTA
movwf BkStatus
;Chequeamos si la interrupción es por evento I2C. En caso positivo llamamos
;a la rutina de proceso del evento
banksel PIR1
btfss PIR1,SSPIF ;Ha ocurrido un evento SSP? (I2C)
goto IntNoSSP ;No. entonces será por otra cosa. Saltamos.
call SSP_Handler ;Si. Procesamos el evento. Si se reciben ordenes, quedarán
;registradas en "MensajeIn". Se enviarán las ordenes
;guardadas en "MensajeOut".
banksel PIR1
bcf PIR1,SSPIF ;Limpiamos el flag
goto Rest
IntNoSSP ;Aquí se gestionan interrupciones que no son por SSP
;..........
; En caso de necesitarse, poner aquí la rutina de gestión de interrupciones
; que no sean por bus I2C
;..........
Rest ;Restauramos las copias de los registros
movf BkStatus,W ;Restaura las copias de registros
movwf STATUS ;registro de estado
movf BkW,W ;registro W
retfie
;-------------------------------------------------------------------------------
INICIO ;Inicio del cuerpo del programa
banksel TRISB ;Apunta a banco 1
movlw b'11111111' ;Salida (Leds)
movwf TRISB ;
banksel PORTB ;Apunta a banco 0
clrf PORTB ;Limpia puerto B
call init_i2c_Slave ;Configuración para uso de i2c
banksel INTCON
bsf INTCON,GIE ;Activamos las interrupciones
banksel MensajeIn
clrf MensajeIn
clrf MensajeOut
MLoop
movf PORTB,W ;dato cualquiera por I2C que metemos en
movwf MensajeOut ;"MensajeOut" para cuando el Master se lo pida
goto MLoop
;***************************************************************************
; SUBRUTINAS
;***************************************************************************
;-------------------------------------------------------------------------------
init_i2c_Slave ;Inicializa valores para uso de I2C en Slave
;Ha de ser llamado tras definir TRISC y un valor para
;ClockValue. Para frecuencia SCL=Fosc/(4x(ClockValue+1))
;-------------------------------------------------------------------------------
;Guardamos copia de algunos registros
movwf BkW ;Hace copia de W
movf STATUS,W ;Hace copia de registro de estado
banksel PORTA
movwf BkStatus
;Configuramos I2C
banksel TRISC ; Pasamos a direccionar Banco 1
movlw b'00011000' ; Establece líneas SDA y SCL como entradas...
iorwf TRISC,f ;..respetando los valores para otras líneas.
bcf SSPSTAT,CKE ; Establece I2C input levels
bcf SSPSTAT,SMP ; Habilita slew rate
bsf SSPCON2,GCEN ; Habilita direccionamiento global
movlw DirNodo ; Dirección esclavo
movwf SSPADD ;
banksel SSPCON ; Pasamos a direccionar Banco 0
movlw b'00110110' ; Slave mode, SSP enable, velocidad segun...
movwf SSPCON ; ... Fosc/(4x(SSPADD+1))
bcf PIR1,SSPIF ; Limpia flag de eventos SSP
bcf PIR1,7 ; Limpia bit. Mandatorio por Datasheet
;Configuración para interrupciones por evento I2C
banksel PIE1
bsf PIE1,SSPIE
bsf INTCON,PEIE
;Restauramos las copias de los registros
movf BkStatus,W ;Restaura las copias de registros
movwf STATUS ;registro de estado
movf BkW,W ;registro W
return
; --------------------------------------------------------------------------------------
SSP_Handler ; Este manejador controla cada evento SSP (I2C) acontecido.
; El código que se muestra abajo chequea 5 posibles estados.
; Cada uno de los 5 estados SSP son identificados haciendo
; XOR de los bits del registro SSPSTAT con mascaras de bits
; predeterminadas. Una vez que el estado ha sido identificado
; se llevan a cabo las acciones pertinentes. Los estados
; indefinidos son considerados como estados de error.
; State 1: Operación de escritura I2C, ultimo byte era de dirección.
; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
; State 2: Operación de escritura I2C, ultimo byte era de datos.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
; State 3: Operación de lectura I2C, ultimo byte era de dirección.
; SSPSTAT bits: S = 1, D_A = 0, R_W = 1, BF = 0
; State 4: Operación de lectura I2C, ultimo byte era de datos.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
; State 5: Reset lógico del Slave I2C por NACK del master.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 0
; --------------------------------------------------------------------------------------
banksel SSPSTAT
movf SSPSTAT,W ; Obtiene el valor de SSPSTAT
andlw b'00101101' ; elimina los bits no importantes SSPSTAT.
banksel Temp
movwf Temp ; para chequeo posterior.
State1: ; Operación de escritura, ultimo byte ha sido
movlw b'00001001' ; de dirección, el buffer está lleno.
banksel Temp
xorwf Temp,W ;
btfss STATUS,Z ; Estamos en el primer estado?
goto State2 ; No, checkeamos siguiente estado
call ReadI2C ; SI. Hacemos un read SSPBUF (para vaciar buffer).
; El Hardware se ocupa de mandar Ack
return
State2: ; Operación de escritura, ultimo byte ha sido
movlw b'00101001' ; de datos, el buffer está lleno.
banksel Temp
xorwf Temp,W
btfss STATUS,Z ; Estamos en el segundo estado?
goto State3 ; NO, checkeamos siguiente estado
call ReadI2C ; SI, Tomamos el byte del SSP.
;Aquí tenemos en W el valor del dato recibido
movwf MensajeIn
return
State3: ; Operación de lectura, ultimo byte ha sido
movlw b'00001100' ; de dirección, el buffer está vacío
banksel Temp
xorwf Temp,W
btfss STATUS,Z ; Estamos en el tercer estado?
goto State4 ; NO, checkeamos siguiente estado
;Aquí debemos poner en W el valor del dato a enviar (solicitado por el master)
movf MensajeOut,W
call WriteI2C ; SI, escribimos el byte en SSPBUF
return
State4: ; Operación de lectura, ultimo byte ha sido
movlw b'00101100' ; de datos, el buffer está vacío
banksel Temp
xorwf Temp,W
btfss STATUS,Z ; Estamos en el cuarto estado?
goto State5 ; NO, checkeamos siguiente estado
;Aquí debemos poner en W el valor del dato a enviar (solicitado por el master)
movf MensajeOut,W
call WriteI2C ; SI, escribimos el byte en SSPBUF
return
State5:
movlw b'00101000' ; Se ha recibido un NACK mientras se transmitían...
banksel Temp
xorwf Temp,W ; ..datos al master. Lo lógica del Slave..
btfss STATUS,Z ; ..se resetea en este caso. R_W = 0, D_A = 1
goto I2CErr ; y BF = 0
return ; Si no estamos en State5, entonces es
; que algo fue mal
I2CErr nop ; Algo fue mal
return
;---------------------------------------------------------------------
WriteI2C ;Usada por SSP_Handler para escribir datos en bus I2C
;---------------------------------------------------------------------
banksel SSPCON
movwf SSPBUF ; Escribe el dato en W
bsf SSPCON,CKP ; Libera el reloj
return
;---------------------------------------------------------------------
ReadI2C ;Usada por SSP_Handler para escribir datos en bus I2C
;---------------------------------------------------------------------
banksel SSPBUF
movf SSPBUF,W ; Toma el byte y lo guarda en W
return
END
Slave2 - RECIBE EL BYTE DEL MASTER Y LO COPIA EN EL PUERTO B
;***************************************************************
;VECTOR DE INICIO / INTERRUPCION
;******************************************************************
ORG 0x00
GOTO Inicio
ORG 0x04
GOTO INT
;=============Definicion de variables
MensajeIn equ 0x20
MensajeOut equ 0x21
BkStatus equ 0x22
BkW equ 0x23
Temp equ 0x24
Dir_slave equ 0x25
;=============Inicio de programa
Inicio
org 0x05
BSF STATUS,RP0
BCF STATUS,RP1 ; Banco 1
MOVLW b'00000000' ; Puerta B como salida
MOVWF TRISB
CLRF SSPADD
BCF STATUS,RP0 ; Restore Bank0
CLRF PORTC ; Limpia bancos
CLRF PORTB
MOVLW b'01111100' ; Direccion del esclavo
MOVWF Dir_slave
CLRF MensajeIn ; Limpia variables
CLRF MensajeOut
CALL ini_i2c_slave
;=============Rutina de servicio de interrupcion
INT
;Guardamos copia de algunos registros
MOVWF BkW
MOVF STATUS,W
banksel PORTA
MOVWF BkStatus
;Chequeamos si la interrupcion es por evento I2C
banksel PIR1
BTFSS PIR1,SSPIF
GOTO IntNoSSP
CALL SSP_Handler
banksel PIR1
; BCF PIR1,SSPIF ; Limpiamos el flag
GOTO REST
IntNoSSP ; Otras interrupciones
REST ;Restauramos las copias de los registros
MOVF BkStatus,W
MOVWF STATUS
MOVF BkW,W
RETFIE
;==============Configuramos I2C
ini_i2c_slave
BANKSEL TRISC
MOVLW b'00011000'
MOVWF TRISC
BANKSEL SSPSTAT
MOVLW b'00000000'
MOVWF SSPSTAT
BANKSEL SSPCON2
MOVLW b'00000000' ; Habilita direccionamiento global
MOVWF SSPCON2
BANKSEL SSPADD
MOVLW b'01111100' ; Direccion del esclavo
MOVWF SSPADD
BANKSEL SSPCON
MOVLW b'00110110'
MOVWF SSPCON
BCF PIR1,SSPIF
BCF PIR1,7 ; Limpia Bit,mandatorio por Datasheet
;================Configuracion para interrupciones I2C
BANKSEL PIE1
BSF PIE1,SSPIE
BSF INTCON,PEIE
BSF INTCON,GIE
;==========================================
;INICIO DE PROGRAMA
;==========================================
MAIN SLEEP
NOP
GOTO MAIN
; --------------------------------------------------------------------------------------
SSP_Handler ; Este manejador controla cada evento SSP (I2C) acontecido.
; El código que se muestra abajo chequea 5 posibles estados.
; Cada uno de los 5 estados SSP son identificados haciendo
; XOR de los bits del registro SSPSTAT con mascaras de bits
; predeterminadas. Una vez que el estado ha sido identificado
; se llevan a cabo las acciones pertinentes. Los estados
; indefinidos son considerados como estados de error.
; State 1: Operación de escritura I2C, ultimo byte era de dirección.
; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1
; State 2: Operación de escritura I2C, ultimo byte era de datos.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1
; State 3: Operación de lectura I2C, ultimo byte era de dirección.
; SSPSTAT bits: S = 1, D_A = 0, R_W = 1, BF = 0
; State 4: Operación de lectura I2C, ultimo byte era de datos.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0
; State 5: Reset lógico del Slave I2C por NACK del master.
; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 0
; --------------------------------------------------------------------------------------
banksel SSPSTAT
movf SSPSTAT,W ; Obtiene el valor de SSPSTAT
andlw b'00101101' ; elimina los bits no importantes SSPSTAT.
banksel Temp
movwf Temp ; para chequeo posterior.
State1: ; Operación de escritura, ultimo byte ha sido
movlw b'00001001' ; de dirección, el buffer está lleno.
banksel Temp
xorwf Temp,W ;
btfss STATUS,Z ; Estamos en el primer estado?
goto State2 ; No, checkeamos siguiente estado
call ReadI2C ; SI. Hacemos un read SSPBUF (para vaciar buffer).
; El Hardware se ocupa de mandar Ack
return
State2: ; Operación de escritura, ultimo byte ha sido "ES MI CASO"
movlw b'00101001' ; de datos, el buffer está lleno.
banksel Temp
xorwf Temp,W
btfss STATUS,Z ; Estamos en el segundo estado?
goto State3 ; NO, checkeamos siguiente estado
call ReadI2C ; SI, Tomamos el byte del SSP.
movwf MensajeIn ;Aquí tenemos en W el valor del dato recibido
movf MensajeIn,W
movwf PORTB
return
State3: ; Operación de lectura, ultimo byte ha sido
movlw b'00001100' ; de dirección, el buffer está vacío
banksel Temp
xorwf Temp,W
btfss STATUS,Z ; Estamos en el tercer estado?
goto State4 ; NO, checkeamos siguiente estado
;Aquí debemos poner en W el valor del dato a enviar (solicitado por el master)
movf MensajeOut,W
call WriteI2C ; SI, escribimos el byte en SSPBUF
return
State4: ; Operación de lectura, ultimo byte ha sido
movlw b'00101100' ; de datos, el buffer está vacío
banksel Temp
xorwf Temp,W
btfss STATUS,Z ; Estamos en el cuarto estado?
goto State5 ; NO, checkeamos siguiente estado
;Aquí debemos poner en W el valor del dato a enviar (solicitado por el master)
movf MensajeOut,W
call WriteI2C ; SI, escribimos el byte en SSPBUF
return
State5:
movlw b'00101000' ; Se ha recibido un NACK mientras se transmitían...
banksel Temp
xorwf Temp,W ; ..datos al master. Lo lógica del Slave..
btfss STATUS,Z ; ..se resetea en este caso. R_W = 0, D_A = 1
goto I2CErr ; y BF = 0
return ; Si no estamos en State5, entonces es
; q ue algo fue mal
I2CErr
nop ; Algo fue mal
return
;---------------------------------------------------------------------
WriteI2C ;Usada por SSP_Handler para escribir datos en bus I2C
;---------------------------------------------------------------------
banksel SSPCON
movwf SSPBUF ; Escribe el dato en W
bsf SSPCON,CKP ; Libera el reloj
return
;---------------------------------------------------------------------
ReadI2C ;Usada por SSP_Handler para escribir datos en bus I2C
;---------------------------------------------------------------------
banksel SSPBUF
movf SSPBUF,W ; Toma el byte y lo guarda en W
return
END
espero que con estos tres codigos puedas analizar lo que ocurre...
saludos,