;MEDIDOR DE NIVEL CON CONVERSOR ANALOGICO DIGITAL
; HECHO POR MARLIN VARGAS

			LIST      P=16F877A
            INCLUDE   "P16F877A.INC"

CONTC		EQU		0X20				;
REG1		EQU		0X21				;
REG2		EQU		0X22				;
N1MS		EQU		0X23				;
N2MS		EQU		0X24				;
REG		EQU		0X25				;
CONTD		EQU		0X26				;
CONTU		EQU		0X27				;
CONT		EQU		0X28				;
REG3		EQU		0X29				;
RESUL		EQU		0X2A				;
VAR1		EQU		0X2B				;
RESULP		EQU		0X2C				;
CONST		EQU		0X2D				;
CONTCC		EQU		0X2E				;
STATUS_TEMP 	EQU     	0X2F          	    		; (LCD)
CONTDC		EQU		0X30				;
CONTUC		EQU		0X31				;
ASSII       	EQU     	0X32	            		; (LCD)
N1MS2		EQU		0X33				;
RETARDO     	EQU     	0X34                		; (LCD)
AUXPOR      	EQU     	0X35	            		; (LCD)
CONTMS      	EQU     	0X36	            		;
MOVLCD      	EQU     	0X37	            		; (LCD)
N2MS2		EQU		0X38				;
STATUS_LCD  	EQU     	0X39                		; (LCD)
QUINCE      	EQU     	0X3A                		; (LCD)
LCD_TEMP    	EQU     	0X3B	            		; (LCD)

;----------------------BITS A UTILIZAR------------------------------
E           	EQU     	2		            	; ENABLE DEL LCD
RW	    	EQU	    	1         		    	; MODO ESCRITURA/LECTURA DEL LCD
RS 	    	EQU     	0             			; SELECCION DEL REGISTRO

			ORG	0X00				;
			GOTO	INICIO				;
			ORG	    0X04          		;		
			;GOTO    INTERUMP      			;
			ORG     0X05          			;
INICIO
			BSF	STATUS,RP0			; ME CAMBIO AL BANCO 1
			CLRF    ADCON1				; ENTRADAS ANALOGICAS, JUSTIFICACIÓN A LA IZQUIERDA
			MOVLW	b'00011001'			; FOSC/2, CANAL 3
			MOVWF	ADCON0				; (RA3/AN3)
			CLRF	PORTA				; LIMPIO EL PUERTO A
			MOVLW	0XFF				;
			MOVWF	TRISA				; PUERTO A COMO ENTRADA
			BCF	STATUS,RP0			; VUELVO AL BANCO 0
			CALL	LCD_INI				; INICIA LA LCD
			CALL    DEMO				; ESPERA 40uS PARA LA ADQUISICION DEL DATO
			BSF	ADCON0,2			; CONVERSIÓN EN PROGRESO
CHEQUEO			BTFSC   ADCON0,2    			; TERMINO LA CONVERSION?
			GOTO    CHEQUEO				; NO. VUELVO A PREGUNTAR
			BCF	ADCON0,2			; APAGO LA CONVERSION
			MOVF	ADRESL,W			; SI. MUEVO LA CONVERSION A W
			MOVWF	REG				; MUEVO LA CONVERSION A REG

;---------------------------TRANSFORMANDO A NIVEL---------------------------------------
			MOVLW	.68				; CARGO W CON EL MAXIMO NIVEL
			MOVWF	CONT				; ESO LO LLEVO A CONTADOR DE NIVEL
			MOVF    REG,W				;
MULT			ADDWF	REG,W				; SUMO A REG CONSIGO MISMO
			DECFSZ  CONT,F              		; ES CERO?
			GOTO	MULT				; NO, SIGO MULTIPLICANDO
			MOVWF	REG3				; SI, MUEVO EL RESULTADO DE LA MULTIPLICACION A REG3
