;******************************** Librería DS1307.INC ***********************************
;
;	===================================================================
;	  Del libro "MICROCONTROLADOR PIC16F84. DESARROLLO DE PROYECTOS"
;	  E. Palacios, F. Remiro y L. López.
; 	  Editorial Ra-Ma.  www.ra-ma.es
;	===================================================================
;
; Estas subrutinas permiten realizar las tareas de manejo del reloj-calendario DS1307
; Este dispositivo transmite la información vía serie a través de un bus I2C.
;
; ZONA DE DATOS **********************************************************************

;	CBLOCK
;	Anho				; Guarda el año.
;	Mes                 ; Guarda el mes.
;	Dia                 ; Guarda el día.
;	DiaSemana			; Guarda el día de la semana: lunes, etc.
;	Hora				; Guarda las horas.
;	Minuto				; Guarda los minutos.
;	Segundo				; Guarda los segundos.
;	ENDC

;DS1307_DireccionEscritura	EQU   0xD0    ; Dirección del DS1307.
;DS1307_DireccionLectura    EQU   0xD1
 
; Subrutina "DS1307_Inicializa" ---------------------------------------------------------
;
; Configura la señal cuadrada que genera el DS1307 en su pin SQW/OUT a 1 Hz.
DS1307_Inicializa
    CALL    I2C_EnviaStart		        ; Envía condición de Start.
    movlw   DS1307_DireccionEscritura	; 0XD0 Indica al DS1307 que el byte a escribir, e ID del RTC
	call	I2C_EnviaByte               ; 
    ; A-ACK                             ; Respuesta del SLAVE
    MOVLW   0X00                        ; Direccion de la RAM
	CALL	I2C_EnviaByte               ; 
    ; D-ACK                             ; Respuesta del SLAVE
    MOVLW   B'00000000'                 ; RAM Segundos, enciendo o apago el oscilador el BIT7 CH.
	CALL	I2C_EnviaByte               ; 1= off; 0= on
    ; D-ACK                             ; Respuesta del SLAVE

SEND_SQ
	call	Restart_I2C                 ; Envía condición de Start.
	movlw	DS1307_DireccionEscritura	; 0XD0 Indica al DS1307 que el byte a escribir,
	call	I2C_EnviaByte 
    ; A-ACK                             ; Respuesta del SLAVE
	movlw	b'00000111'                 ; Posición 07h, que corresponde  
	call	I2C_EnviaByte               ; al control de la señal cuadrada.
    ; D-ACK                             ; Respuesta del SLAVE
	movlw	b'10010000'                 ; 0X90 Escribe en el registro de control para   
	call	I2C_EnviaByte               ; Configurar onda cuadrada del DS1307 a 1 Hz.
    ; D-ACK                             ; Respuesta del SLAVE
	call	I2C_EnviaStop               ; Termina de enviar datos.
   RETURN


; Subrutina "DS1307_CargaInicial" -------------------------------------------------------
; Realiza una carga inicial en los registros internos del reloj-calendario DS1307 a fecha
; Lunes, 1 de Enero de 2004 a las 0:00:00.
DS1307_CargaInicial
	movlw	0x29			    ; 29 Inicializa todos los datos del reloj:
	movwf	Dia			        ; 
	movlw   0x10			    ; 10 Inicializa todos los datos del reloj:
	movwf	Mes
	movlw	0x02		        ;  2 Inicializa todos los datos del reloj: 
	movwf	DiaSemana
	MOVLW   0x12                ; 12
	MOVWF   Anho			    ; Inicializa en el año 2012.
    MOVLW   0x15                ; 15
	MOVWF	Hora
    MOVLW   0x16                ; 16
	MOVWF   Minuto
    MOVLW   b'00110000'         ; .30
	MOVWF   Segundo			    ; Después lo graba en el DS1307 para
	CALL    DS1307_Escribe		; ponerlo en marcha.
	RETURN

