; ZONA DE DATOS *******************************************************************
__config _CP_OFF& _CPD_OFF& _LVP_OFF& _BODEN_OFF& _PWRTE_ON& _WDT_OFF& _XT_OSC
processor 16f876A
include <p16f876A.inc>
cblock 0x20 ; Declaracion de variables Add. H20
R_ContA ; Variables de temporizaciones
R_ContB
R_ContC
PCF8574_Dato
endc
PCF8574_R/ADD EQU b'01000001' ; R/Add. Expansor I/O
PCF8574_W/ADD EQU b'01000000' ; W/Add. Expansor I/O
; MACROS ***********************************************************************
Banco0 macro
bcf STATUS,RP0 ; Banco 0
bcf STATUS,RP1
endm
Banco1 macro
bsf STATUS,RP0 ; Banco 1
bcf STATUS,RP1
endm
Banco2 macro
bcf STATUS,RP0 ; Banco 2
bsf STATUS,RP1
endm
Banco3 macro
bsf STATUS,RP0 ; Banco 3
bsf STATUS,RP1
endm
; CONFIGURACION ****************************************************************
org 0x00 ; Vector de Reset
goto Inicio
org 0x04 ; Vector de Interrupcion
goto Interrupcion
Inicio
clrf PORTB ; Limpiar Latch salidas
clrf PORTC
Banco1
movlw b'00000110'
movlw ADCON1 ; Puerta A Digital
movlw b'00111111'
movwf PORTA ; Puerta A como entrada
clrf PORTB ; PORTB como salida
movlw b'00011000' ; RC3/SCL entrada RC4/SDA entrada
movwf PORTC
movlw b'10000000'
movwf SSPSTAT ; Velocidad standar niveles I2C (100KHz y 1MHz)
movlw .9
movwf SSPADD ; Velocidad bus I2C 100KHz Fosc = 4MHz
Banco0
movlw b'00001000' ; I2C Master mode
movwf SSPCON ; clock = Fosc/(4*(SSPAD+1))
movlw b'11000000' ; Habilitación de GIE y PIE
movwf INTCON
bsf SSPCON,SSPEN ; Habilitacion modulo MSSP en I2C
clrw
call PCF8574_Escribe
; PROGRMA PRINCIPAL ************************************************************
Main ; Programa Principal
movlw 0x0F
call PCF8574_Escribe
call Retardo_500ms
Loop ; Bucle infinito
swapf PCF8574_Escribe,F
call PCF8574_Escribe
call Retardo_500ms
goto Loop
; ZONA INTERRUPCION ************************************************************
Interrupcion ; Interrupciones
nop
retfie
; ZONA SUBRUTINAS **************************************************************
; PCF8574P *********************************************************************
PCF8574_Lee ; Lee Byte de PCF8574
call I2C_Start ; Envía la condición de Start.
movlw PCF8574_R/ADD ; Apunta al expansor de lectura.
call I2C_EnviaByte
call I2C_LeeByte ; Lee el puerto.
movwf PCF8574_Dato ; Lo guarda en el registro
call I2C_NACK ; Envio NACK bit por ser ultimo Byte recivido
call I2C_Stop ; Termina.
movf PCF8574_Dato,W ; Recupera el valor del dato leído.
return
PCF8574_Escribe ; Escribe Byte en PCF8574
movwf PCF8574_Dato ; Guarda el dato a escribir.
call I2C_Start ; Envia condición de Start.
movlw PCF8574_W/ADD ; Apunta al expansor que actúa como salida.
call I2C_EnviaByte
movf PCF8574_Dato,W ; Recupera el valor del dato a enviar.
call I2C_EnviaByte ; Envía el dato.
call I2C_Stop ; Termina.
movf PCF8574_Dato,W ; Recupera el valor del dato escrito.
return
; Retardos *********************************************************************
; Retardo de 500ms
Retardo_500ms ; La llamada "call" aporta 2 ciclos máquina.
movlw d'5' ; Aporta 1 ciclo máquina. Este es el valor de "N".
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
; I2C **************************************************************************
;
; RC3/SCL y RC4/SDA Entradas
I2C_Start ; Envia Start
Banco1
bsf SSPCON2,SEN ; Activa secuencia de Start
btfsc SSPCON2,SEN
goto $-1
Banco0
btfss PIR1,SSPIF ; ¿Fin de secuencia?
goto $-1 ; No, esperar Start
bcf PIR1,SSPIF ; Reset Int Flag
return
I2C_RStart ; Envia ReStart
call I2C_Idle ; Espera estado Idle del Data Bus
Banco1
bsf SSPCON2,RSEN ; Activa secuencia de ReStart
btfsc SSPCON2,RSEN ; Sirve para redireccionar un esclavo
goto $-1 ; en la tramada sin realizar Stop
Banco0
btfss PIR1,SSPIF ; ¿Fin de secuencia?
goto $-1 ; No, esperar Start
bcf PIR1,SSPIF ; Reset Int Flag
return
I2C_EnviaByte ; Envia Byte a traves del Buffer
movwf SSPBUF ; Move Byte al Buffer
btfss PIR1,SSPIF ; ¿Tx realizada?
goto $-1
bcf PIR1,SSPIF ; Reset Int Flag
Banco1
btfsc SSPCON2,ACKSTAT ; ¿Recibido ACK?
goto $-1
Banco0
btfss PIR1,SSPIF ; ¿Fin ACK?
goto $-1
bcf PIR1,SSPIF ; Reset Int Flag
return
I2C_LeeByte ; Lee Byte del Buffer
call I2C_Idle ; Espera estado Idle del Data Bus
Banco1
bsf SSPCON2,RCEN ; Activa modo receptor
Banco0
btfss PIR1,SSPIF ; ¿Fin de secuencia?
goto $-1 ; No, esperar
movf SSPBUF,W ; Byte en SSPBUS, movemos a W
bcf PIR1,SSPIF ; Reset Int Flag
return
I2C_ACK ; Envia ACK bit
Banco1
bcf SSPCON2,ACKDT ; Flanco SDAL con SCLH
bsf SSPCON2,ACKEN ; Enviar ACK
Banco0
btfss PIR1,SSPIF ; ¿Fin de secuencia?
goto $-1
bcf PIR1,SSPIF ; Reset Int Flag
return
I2C_NACK ; Envia No ACK bit
Banco1
bsf SSPCON2,ACKDT ; Flanco SDAH con SCLH
bsf SSPCON2,ACKEN ; Enviar NACK
Banco0
btfss PIR1,SSPIF ; ¿Fin de secuencia?
goto $-1
bcf PIR1,SSPIF ; Reset Int Flag
return
I2C_Stop ; Envia Stop
Banco1
bsf SSPCON2,PEN ; Activa secuencia de Stop
Banco0
btfss PIR1,SSPIF ; ¿Fin de secuencia?
goto $-1 ; No, esperar Stop
bcf PIR1,SSPIF ; Reset Int Flag
return
I2C_Idle ; ¿Bus en Idle? ¿Bus libre?
Banco1
btfsc SSPSTAT,R_W ; ¿Hay flujo de datos?
goto $-1
movf SSPCON2,W
andlw 0x1F
btfss STATUS,Z ; ¿SSPCON2 <4:0> = 0?
goto $-3
Banco0
return ; Bus Libre
End