DIVI			MOVLW	.255				; MUEVO 255 A W
			SUBWF	REG3,F				; REG3 - 255, Y LO GUARDO EN REG3
			BTFSS	STATUS,C			; HAY ACARREO?, SI C=1 HUBO ACARREO
			GOTO	$+2				; NO HUBO ACARREO, VOY Y VERIFICO QUE NO HAYA TERMINADO LA DIV
			GOTO	VERI				; SI.
			BTFSC	STATUS,Z			; LLEGO AL FINAL DE LA DIVISION? SI Z=1, HUBO UN 0 EN EL RESUL
			GOTO	CENTENA				; SI, 
			INCF	RESUL,F				; INCREMENTO EL RESULTADO DE LA DIVISION
			GOTO	DIVI				; NO, SIGO RESTANDO.
VERI			MOVLW	.255				; PARA EMPEZAR LA OTRA SERIE DE RESTAS
			MOVWF	VAR1				; ESE 255 LO COPIO A VAR1
			MOVF	REG3,W				; MUEVO EL ULTIMO RESULTADO DE LA RESTA A W
			SUBWF	VAR1,W				; VAR1(255) - W(ULTIMO RFESULTADO DE LA RESTA SUCESIVA)
			MOVWF	RESULP				; GUARDO LO QUE ME DIO DE LA OPERACION ANTERIOR EN RESUL PARCIAL
			MOVLW	.0				; PARA SABER DONDE VA A EMPEZAR LA OTRA SERIE DE RESTAS
			MOVWF	CONST				; 
			MOVF    RESULP,W			; LO QUE ESTA EN RESULTADO PARCIAL LO PASO A W
			SUBWF	CONST,W				; RESTO PARA SABER DONDE EMPEZARÁ LA PROXIMA RESTA
			MOVWF	REG3				; LUEGO LO PASO A W Y
			GOTO	DIVI				; SIGO DIVIDIENO NORMAL DE NUEVO      				  
CENTENA			MOVLW	0X64				; CARGO LAS CENTENAS A W (100)
			SUBWF	REG,F				; REG - 100
			BTFSS	STATUS,C			; HUBO ACARREO?, SI C=0 HAY ACARREO
			GOTO    DECENA              		; SI, VOY A DECENA
			INCF    CONTC,F				; NO INCREMENTO CONTADOR DE CENTENAS
			CALL	MOSTRAR_NIVEL			; VOY MOSTRANDO EL NIVEL ALCANZADO
			GOTO	CENTENA				; SIGO RESTANDO
DECENA			MOVLW	0X0A 				; CARGO LAS DECENAS A W (10)
			SUBWF	REG,F				; REG - 10
			BTFSS	STATUS,C			; HUBO ACARREO?, SI C=0, HAY ACARREO
			GOTO	UNIDAD				; SI, VOY A UNIDAD
			INCF	CONTD,F				; NO, INCREMENTO CONTADOR DE DECENAS
			CALL	MOSTRAR_NIVEL			; VOY MOSTRANDO EL NIVEL ALCANZADO
			GOTO	DECENA				; SIGO RESTANDO
UNIDAD			MOVLW	0X01				; CARGO W CON LAS UNIDADES (1)
			SUBWF	REG,F				; REG - 1
			BTFSC	STATUS,Z			; LLEGO AL FINAL?, SI Z=1, HUBO UN 0 EN EL RESULTADO 
			CALL	MOSTRAR_NIVEL			; VOY MOSTRANDO EL NIVEL ALCANZADO
			INCF	CONTU,F				; INCREMENTO EL CONTADOR DE LAS UNIDADES
			CALL	MOSTRAR_NIVEL			; VOY MOSTRANDO EL NIVEL ALCANZADO
			GOTO	UNIDAD				; SIGO RESTADNO LAS UNIDADES
				
;---------------------------RUTINA DE DEMORA DE 40us------------------------------------			
DEMO
	    	MOVLW    .2             ; (1)
	    	MOVWF    N1MS           ; (1)
REP1D
	    	MOVLW    .17            ; (1)
	    	MOVWF    N2MS           ; (1)