; Subrutina "DS1307_Lee" ----------------------------------------------------------------
; Se leen las variables de tiempo del DS1307 y se guardan en los registros correspondientes.
DS1307_Lee
	call	I2C_EnviaStart		        ; Envía condición de Start.
	movlw	DS1307_DireccionEscritura	; 0XD0 Indica al DS1307 que el primer byte
	call	I2C_EnviaByte		        ; a leer está en la posición 00H, que corresponde
	movlw	0x00			            ; a los segundos.
	call	I2C_EnviaByte

;	call	I2C_EnviaStop	            ; Envía condición de Stop.
    CALL    Restart_I2C
					                    ; Ahora va a leer el DS1307.
;	call	I2C_EnviaStart		        ; Envía condición de Start.
	movlw	DS1307_DireccionLectura     ; 0XD1
	call	I2C_EnviaByte
	call	I2C_LeeByte	                ; Lee los segundos.
	movwf	Segundo			            ; Lo carga en el registro correspondiente.
	call	I2C_LeeByte		            ; Lee el resto de los registros utilizando
	movwf	Minuto			            ; el mismo procedimiento.
	call	I2C_LeeByte
	movwf	Hora
	call	I2C_LeeByte
	movwf	DiaSemana
	call	I2C_LeeByte
	movwf	Dia
	call	I2C_LeeByte
	movwf	Mes
	call	I2C_LeeByte
	movwf	Anho
    CALL    Send_I2C_NoAck
	call	I2C_EnviaStop		; Acaba de leer.
	return

; Subrutina "DS1307_Escribe" ----------------------------------------------------------------
; Carga los datos de los registros Anho, Mes, etc., dentro del DS1307.
DS1307_Escribe
	call	I2C_EnviaStart		        ; Envía condición de Start.
	movlw	DS1307_DireccionEscritura	; 0XD0 Indica al DS1307 que el primer byte a escribir
	call	I2C_EnviaByte		        ; está en la posición 00h que corresponde
	movlw	0x00			            ; a los segundos.
	call	I2C_EnviaByte
	movf	Segundo,W		            ; Pasa los segundos de la memoria del PIC16F84A al
	call	I2C_EnviaByte		        ; DS1307.
	movf	Minuto,W		            ; Y se repite el proceso para el resto.
	call	I2C_EnviaByte
	movf	Hora,W
	call	I2C_EnviaByte
	movf	DiaSemana,W
	call	I2C_EnviaByte
	movf	Dia,W
	call	I2C_EnviaByte
	movf	Mes,W
	call	I2C_EnviaByte
	movf	Anho,W
	call	I2C_EnviaByte
	call	I2C_EnviaStop		        ; Termina de enviar datos.
	return

;------------------------- I2C_EnviaByte -------------------------------------------------
I2C_EnviaByte
    MOVWF   SSPBUF,0                     ;Lo carga en el Buffer de salida
    BCF     PIR1,SSPIF,0                ;borra la bandera de la interrupción  TRANSMICION COMPLETA
Write_I2C                                ;Llama a la subrutina de escritura
    BTFSC   SSPSTAT,R_W,0                ;Verifica que se ponga a cero el bit R/W
    BRA     Write_I2C                    ;Espera a que termine de enviar el dato

Write_I2C_LOOP1
    BTFSS   PIR1,SSPIF
    GOTO    Write_I2C_LOOP1
    BCF     PIR1,SSPIF,0                 ;borra la bandera de la interrupción  TRANSMICION COMPLETA

Write_I2C_LOOP2 
    BTFSC   SSPCON2,ACKSTAT,0            ;Espera a que reciba el bit de ACKNOWLEDGE
    GOTO    Write_I2C_LOOP2
    RETURN                               ;Retorna de la subrutina

;------------------------- I2C_EnviaStart -------------------------------------------------
I2C_EnviaStart
    BCF     PIR1,SSPIF,0                ;Borra la bandera de la interrupción
    BSF     SSPCON2,SEN,0               ;Pone a uno el bit de START

I2C_EnviaStart_LOOP1
    BTFSC   SSPCON2,SEN,0               ;Espera a que se ponga a cero el bit de START
    GOTO    I2C_EnviaStart_LOOP1
 
