; ////////////////////// I2C_MASTER.INC ////////////////////////////////////////////////
; VARIABLES LOCALES ******************************************************************
CBLOCK 0xA0 ; TODAS LAS VARIABLES DEL I2C ESTAN EN EL BANK 1 !!!!!
Bus_Status ; Status Reg of I2C Bus for both TXMT & RCVE
DataByte ; load this reg with the data to be transmitted
BitCount ; The bit number (0:7) transmitted or received
SlaveAddr
ENDC
; ******************** DEFINICIONES **************************************************
; #DEFINE I2C_SCL TRISA,3 ; I2C Clock
; #DEFINE I2C_SDA TRISA,4 ; I2C Data
#DEFINE _SCL PORTA,3 ; I2C Clock Estado del Bus
#DEFINE _SDA PORTA,4 ; I2C Data Estado del Bus
; NO SE TRABAJA CON BSF NI BCF SOBRE EL PORT !!!!!
; SE PONEN AMBOS PORT LATCHS EN CERO, PULLUPS EXTERNOS DE 4K7 Y SE TRABAJA CON TRIS
; Si TRIS es 0 (output) entonces pone cero (lo que tenía en el latch).
; Si TRIS es 1 (input) entonces deja que el pullup levante a 1 (el port que High Z).
;*************************************************************************************
; I2C Bus Status Reg Bit Definitions
;*************************************************************************************
#define _Bus_Busy Bus_Status,0
#define _Abort Bus_Status,1
#define _Txmt_Progress Bus_Status,2
#define _Rcv_Progress Bus_Status,3
#define _Txmt_Success Bus_Status,4
#define _Rcv_Success Bus_Status,5
#define _Fatal_Error Bus_Status,6
#define _ACK_Error Bus_Status,7
;*************************************************************************************
RELEASE_BUS MACRO ; pone el port en Input y deja que actue el pullup externo de 4k7
bsf STATUS,RP0 ; select page 1
bsf I2C_SDA ; tristate SDA
bsf I2C_SCL ; tristate SCL
ENDM ; fin de la Macro. OJO queda en Bank 1 !!
;**************************************************************************************
; EQUIVALENCIAS ***********************************************************************
TRUE equ 1
FALSE equ 0
;*************************************************************************************
; SINGLE MASTER, MULTIPLE SLAVES
;*************************************************************************************
; I2C Bus Initialization
;*************************************************************************************
InitI2CBus_Master
bcf STATUS,RP0 ; bank 0
movf PORTA,W
andlw 0xE7 ; do not use BSF & BCF on Port Pins
movwf PORTA ; set SDA & SCL to zero. From Now on, simply play with TRIS
RELEASE_BUS ; MACRO
clrf Bus_Status ; reset status reg
return
;***************************************************************************************
; Send Start Bit
;***************************************************************************************
SendStartBit
bsf I2C_SDA ; set SDA high
bsf I2C_SCL ; set SCL high
call Delay10uS ; only necessary for setup time
bcf I2C_SDA ; give a falling edge on SDA while clock is high
call Delay10uS ; only necessary for START HOLD time
bsf _Bus_Busy ; on a start condition bus is busy
return
;****************************************************************************************
; Send Stop Bit
;****************************************************************************************
SendStopBit
bsf STATUS,RP0 ; select page 1
bcf I2C_SCL
bcf I2C_SDA ; set SDA low
bsf I2C_SCL ; Clock is pulled up
call Delay10uS
bsf I2C_SDA ; give a rising edge on SDA while CLOCK is high
bcf _Bus_Busy ; on a stop condition bus is considered Free
return
;*****************************************************************************************
; Abort Transmission / Send STOP Bit & set Abort Flag
;*****************************************************************************************
AbortTransmission
call SendStopBit
bsf _Abort
return
;*****************************************************************************************
; Transmit Address (1st Byte)& Put in Read/Write Operation
; Transmits Slave Addr On the 1st byte and set LSB to R/W operation
; Slave Address must be loaded into SlaveAddr reg
; On Success, return TRUE in WREG, else FALSE in WREG
; If desired, the failure may tested by the bits in Bus Status Reg
;*******************************************************************************************
SendSlaveAddr
bcf _ACK_Error ; reset Acknowledge error bit
movf SlaveAddr,W
movwf DataByte ; load addr to Data Byte for transmission
call SendData ; send 8 bits of address
; if successfully transmitted, expect an ACK bit
_AddrSendTest
btfss _Txmt_Success ; skip if successful
goto _AddrSendFail
retlw TRUE
_AddrSendFail
btfss _ACK_Error
retlw FALSE ; Addr Txmt Unsuccessful, so return 0
; Address Not Acknowledged, so send STOP bit
call SendStopBit
retlw FALSE ; Addr Txmt Unsuccessful, so return 0
;*******************************************************************************************
; TRANSMIT A BYTE OF DATA
; The data to be transmitted must be loaded into DataByte Reg
;*******************************************************************************************
SendData ; send 8 bits & wait for ACK
bcf _Txmt_Success ; reset status bit
movlw 0x08
movwf BitCount
TxmtNextBit
bcf I2C_SCL ; set clock low
call Delay10uS
rlf DataByte, F ; MSB first, Note DataByte Is Lost
bcf I2C_SDA
btfsc STATUS,C
bsf I2C_SDA
call Delay10uS
bsf I2C_SCL ; set clock high
; check if clock is high, else clock is being stretched
call Delay10uS
decfsz BitCount, F
goto TxmtNextBit
; Check For Acknowledge
bcf I2C_SCL ; set clock low
bsf I2C_SDA ; Release SDA line for Slave to pull down
call Delay10uS
bsf I2C_SCL ; clock for slave to ACK
call Delay10uS
bcf STATUS,RP0 ; select PAGE 0 to test PortA pin SDA
btfsc _SDA ; SDA should be pulled low by slave if OK
goto _TxmtErrorAck
bsf STATUS,RP0 ; select page 1
bcf _Txmt_Progress ; reset TXMT bit in Bus Status
bsf _Txmt_Success ; transmission successful
bcf _ACK_Error ; ACK OK
return
_TxmtErrorAck
RELEASE_BUS
bcf _Txmt_Progress ; reset TXMT bit in Bus Status
bcf _Txmt_Success ; transmission NOT successful
bsf _ACK_Error ; No ACK From Slave
return
;********************************************************************************************
; General Purpose Delay Routine
;********************************************************************************************
Delay10uS ; 2us for the Call + 8 nops + 2us for return = 10us
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
return
;********************************************************************************************
;**************************** Librería "RETARDOS.INC" *********************************
;
; ===================================================================
; Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
; E. Palacios, F. Remiro y L. López.
; Editorial Ra-Ma. www.ra-ma.es
; ===================================================================
;
; Librería con múltiples subrutinas de retardos, desde 4 microsegundos hasta 20 segundos.
; Además se pueden implementar otras subrutinas muy fácilmente.
;
; Se han calculado para un sistema microcontrolador con un PIC trabajando con un cristal
; de cuarzo a 4 MHz. Como cada ciclo máquina son 4 ciclos de reloj, resulta que cada
; ciclo máquina tarda 4 x 1/4MHz = 1 µs.
;
; En los comentarios, "cm" significa "ciclos máquina".
;
; ZONA DE DATOS *********************************************************************
CBLOCK 0x20
R_ContA ; Contadores para los retardos.
R_ContB
R_ContC
ENDC
;
; RETARDOS de 4 hasta 10 microsegundos ---------------------------------------------------
;
; A continuación retardos pequeños teniendo en cuenta que para una frecuencia de 4 MHZ,
; la llamada a subrutina "call" tarda 2 ciclos máquina, el retorno de subrutina
; "return" toma otros 2 ciclos máquina y cada instrucción "nop" tarda 1 ciclo máquina.
;
Retardo_10micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
nop ; Aporta 1 ciclo máquina.
Retardo_5micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
Retardo_4micros ; La llamada "call" aporta 2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
; RETARDOS de 20 hasta 500 microsegundos ------------------------------------------------
;
Retardo_500micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
movlw d'164' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_200micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
movlw d'64' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_100micros ; La llamada "call" aporta 2 ciclos máquina.
movlw d'31' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_50micros ; La llamada "call" aporta 2 ciclos máquina.
nop ; Aporta 1 ciclo máquina.
movlw d'14' ; Aporta 1 ciclo máquina. Este es el valor de "K".
goto RetardoMicros ; Aporta 2 ciclos máquina.
Retardo_20micros ; La llamada "call" aporta 2 ciclos máquina.
movlw d'5' ; Aporta 1 ciclo máquina. Este es el valor de "K".
;
; El próximo bloque "RetardoMicros" tarda:
; 1 + (K-1) + 2 + (K-1)x2 + 2 = (2 + 3K) ciclos máquina.
;
RetardoMicros
movwf R_ContA ; Aporta 1 ciclo máquina.
Rmicros_Bucle
decfsz R_ContA,F ; (K-1)x1 cm (cuando no salta) + 2 cm (al saltar).
goto Rmicros_Bucle ; Aporta (K-1)x2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_500micros: 2 + 1 + 1 + 2 + (2 + 3K) = 500 cm = 500 µs. (para K=164 y 4 MHz).
; - Retardo_200micros: 2 + 1 + 1 + 2 + (2 + 3K) = 200 cm = 200 µs. (para K= 64 y 4 MHz).
; - Retardo_100micros: 2 + 1 + 2 + (2 + 3K) = 100 cm = 100 µs. (para K= 31 y 4 MHz).
; - Retardo_50micros : 2 + 1 + 1 + 2 + (2 + 3K) = 50 cm = 50 µs. (para K= 14 y 4 MHz).
; - Retardo_20micros : 2 + 1 + (2 + 3K) = 20 cm = 20 µs. (para K= 5 y 4 MHz).
;
; RETARDOS de 1 ms hasta 200 ms. --------------------------------------------------------
;
Retardo_200ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'200' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_100ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'100' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_50ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'50' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_20ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'20' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_10ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'10' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_5ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'5' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_2ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'2' ; Aporta 1 ciclo máquina. Este es el valor de "M".
goto Retardos_ms ; Aporta 2 ciclos máquina.
Retardo_1ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'1' ; Aporta 1 ciclo máquina. Este es el valor de "M".
;
; El próximo bloque "Retardos_ms" tarda:
; 1 + M + M + KxM + (K-1)xM + Mx2 + (K-1)Mx2 + (M-1) + 2 + (M-1)x2 + 2 =
; = (2 + 4M + 4KM) ciclos máquina. Para K=249 y M=1 supone 1002 ciclos máquina
; que a 4 MHz son 1002 µs = 1 ms.
;
Retardos_ms
movwf R_ContB ; Aporta 1 ciclo máquina.
R1ms_BucleExterno
movlw d'249' ; Aporta Mx1 ciclos máquina. Este es el valor de "K".
movwf R_ContA ; Aporta Mx1 ciclos máquina.
R1ms_BucleInterno
nop ; Aporta KxMx1 ciclos máquina.
decfsz R_ContA,F ; (K-1)xMx1 cm (cuando no salta) + Mx2 cm (al saltar).
goto R1ms_BucleInterno ; Aporta (K-1)xMx2 ciclos máquina.
decfsz R_ContB,F ; (M-1)x1 cm (cuando no salta) + 2 cm (al saltar).
goto R1ms_BucleExterno ; Aporta (M-1)x2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_200ms: 2 + 1 + 2 + (2 + 4M + 4KM) = 200007 cm = 200 ms. (M=200 y K=249).
; - Retardo_100ms: 2 + 1 + 2 + (2 + 4M + 4KM) = 100007 cm = 100 ms. (M=100 y K=249).
; - Retardo_50ms : 2 + 1 + 2 + (2 + 4M + 4KM) = 50007 cm = 50 ms. (M= 50 y K=249).
; - Retardo_20ms : 2 + 1 + 2 + (2 + 4M + 4KM) = 20007 cm = 20 ms. (M= 20 y K=249).
; - Retardo_10ms : 2 + 1 + 2 + (2 + 4M + 4KM) = 10007 cm = 10 ms. (M= 10 y K=249).
; - Retardo_5ms : 2 + 1 + 2 + (2 + 4M + 4KM) = 5007 cm = 5 ms. (M= 5 y K=249).
; - Retardo_2ms : 2 + 1 + 2 + (2 + 4M + 4KM) = 2007 cm = 2 ms. (M= 2 y K=249).
; - Retardo_1ms : 2 + 1 + (2 + 4M + 4KM) = 1005 cm = 1 ms. (M= 1 y K=249).
;
; RETARDOS de 0.5 hasta 20 segundos ---------------------------------------------------
;
Retardo_20s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'200' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_10s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'100' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_5s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'50' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_2s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'20' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_1s ; La llamada "call" aporta 2 ciclos máquina.
movlw d'10' ; Aporta 1 ciclo máquina. Este es el valor de "N".
goto Retardo_1Decima ; Aporta 2 ciclos máquina.
Retardo_500ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'5' ; Aporta 1 ciclo máquina. Este es el valor de "N".
;
; El próximo bloque "Retardo_1Decima" tarda:
; 1 + N + N + MxN + MxN + KxMxN + (K-1)xMxN + MxNx2 + (K-1)xMxNx2 +
; + (M-1)xN + Nx2 + (M-1)xNx2 + (N-1) + 2 + (N-1)x2 + 2 =
; = (2 + 4M + 4MN + 4KM) ciclos máquina. Para K=249, M=100 y N=1 supone 100011
; ciclos máquina que a 4 MHz son 100011 µs = 100 ms = 0,1 s = 1 décima de segundo.
;
Retardo_1Decima
movwf R_ContC ; Aporta 1 ciclo máquina.
R1Decima_BucleExterno2
movlw d'100' ; Aporta Nx1 ciclos máquina. Este es el valor de "M".
movwf R_ContB ; Aporta Nx1 ciclos máquina.
R1Decima_BucleExterno
movlw d'249' ; Aporta MxNx1 ciclos máquina. Este es el valor de "K".
movwf R_ContA ; Aporta MxNx1 ciclos máquina.
R1Decima_BucleInterno
nop ; Aporta KxMxNx1 ciclos máquina.
decfsz R_ContA,F ; (K-1)xMxNx1 cm (si no salta) + MxNx2 cm (al saltar).
goto R1Decima_BucleInterno ; Aporta (K-1)xMxNx2 ciclos máquina.
decfsz R_ContB,F ; (M-1)xNx1 cm (cuando no salta) + Nx2 cm (al saltar).
goto R1Decima_BucleExterno ; Aporta (M-1)xNx2 ciclos máquina.
decfsz R_ContC,F ; (N-1)x1 cm (cuando no salta) + 2 cm (al saltar).
goto R1Decima_BucleExterno2 ; Aporta (N-1)x2 ciclos máquina.
return ; El salto del retorno aporta 2 ciclos máquina.
;
;En total estas subrutinas tardan:
; - Retardo_20s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 20000807 cm = 20 s.
; (N=200, M=100 y K=249).
; - Retardo_10s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 10000407 cm = 10 s.
; (N=100, M=100 y K=249).
; - Retardo_5s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 5000207 cm = 5 s.
; (N= 50, M=100 y K=249).
; - Retardo_2s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 2000087 cm = 2 s.
; (N= 20, M=100 y K=249).
; - Retardo_1s: 2 + 1 + 2 + (2 + 4N + 4MN + 4KMN) = 1000047 cm = 1 s.
; (N= 10, M=100 y K=249).
; - Retardo_500ms: 2 + 1 + (2 + 4N + 4MN + 4KMN) = 500025 cm = 0,5 s.
; (N= 5, M=100 y K=249).
; ===================================================================
; Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
; E. Palacios, F. Remiro y L. López.
; Editorial Ra-Ma. www.ra-ma.es
; ===================================================================
; I2C_SLAVE.ASM ----------------------------------------------------
list p=16F73
#include <p16F73.inc>
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC
ERRORLEVEL -302
ERRORLEVEL -305
#DEFINE NODE_ADDR 0x22 ; I2C address of this node
reset ORG 0x000 ; processor reset vector
goto inicio ; go to beginning of program
ORG 0x004 ; interrupt vector
goto ISR ;
inicio
call Setup
Main NOP
goto Main ; Loop forever.
; ------------------------------------SUBRUTINAS ------------------------------------------
Setup ; Initializa variables y registros
banksel PORTC
clrf PIR1
clrf SSPBUF
clrf PORTB
movlw NODE_ADDR
banksel SSPADD
movwf SSPADD
clrf SSPSTAT
clrf TRISB
MOVLW 0xFF
movwf TRISC ; ALL INPUTS (RC3 & RC4 MUST BE INPUTS)
bsf PIE1,SSPIE
bsf INTCON,PEIE ; Enable all peripheral interrupts
bsf INTCON,GIE ; Enable global interrupts
bcf STATUS,RP0
movlw 0x36 ; Setup SSP module for 7-bit
movwf SSPCON ; address, slave mode
return
; ******************* INTERRUPT **********************************************
ISR
banksel PIR1
btfss PIR1,SSPIF ; Is this an I2C interrupt?
goto salida ; No, salga.
call I2C_Handler ; Yes, service I2C interrupt.
banksel PIR1
bcf PIR1,SSPIF
salida
retfie ; Return from interrupt.
I2C_Handler
banksel SSPBUF
movf SSPBUF,W
movwf PORTB
bcf SSPCON,SSPOV ; SSPCON<6> =0 ----> No Overflow
banksel SSPSTAT ; Bank 1
bcf SSPSTAT,BF ; SSPSTAT<0> Buffer Full
return
; INCLUDES *****************************************************************
; #include <I2C_SLAVE.inc> ; subrutinas de manejo de BUS I2C
end
Hola Suki.
Bueno parece que tenías razón :-/ antes de mover algún pin del PORT A, primero tuve que mandar los que usaba para SDA y SCL a 1 y el TRISA 3 y 4 como salidas. Luego de eso te permite comandar las salidas de los pines del port con BSF y BCF directamente sobre el pin y sigue funcionando todo normal.
:shock: :shock: :shock: :?: :?: :?:sigo sin entender porqué pasa esto pero: creer o reventar :D
Ah, antes que me olvide, si pones en el Slave un dirección en el SSPADD (x ej: 0x22), hay que transmitirle exactamente ese valor para que reconozca la transmisión, o sea 0x22 y no 0x44 como pensábamos.