REP2D        
	    	DECFSZ   N2MS,F         ; (1)(2)
	    	GOTO     REP2           ; (2)
	    	DECFSZ   N1MS,F         ; (1)(2)
	    	GOTO     REP1           ; (2)
	    	RETURN                  ;	

;---------------MOSTRAR LOS VALORES EN LA LCD-------------------------------

MOSTRAR_NIVEL
	        	MOVF     STATUS,W       ; MUEVE A W LO QUE ESTA EN STATUS (ESTADO DEL LCD)
			MOVWF    STATUS_TEMP    ; GUARDA LA VARIABLE STATUS
			CALL     LCDCLEAR
			MOVFW   CONTC           ; MUEVO LO CONTENIDO EN EL CONTADOR DE CENTENAS A W
			MOVWF   CONTCC          ; DE CONTC A CONTC CLON
			MOVLW   0x30            ; MUEVO 30 A W
			ADDWF   CONTCC,F        ; SUMO LA VARIABLE ORINAL + 30
			MOVFW   CONTCC 
			CALL    CARACTER        ; MANDO AL LCD
			MOVF    CONTD,W         ; MUEVO LO CONTENIDO EN EL CONTADOR DE DECENAS A W
			MOVWF   CONTDC          ; DE CONTD A CONTD CLON
			MOVLW   0x30            ; MUEVO 30 A W
			ADDWF   CONTDC,F        ; SUMO LA VARIABLE ORINAL + 30
			MOVFW   CONTDC 
			CALL    CARACTER        ; MANDO AL LCD
			MOVLW	','             ; ESCRIBIR ,
			CALL    CARACTER        ; MANDO AL LCD
			MOVF    CONTU,W         ; MUEVO LO CONTENIDO EN EL CONTADOR DE UNIDADES A W
			MOVWF   CONTUC          ; DE CONTU A CONTU CLON
			MOVLW   0x30            ; MUEVO 30 A W
			ADDWF   CONTUC,F        ; SUMO LA VARIABLE ORINAL + 30
			MOVFW   CONTUC 
			CALL    CARACTER        ; MANDO AL LCD
            		RETURN                  ;

;-----------------RUTINA DE INICIO DEL LCD---------------------------------
LCD_INI
	    	MOVF     STATUS,W       ; MUEVE A W LO QUE ESTA EN STATUS (ESTADO DEL LCD)
	    	MOVWF    STATUS_LCD     ; GUARDA LA VARIABLE STATUS
	    	BSF      STATUS,RP0	; CAMBIA AL BANCO 1
	    	BCF      STATUS,RP1     ; CAMBIA AL BANCO 1
	    	MOVLW    0X06	    	; MUEVO SEIS A W
	    	MOVWF    ADCON1         ; CONFIGURA EL PUERTO A COMO DIGITAL
	    	MOVLW    0XF8           ; PARA CONFIGURAR EL PUERTO
	    	MOVWF    TRISA          ; CONFIGURA EL PUERTO A (RA7-RA3 ENTRADAS Y RA2-RA0 SALIDAS)
	    	CLRF     TRISD          ; CONFIGURA COMO SALIDA AL PUERTO D.
	    	BCF      STATUS,RP0     ; ME CAMBIO AL BANCO 0
	    	CLRF     PORTD          ; LIMPIO EL PUERTO D
	    	CLRF     PORTA          ; LIMPIO EL PUERTO A
	    	CALL     DELAY          ; DEMORA DE 15ms PARA QUE LA LCD REGULE SUS VOLTAJES INTERNOS
	    	MOVLW    0X34           ; COLOCA AL LCD A TRABAJAR A 8 BITS EN EL BUS DE DATOS CON UNA LINEA
	    	CALL     COMANDOS       ; PARA ENVIAR INSTRUCCIONES A LA LCD
	    	MOVLW    0X08           ; PARA TEXTO. CURSOR NO VISIBLE NO PARPADEA.
	    	CALL     COMANDOS       ; PARA ESCRIBIR INSTRUCCIONES EN LA LCD
            	MOVLW    0X01           ; BORRA LA PANTALLA
	    	CALL     COMANDOS       ; PARA ESCRIBIR INSTRUCCIONES EN LA LCD
	    	MOVLW    0X0C           ; TEXTO NO VISIBLE Y CURSOR NO VISIBLE, NO PARPADEA
	    	CALL     COMANDOS       ; PARA ESCRIBIR INSTRUCCIONES EN LA LCD
	    	MOVLW    0X06           ; AUTO INCREMENTO Y TEXTO NO AVANZA
	    	CALL     COMANDOS       ; PARA ESCRIBIR INSTRUCCIONES EN LA LCD
	    	MOVF     STATUS_LCD,W   ; MUEVO EL STATUS DEL LCD A W
	    	MOVWF    STATUS         ; MUEVO EL ESTADO DEL LCD A LA VARIABLE STATUS
	    	RETURN                  ;
