
; ************************************ LCD_4BITX.INC *******************************************
; Programa: Manejo de LCD 16X2 con inerfaz de 4 Bits
; Utiliza unicamente el Puerto B pero usarse en cualquiera
; BUS ( RB4 - RB7 ) Pin RS ( RB3 ) Pin E ( RB2 ) el Pin R / W se coecta al Negativo
; *******************************************************************************

	CBLOCK
	LCD_GuardaDato
	LCD_Dato
	LCD_CaracteresPorLinea
	LCD_Auxiliar1
	LCD_Auxiliar2
	ENDC

#DEFINE	Pin_RS	PORTB,2			; Definicion del Pin RS
#DEFINE	Pin_E	PORTB,3			; Definicion del Pin E


; *******************************************************************************
; Inicialización del LCD ****
; *******************************************************************************

LCD_Inicializa:

	bsf	STATUS,RP0	; Seleccionar el Banco 1
	movlw	B'00000011' 	; Puerto B como salidas (Control, ( RS, RB3 )- ( E, RB2 ) )-( Datos, RB4-RB7 )
	movwf	TRISB
	movlw	B'00000111'	; Comparadores apagados 
	BCF	STATUS,RP0	; Regresar al Banco 0
	clrf	PORTB

	movlw	B'00000010'	; Habilitar el LCD
	call 	LCD_Escribe_Co	; Envíar los datos al LCD por el puerto B
	movlw	B'00101000' 	; Activar Función
	call 	LCD_Escribe_Co
	movlw	B'00000110' 	; Seleccionar Modo
	call 	LCD_Escribe_Co
	movlw	B'00001100' 	; Encender o apagar la pantalla
	call 	LCD_Escribe_Co
	movlw	B'00000001' 	; Borrar la pantalla
	call 	LCD_Escribe_Co
	return

; *******************************************************************************
; Ésta subrutina manda una instrucción o dato al LCD
; *******************************************************************************

LCD_Escribe_Co:
	bcf		Pin_RS			; RS = 0 Si es una instrucción para el LCD
	goto	Continua

LCD_Escribe_Da:
	bsf		Pin_RS			; RS = 1 Si es un dato para el LCD

; *******************************************************************************	
; Ésto es para no modificar el contenido de los 4 bit menos significativos del puerto B
; *******************************************************************************

Continua:
	movwf	LCD_GuardaDato
	movlw	0x0F
	andwf	PORTB,f			; AND entre 15 y el puerto B
	movf	LCD_GuardaDato,w	
	andlw	0xF0			; AND entre literal 240 y w en el cual esta el valor de Aux y guarda el resultado en w
	iorwf	PORTB,f			; OR entre w  y el puerto B
	bsf		Pin_E			; E = 1 Habilitar el LCD
	call	Retardo_2ms	
	bcf		Pin_E			; E = 0 Deshabilitar el LCD
	call	Retardo_2ms
	movlw	0x0F
	andwf	PORTB,f			; AND entre 15 el puerto B
	swapf	LCD_GuardaDato,w	; Intercambia los nibles de Aux y los guarda en w
	andlw	0xF0			; AND entre 240 y W, en el cual está el valor de Aux con los nibles intercambiados
	iorwf	PORTB,f			; OR entre w  y el puerto B
	bsf		Pin_E			; E = 1 Habilitar el LCD
	call	Retardo_2ms
	bcf		Pin_E			; E = 0 Deshabilitar el LCD
	call	Retardo_2ms
	return

; *******************************************************************************
; Subrutinas para manejar el LCD, Como posicion y Uso De Cursor
; *******************************************************************************

LCD_CursorIncr:				; Cursor en modo incrementar.
	movlw	b'00000110'
	goto	LCD_Escribe_Da

LCD_Linea1:					; Cursor al principio de la Línea 1.
	movlw	b'10000000'		; Dirección 00h de la DDRAM
	goto	LCD_Escribe_Da

LCD_Linea2:					; Cursor al principio de la Línea 2.
	movlw	b'11000000'		; Dirección 40h de la DDRAM
	goto	LCD_Escribe_Da

LCD_PosicionLinea1:			; Cursor a posición de la Línea 1, a partir de la
	iorlw	b'10000000'		; dirección 00h de la DDRAM más el valor del
	goto	LCD_Escribe_Co	; registro W.

LCD_PosicionLinea2:			; Cursor a posición de la Línea 2, a partir de la
	iorlw	b'11000000'		; dirección 40h de la DDRAM más el valor del
	goto	LCD_Escribe_Co	; registro W.

LCD_OFF:					; Pantalla apagada.
	movlw	b'00001000'
	goto	LCD_Escribe_Da

LCD_CursorON:				; Pantalla encendida y cursor encendido.
	movlw	b'00001110'
	goto	LCD_Escribe_Da
LCD_CursorOFF				; Pantalla encendida y cursor apagado.
	movlw	b'00001100'
	goto	LCD_Escribe_Da