I2C_EnviaStart_LOOP2
    BTFSS   PIR1,SSPIF
    GOTO    I2C_EnviaStart_LOOP2
    BCF     PIR1,SSPIF,0                 ;borra la bandera de la interrupción  TRANSMICION COMPLETA
    RETURN                              ;Retorna de la subrutina

;------------------------- I2C_EnviaStop -------------------------------------------------
I2C_EnviaStop
    BCF     PIR1,SSPIF,0                ;Borra la bandera de la interrupción
    BSF     SSPCON2,PEN,0                ;Genera la condición de STOP poniendo a 1 el bit PEN

I2C_EnviaStop_LOOP1
    BTFSC   SSPCON2,PEN,0                ;Espera a que se ponga a cero el bit PEN
    GOTO    I2C_EnviaStop_LOOP1

I2C_EnviaStop_LOOP2
    BTFSS   PIR1,SSPIF
    GOTO    I2C_EnviaStop_LOOP2
    BCF     PIR1,SSPIF,0                 ;borra la bandera de la interrupción  TRANSMICION COMPLETA
    RETURN                               ;Retorna de la subrutina

;---------------------------------------------------------------------------------------
Restart_I2C
    BSF     SSPCON2,RSEN,0               ;Pone a uno el bit de RESTART
R2 
    BTFSC   SSPCON2,RSEN,0               ;Espera a que se ponga a cero el bit de RESTART
    BRA     R2
  
    BTFSS   PIR1,SSPIF
    BRA    $-2
    BCF     PIR1,SSPIF,0                 ;borra la bandera de la interrupción  TRANSMICION COMPLETA
    RETURN                               ;Retorna de la subrutina

;-------------------------------------------------------------------------------------------------------------------
Send_I2C_Ack 
    BCF     SSPCON2,ACKDT,0              ;Pone a cero el bit de ACKNOWLEDGE DATA
    NOP
    NOP
    NOP
    BSF     SSPCON2,ACKEN,0              ;Genera la condición de ACKNOWLEDGE Poniendo a 1 el bit ACKEN

Send_I2C_Ack_LOOP1
    BTFSS   PIR1,SSPIF
    GOTO    Send_I2C_Ack_LOOP1
    BCF     PIR1,SSPIF,0                 ;borra la bandera de la interrupción  TRANSMICION COMPLETA
    RETURN                               ;Retorna de la subrutina

;-------------------------------------------------------------------------------------------------------------------
Send_I2C_NoAck  
    BSF     SSPCON2,ACKDT,0              ;Pone a 1 el bit de ACKNOWLEDGE DATA
    NOP
    NOP
    NOP
    BSF     SSPCON2,ACKEN,0              ;Genera la condición de NO ACKNOWLEDGE Poniendo a 1 el bit ACKEN

Send_I2C_NoAck_LOOP1
    BTFSS   PIR1,SSPIF
    GOTO    Send_I2C_NoAck_LOOP1
    BCF     PIR1,SSPIF,0                 ;borra la bandera de la interrupción  TRANSMICION COMPLETA
    RETURN                               ;Retorna de la subrutina

;-------------------------------------------------------------------------------------------------------------------
I2C_LeeByte
    BCF     PIR1,SSPIF,0
    BSF     SSPCON2,RCEN,0               ;Habilita la recepción de datos mediante el bit RCEN

I2C_LeeByte_LOOP1
    NOP
    BTFSC   SSPCON2,RCEN,0               ;Espera a que se ponga a cero el bit RCEN
    GOTO    I2C_LeeByte_LOOP1

I2C_LeeByte_LOOP2
    NOP
    BTFSS   SSPSTAT,BF,0                 ;Dato disponible en SSPBUF para ser leidos?
    GOTO    I2C_LeeByte_LOOP2                        ;No, esperar
 
I2C_LeeByte_LOOP3
    BTFSS   PIR1,SSPIF
    GOTO    I2C_LeeByte_LOOP3
    BCF     PIR1,SSPIF,0                 ;borra la bandera de la interrupción  TRANSMICION COMPLETA
    RETURN                               ;Retorna de la subrutina

;-------------------------------------------------------------------------------------------------------------------