LCDSDDA
	    	IORLW    0X80           ; COLOCA EN 1 AL BIT 7 PARA INDICAR AL LCD QUE LA INSTRUCCIÓN QUE SE
				    				; ENVIA ES REFERENTE A LA DIRECCIÓN DDRAM
	    	CALL     COMANDOS       ; PARA ENVIAR LA INSTRUCCION A LA LCD
	    	RETURN                  ;

;------------------RUTINA DE RETRASO PARA LA LCD-------------------------------
DELAY
	    	MOVLW    0X14	    	; MUEVO 14 A W
	    	MOVWF    QUINCE         ; MUEVO 14 A QUINCE
RECAR
	    	MOVLW    0XFF	    	; MUEVO 255 A W
	    	MOVWF    RETARDO	    ; MUEVO 255 A RETARDO
	    	DECFSZ   RETARDO,F      ; DECREMENTA RETARDO, SALTA SI ES CERO
	    	GOTO     $-1            ;
	    	DECFSZ   QUINCE,F       ;
	    	GOTO     RECAR          ; NO ES CERO, REPITE LA RUTINA NUEVAMENTE
	    	RETURN                  ;

;------------------RUTINA QUE ENVIA INSTRUCCIONES A LA LCD----------------------
COMANDOS
	    	MOVWF    LCD_TEMP	; GUARDA LA INSTRUCCIÓN A ENVIAR
	    	CALL     LCD_BUSY       ; VERIFICA SI LA LCD ESTA OCUPADA
	    	BCF	 PORTA,RW	; LCD EN MODO ESCRITURA
	    	BCF	 PORTA,RS	; LCD EN MODO DE INSTRUCCION
	    	BSF      PORTA,E	; COLOCA EN 1 AL ENABLE PARA ACTIVAR AL LCD
	    	MOVF     LCD_TEMP,W     ; LEE LA INSTRUCCIÓN A ENVIAR
	    	MOVWF    PORTD          ; ENVIA LA INSTRUCCIÓN AL BUS DEL LCD
	    	BCF      PORTA,E        ; DESACTIVA A LA LCD
	    	RETURN                  ; 
 
;-----------------------------RUTINA DEL LCD-----------------------------------
LCD_BUSY
	    	BSF      STATUS,RP0     ; ME CAMBIO AL BANCO 1
	    	MOVLW    0XFF           ; CONFIGURACIÓN DEL PUERTO
	    	MOVWF    TRISD          ; CONFIGURA EL PUERTO D COMO ENTRADA
	    	BCF      STATUS,RP0     ; ME DEVUELVO AL BANCO 0
	    	BSF      PORTA,RW       ; LCD MODO LECTURA (LEO LO QUE HAY EN EL BUS)
	    	BCF      PORTA,RS       ; LCD EN MODO DE INSTRUCCIONES
	    	BSF      PORTA,E        ; HABILITO AL ENABLE
            	MOVF     PORTD,W        ; LEE LOS DATOS DEL LCD
	    	BCF	 PORTA,E        ; DESAHABILITA AL LCD
	    	MOVWF    AUXPOR         ; VARIABLE AUXILIAR PARA LEER EL ESTADO DEL LCD
	    	BTFSC    AUXPOR,7       ; SI EL BIT 7 ES IGUAL A 1 EL LCD ESTA OCUPADO
	    	GOTO     LCD_BUSY       ; VERIFICA DE NUEVO SI ESTA OCUPADO
	    	BCF      PORTA,RW       ; LCD NO ESTA OCUPADO ENTRA EN MODO DE ESCRITURA
	    	BSF      STATUS,RP0     ; ME VOY AL BANCO 1
	    	CLRF     TRISD          ; CONFIGURA EL PUERTO D COMO SALIDA
	    	BCF      STATUS,RP0     ; ME VOY AL BANCO 0 DE NUEVO
	    	RETURN                  ;

;----------------------RUTINA QUE ENVIA CARACTERES A LA LCD---------------------
CARACTER
            	MOVWF    LCD_TEMP	; GUARDA EL CARACTER A ENVIAR
	    	CALL     LCD_BUSY	; VERIFICA SI LA LCD ESTA OCUPADO
	    	BCF      PORTA,RW       ; LCD EN MODO DE ESCRITURA
	    	BSF      PORTA,RS       ; LCD EN MODO DE CARACTER
	    	BSF      PORTA,E        ; COLOCA EN 1 AL ENABLE PARA GENERAR EL FLANCO DE BAJADA
	    	MOVF     LCD_TEMP,W	; LEE EL CARACTER A ENVIAR Y LO GUARDA EN W
	    	MOVWF    PORTD          ; ENVIA EL DATO AL BUS DEL LCD
            	BCF      PORTA,E        ; GENERA EL FLANCO DE BAJADA PARA TOMAR LOS DATOS DEL BUS
	    	RETURN                  ;

;---------------RUTINA QUE DESPLAZA EL CURSOR A LA DERECHA TANTAS VECES
; TENGA EL VALOR DE W. SI W>7  SE TRUNCA A UN VALOR MAXIMO 
; DE 7 DESPLAZAMIENTOS DEL CURSOR---------------------------------------------

LCD_DERECHA 
	    	ADDLW    0X01           ; SUMA 1 CON W
	    	ANDLW    0X07           ; TRUNCA EL DESPLAZAMIENTO A MAXIMO 7
	    	MOVWF    MOVLCD         ; MUEVO ESE VALOR A LA VARIABLE MOVLCD
REPETIR     	DECFSZ   MOVLCD,F       ; DECREMENTO LA VARIABLE. SALTA SI ES CERO
	    	GOTO     MUEVE          ;
	    	RETFIE                  ; 
MUEVE	    	MOVLW    ' '            ; MUEVE EL ESPACIO EN BLANCO
	    	CALL     CARACTER       ; COLOCA CARACTERES EN BLANCO PARA MOVER EL CURSOR A LA DERECHA
	    	GOTO     REPETIR        ;

;-------------------PARA LIMPIAR LA PANTALLA DE LA LCD--------------------
LCDCLEAR
    	    MOVLW    0X001          ;
            CALL     COMANDOS       ;
            RETURN                  ;

LCDHOME
            MOVLW    0X002          ;
            CALL     COMANDOS       ;
            RETURN	            ;

;---------------------------RUTINA DE DEMORA DE 20ms------------------------------------			
DEM20MILI
	    	MOVLW    0X1A           ; (1)
	    	MOVWF    N1MS2          ; (1)
REP1
	    	MOVLW    0XFF           ; (1)
	    	MOVWF    N2MS2          ; (1)
REP2        
	    	DECFSZ   N2MS2,F        ; (1)(2)
	    	GOTO     REP2           ; (2)
	    	DECFSZ   N1MS2,F        ; (1)(2)
	    	GOTO     REP1           ; (2)
	    	RETURN                  ;

STOP
	    	NOP                     ;
	    	END                     ;	