LCD_Borra:					; Borra toda la pantalla, memoria DDRAM y pone el 
	movlw	b'00000001'		; cursor a principio de la línea 1.
	goto	LCD_Escribe_Da 

; *******************************************************************************	
; Rutinas para manejos Especiales, La GROM, Minusculas, Mayusculas y Simbolo de Grados Centigrado
; *******************************************************************************

LCD_CodigoCGROM:
	movwf	LCD_Dato		; Guarda el valor del carácter y comprueba si es

LCD_EnheMinuscula:			; un carácter especial.
	sublw	'ñ' 			; ¿Es la "ñ"?
	btfss	STATUS,Z
	goto	LCD_EnheMayuscula	; No es "ñ".
	movlw	b'11101110'		; Código CGROM de la "ñ".
	movwf	LCD_Dato
	goto	LCD_FinCGROM

LCD_EnheMayuscula:
	movf	LCD_Dato,W		; Recupera el código ASCII de entrada.
	sublw	'Ñ' 			; ¿Es la "Ñ"?
	btfss	STATUS,Z
	goto	LCD_Grado		; No es "Ñ".
	movlw	b'11101110'		; Código CGROM de la "ñ". (No hay símbolo para
	movwf	LCD_Dato		; la "Ñ" mayúscula en la CGROM).
	goto	LCD_FinCGROM
	
LCD_Grado:
	movf	LCD_Dato,W		; Recupera el código ASCII de entrada.
	sublw	'º' 			; ¿Es el símbolo "º"?
	btfss	STATUS,Z
	goto	LCD_FinCGROM	; No es "º".
	movlw	b'11011111'		; Código CGROM del símbolo "º".
	movwf	LCD_Dato

LCD_FinCGROM:
	movf	LCD_Dato,W		; En (W) el código buscado.
	return

; *******************************************************************************	
; Rutinas para Manejo de Espacios y Lineas en en Blanco
; *******************************************************************************

LCD_LineaEnBlanco:
	movlw	LCD_CaracteresPorLinea
	goto	LCD_EnviaBlancos

LCD_UnEspacioBlanco:
	movlw	.1
	goto	LCD_EnviaBlancos

LCD_DosEspaciosBlancos:
	movlw	.2
	goto	LCD_EnviaBlancos

LCD_TresEspaciosBlancos:
	movlw	.3

LCD_EnviaBlancos:
	movwf	LCD_Auxiliar1		; (LCD_Auxiliar1) se utiliza como contador.

LCD_EnviaOtroBlanco:	
	movlw	' '					; Esto es un espacio en blanco.
	call	LCD_Escribe_Da		; Visualiza tanto espacios en blanco como se
	decfsz	LCD_Auxiliar1,F		; haya cargado en (LCD_Auxiliar1).
	goto	LCD_EnviaOtroBlanco
	return

; *******************************************************************************	
; Rutinas Pa operaciones de Majeos de Vizualiacion de BYTE en la LCD
; *******************************************************************************

LCD_Byte:
	movwf	LCD_Auxiliar2		; Guarda el valor de entrada.
	andlw	b'11110000'			; Analiza si el nibble alto es cero.
	btfss	STATUS,Z			; Si es cero lo apaga.
	goto	LCD_VisualizaAlto	; No es cero y lo visualiza.
	movlw	' '					; Visualiza un espacio en blanco.
	call	LCD_Escribe_Da
	goto	LCD_VisualizaBajo

LCD_ByteCompleto:
	movwf	LCD_Auxiliar2		; Guarda el valor de entrada.

LCD_VisualizaAlto:
	swapf	LCD_Auxiliar2,W		; Pone el nibble alto en la parte baja.
	call	LCD_Nibble			; Lo visualiza.

LCD_VisualizaBajo:
	movf	LCD_Auxiliar2,W		; Repite el proceso con el nibble bajo.
;	call	LCD_Nibble			; Lo visualiza.
;	return

; *******************************************************************************	
; Rutinas para manejo y Viuualizacion de NIBBLE Bajo del BYTE sin importar el Alto
; *******************************************************************************

LCD_Nibble:
	andlw	b'00001111'			; Se queda con la parte baja.
	movwf	LCD_Auxiliar1		; Lo guarda.
	sublw	0x09				; Comprueba si hay que representarlo con letra.
	btfss	STATUS,C	
	goto	LCD_EnviaByteLetra
	movf	LCD_Auxiliar1,W
	addlw	'0'					; El número se pasa a carácter ASCII sumándole
	goto 	LCD_FinVisualizaDigito	; el ASCII del cero y lo visualiza.

LCD_EnviaByteLetra:
	movf	LCD_Auxiliar1,W
	addlw	'A'-0x0A			; Sí, por tanto, se le suma el ASCII de la 'A'.

LCD_FinVisualizaDigito:
	goto	LCD_Escribe_Da		; Y visualiza el carácter. Se hace con un "goto"
								; para no sobrecargar la pila.
; *******************************************************************************	
; Fin de Libreria de Manejo de LCD 16X2 podria modificarse
; *******************************************************************************

