fbpx

Expresate

Si además quieres enviarnos un Artículo para el Blog y redes sociales, pulsa el siguiente botón:

Comunicacion i2c en...
 
Avisos
Vaciar todo

Comunicacion i2c entre un master y dos slaves

13 Respuestas
4 Usuarios
0 Reactions
7,823 Visitas
wallen74
Respuestas: 7
Topic starter
(@wallen74)
Active Member
Registrado: hace 18 años

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

Responder
12 respuestas
garrocha
Respuestas: 1110
(@garrocha)
Ardero
Registrado: hace 19 años

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

Responder
wallen74
Respuestas: 7
Topic starter
(@wallen74)
Active Member
Registrado: hace 18 años

vale pero va a salir demasiado grande el post...en cuanto llegue a
casa lo envio

Responder
wallen74
Respuestas: 7
Topic starter
(@wallen74)
Active Member
Registrado: hace 18 años

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,

Responder
Página 3 / 3
Compartir: