; Write to location 0x12, data 0x34 and read it back.
; The MSSP module is used in I2C MASTER mode.                                 
	    
#define BAUD D'100'                                       ; Desired Baud Rate in kbps
#define FOSC D'4000'                                      ; Oscillator Clock in kHz
    
#include <p16F877A.inc>                                    ; Processor Include file, for standard names
							  
 __CONFIG _FOSC_XT & _WDTE_OFF & _PWRTE_ON & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF
							  
varA               EQU 20
varB               EQU 21
varC	           EQU 22					  
varD               EQU 23
BCD_Centenas	   EQU 24			; de la RAM de usuario. Se toma a continuación de
BCD_Decenas        EQU 25					; la última asignada.
BCD_Unidades       EQU 26
	
	    ORG 0                                         ; Start of code (location 0)
	    
; *** Setup I/O ***
	    clrf PORTA
	    clrf PORTB                                    ; PORTB pins set to drive low when enabled
            BANKSEL TRISC                                 ; BANK 1
            movlw B'10011000'                             ; RC3, RC4 are inputs for PORTC
            movwf TRISC                                   ; Remaining PORTC I/O lines are outputs
	    BANKSEL TRISB
	    MOVLW   B'00000000'
            movwf TRISB                                    ; all PORTB pins configured for output mode
                                                          ; (enables all PORTB drivers for driving LEDs)
; *** Setup Registers for I2C ***
                                                          ; Configure MSSP module for Master Mode
            BANKSEL SSPCON
            movlw B'00101000'                             ; Enables MSSP and uses appropriate
                                                          ; PORTC pins for I2C mode (SSPEN set) AND
                                                          ; Enables I2C Master Mode (SSPMx bits) 
            movwf SSPCON                                  ; This is loaded into SSPCON
                                                          ; Configure Input Levels and slew rate as I2C Standard Levels
            BANKSEL SSPSTAT
            movlw B'10000000'                             ; Slew Rate control (SMP) set for 100kHz
            movwf SSPSTAT                                 ; mode and input levels are I2C spec,
                                                          ; loaded in SSPSTAT
                                                          ; Configure Baud Rate
            BANKSEL SSPADD
            movlw (FOSC / (4 * BAUD)) - 1                 ; Calculates SSPADD Setting for
            movwf SSPADD                                  ; desired Baud rate and sets up SSPADD
;-------------------CONFIGURO USART--------
	    BANKSEL CMCON
            MOVLW   B'00000111'     ;modulo comparador apagado
            MOVWF   CMCON 
            BANKSEL TXSTA	    
	    MOVLW   B'00100100'     ;configuro el registro TXSTA
	    MOVWF   TXSTA
	    BANKSEL SPBRG
	    MOVLW   D'25'           ;cargo el registro SPBRG con la variable correpondiete segun la formula para 9600 baudios
            MOVWF   SPBRG
	    BANKSEL RCSTA
	    MOVLW   B'10010000'
            MOVWF   RCSTA 
; *** Begin I2C Data Transfer Sequences ***
	    
configuro_mpu:
;----------------------------
            BANKSEL SSPCON2                               ; BANK 1
            bsf SSPCON2,SEN                               ; Generate START Condition
            call WaitMSSP                                 ; Wait for I2C operation to complete
            movlw H'D0'
            call Send_I2C_Byte
            call WaitMSSP                                 ; Wait for I2C operation to completeBANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw 0x6B
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw B'10000000'
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful  
            BANKSEL SSPCON2
            bsf SSPCON2,PEN                               ; Send STOP condition
            call WaitMSSP                                 ; Wait for I2C operation to complet
;----------------------------
            BANKSEL SSPCON2                               ; BANK 1
            bsf SSPCON2,SEN                               ; Generate START Condition
            call WaitMSSP                                 ; Wait for I2C operation to complete
            movlw H'D0'
            call Send_I2C_Byte
            call WaitMSSP                                 ; Wait for I2C operation to completeBANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw 0x6B
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw B'00000000'
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful  
            BANKSEL SSPCON2
            bsf SSPCON2,PEN                               ; Send STOP condition
            call WaitMSSP                                 ; Wait for I2C operation to complet
;----------------------------
            BANKSEL SSPCON2                               ; BANK 1
            bsf SSPCON2,SEN                               ; Generate START Condition
            call WaitMSSP                                 ; Wait for I2C operation to complete
            movlw H'D0'
            call Send_I2C_Byte
            call WaitMSSP                                 ; Wait for I2C operation to completeBANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw 0x1A
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw B'00000001'
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful  
            BANKSEL SSPCON2
            bsf SSPCON2,PEN                               ; Send STOP condition
            call WaitMSSP                                 ; Wait for I2C operation to complet
;----------------------------
            BANKSEL SSPCON2                               ; BANK 1
            bsf SSPCON2,SEN                               ; Generate START Condition
            call WaitMSSP                                 ; Wait for I2C operation to complete
            movlw H'D0'
            call Send_I2C_Byte
            call WaitMSSP                                 ; Wait for I2C operation to completeBANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw 0x1B
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful
	    movlw B'00000000'
            call Send_I2C_Byte
	    call WaitMSSP 
	    BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                         ; Check ACK Status bit to see if I2C
            goto I2CFail                                  ; failed, skipped if successful  
            BANKSEL SSPCON2
            bsf SSPCON2,PEN                               ; Send STOP condition
            call WaitMSSP                                 ; Wait for I2C operation to complet
	    
	    bsf PORTB,0
	    call retardo1s
	    call retardo1s
	    bcf PORTB,0
	    
	    MOVLW     'O'               ; envia caracter A
            CALL      RS232_EnviaDato
            MOVLW     'K'               ; envia caracter T
	    CALL      RS232_EnviaDato
	    
	    bsf PORTB,0
	    call retardo1s
	    call retardo1s
	    bcf PORTB,0
	    

I2CRead:
; Send RESTART condition and wait for it to complete
            BANKSEL SSPCON2
            bsf SSPCON2,RSEN                          ; Generate RESTART Condition
            call WaitMSSP                             ; Wait for I2C operation to complete
; Send and Check CONTROL BYTE, wait for it to complete
            movlw H'D0'                          ; Load CONTROL BYTE (input)
            call Send_I2C_Byte                        ; Send Byte
            call WaitMSSP                             ; Wait for I2C operation to complete
; Now check to see if I2C EEPROM is ready
            BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                     ; Check ACK Status bit to see if I2C
            goto I2CRead                              ; ACK Poll waiting for EEPROM write to complete
; Send and Check ADDRESS BYTE, wait for it to complete
            movlw 0x43                            ; Load ADDRESS BYTE
            call Send_I2C_Byte                        ; Send Byte
            call WaitMSSP                             ; Wait for I2C operation to complete
            BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                     ; Check ACK Status bit to see if I2C
            goto I2CFail                              ; failed, skipped if successful
; Send REPEATED START condition and wait for it to complete
            bsf SSPCON2,RSEN                          ; Generate REPEATED START Condition
            call WaitMSSP                             ; Wait for I2C operation to complete
; Send and Check CONTROL BYTE (out), wait for it to complete
            movlw H'D1'                         ; Load CONTROL BYTE (output)
            call Send_I2C_Byte                        ; Send Byte
            call WaitMSSP                             ; Wait for I2C operation to complete
            BANKSEL SSPCON2
            btfsc SSPCON2,ACKSTAT                     ; Check ACK Status bit to see if I2C
            goto I2CFail                              ; failed, skipped if successful
; Switch MSSP module to I2C Receive mode
            bsf SSPCON2,RCEN                          ; Enable Receive Mode (I2C)
; Get the DATA BYTE and wait for it to complete. Data is in SSPBUF when done.
; The receive mode is disabled at end automatically by the MSSP module.
            call WaitMSSP ; Wait for I2C operation to complete
; Send NACK bit for Acknowledge Sequence
            BANKSEL SSPCON2
            bsf SSPCON2,ACKDT                         ; ACK DATA to send is 1, which is NACK.
            bsf SSPCON2,ACKEN                         ; Send ACK DATA now.
; Once ACK or NACK is sent, the ACKEN is automatically cleared by the MSSP
; Send and Check the STOP condition and wait for it to complete.
            bsf SSPCON2,PEN                           ; Send STOP condition
            call WaitMSSP                             ; Wait for I2C operation to complete
; I2C Write and Read have both finished, the value is output on LEDs.
            BANKSEL SSPBUF                            ; BANK 0
            movf   SSPBUF,W                            ; Get data from SSPBUF into W register
	    call   BIN_a_BCD
            call   RS232_EnviaDato
	    MOVLW   H'0D'               ; nueva linea
	    call   BIN_a_BCD
            CALL    RS232_EnviaDato
            MOVLW   H'0A'               ; nueva linea
	    call   BIN_a_BCD
            CALL    RS232_EnviaDato
	    call   retardo1s
; Program has finished and completed successfully.
            goto  I2CRead

; *** SUBROUTINES & ERROR HANDLERS ***
; I2C Operation Failed code sequence - This will normally not happen,
; but if it does, a STOP is sent and the entire code is tried again.
I2CFail:
           BANKSEL SSPCON2
           bsf SSPCON2,PEN                                ; Send STOP condition
           call WaitMSSP                                  ; Wait for I2C operation to complete
           BANKSEL PORTB                                  ; BANK 0
           movlw 0x01                                     ; Turn on all LEDs on PORTB
           movwf PORTB                                    ; to show error condition
           goto $                                         ; Wait forever at this location
	    
Send_I2C_Byte:
            BANKSEL SSPBUF                                ; BANK 0
            movwf SSPBUF                                  ; Get value to send from W, put in SSPBUF
            retlw 0                                       ; Done, Return 0
WaitMSSP:
            BANKSEL PIR1                                  ; BANK 0
            btfss PIR1,SSPIF                              ; Check if done with I2C operation
            goto WaitMSSP                                     ; I2C module is not ready yet
            bcf PIR1,SSPIF                                ; I2C module is ready, clear flag.
            Retlw 0                                       ; Done, Return 0
	    
;-------------------ENVIO DE DATOS SERIAL-------
RS232_EnviaDato:
        MOVWF     TXREG
	BCF       STATUS, RP1     ;accedo al banco 1
        BSF       STATUS, RP0
espero:
        BTFSS	  TXSTA,TRMT      ;verifico que ya se envio
	GOTO      espero
	BCF       STATUS, RP1     ;accedo al banco 0
        BCF       STATUS, RP0
	RETURN
	
espera_dato:
        BTFSS     PIR1,RCIF   
        GOTO      espera_dato 
si_hay_error:
	BTFSC     RCSTA,OERR
	CALL      error1
	BTFSC     RCSTA,FERR
	CALL      error2 
        MOVF      RCREG,W  
        RETURN

error1:
        BCF       RCSTA,CREN
	BSF       RCSTA,CREN
	RETURN
error2:
        MOVF      RCREG,W 
	RETURN
;-------------------BIN a BCD-------------------
BIN_a_BCD:
	clrf	BCD_Centenas		; Carga los registros con el resultado inicial.
	clrf	BCD_Decenas			; En principio las centenas y decenas a cero.
	movwf	BCD_Unidades		; Se carga el número binario a convertir.
BCD_Resta10:
	movlw	.10					; A las unidades se les va restando 10 en cada
	subwf	BCD_Unidades,W		; pasada. (W)=(BCD_Unidades) -10.
	btfss	STATUS,C			; ¿C = 1?, ¿(W) positivo?, ¿(BCD_Unidades)>=10?
	goto 	BIN_BCD_Fin			; No, es menor de 10. Se acabó.
BCD_IncrementaDecenas:
	movwf	BCD_Unidades		; Recupera lo que queda por restar.
	incf	BCD_Decenas,F		; Incrementa las decenas y comprueba si ha llegado
	movlw	.10					; a 10. Lo hace mediante una resta.
	subwf	BCD_Decenas,W		; (W)=(BCD_Decenas)-10).
	btfss	STATUS,C			; ¿C = 1?, ¿(W) positivo?, ¿(BCD_Decenas)>=10?
	goto	BCD_Resta10			; No. Vuelve a dar otra pasada, restándole 10 a
BCD_IncrementaCentenas:			; las unidades.
	clrf	BCD_Decenas			; Pone a cero las decenas 
	incf	BCD_Centenas,F		; e incrementa las centenas.
	goto	BCD_Resta10			; Otra pasada: Resta 10 al número a convertir.
BIN_BCD_Fin:
	swapf	BCD_Decenas,W		; En el nibble alto de (W) también las decenas.
	addwf	BCD_Unidades,W		; En el nibble bajo de (W) las unidades.
	return						; Vuelve al programa principal.	
;-------------------RETARDOS--------------------	    
retardo1s:
    MOVLW   D'4'
    MOVWF   varC
bucleext2:
    MOVLW   D'252'
    MOVWF   varB
bucleext:
    MOVLW   D'247'
    MOVWF   varA
bucleint:
    NOP
    DECFSZ  varA,F
    GOTO    bucleint
    DECFSZ  varB,F
    GOTO    bucleext
    DECFSZ  varC,F      
    GOTO    bucleext2
    MOVLW   D'13'      ;cargo varD para aproximarme mas aun al tiempo de retaro deseado
    MOVWF   varD
regfina:               
    DECFSZ  varD,F
    GOTO    regfina
    NOP
    NOP
    RETURN
    
            END