;*********************************************************************************************************
;************************************   Xiamen DISPLAY   *************************************************
;*********************************************************************************************************

	list p=16f76
	include "p16f76.inc"
	errorlevel -302 ; supress "register not in bank0, check page bits" message
	__CONFIG _PWRTE_OFF & _BODEN_OFF &_HS_OSC & _WDT_OFF

#DEFINE ANAIN		PORTA, 0		;Entrada analógica
#DEFINE lcd_DAT		PORTB
#DEFINE lcd_RS		PORTC, 0		;LCD Register Select
#DEFINE lcd_RW		PORTC, 1		;LCD Read/Write
#DEFINE lcd_E		PORTC, 2		;LCD Enable

Same    equ     1
J		equ	0x20
K		equ	0x21
PDel0	equ	0x22
PDel1	equ	0x23
PDel2	equ	0x24
PDel3	equ	0x25
PDel4	equ	0x26
PDel5	equ	0x27
PDel6	equ	0x28
POSI	equ	0x29
VIN		equ	0x2A
TEMP1	equ	0x2D
mulcnd  equ 0x2E      ; 8 bit multiplicand
mulplr  equ 0x2F      ; 8 bit multiplier
H_byte  equ 0x30      ; High byte of the 16 bit result
L_byte  equ 0x31      ; Low byte of the 16 bit result
count	equ	0x32
aar0	equ 0x33    ;binary number low byte for BIN2BCD conversion
aar1	equ 0x34	;binary number high byte for BIN2BCD conversion
aac4	equ 0x35	;bcd number ten-thousands
aac3	equ 0x36	;bcd number thousands
aac2	equ 0x37	;bcd number hundreds
aac1	equ 0x38	;Rbcd number tens
aac0	equ 0x39	;bcd number ones

		org		0x00		;Program start
		goto	INICIO

;*****************************************************************************************
;Main program
;*****************************************************************************************
INICIO:
		clrf	STATUS
		bsf		STATUS,RP0	;Cambia a Bank 1
		clrf	ADCON1		;RA0 a RA5 todos Analógicos
	    movlw   0x01		;Pone a w = 00100000
    	movwf   PORTA  		;Pone PORTA como entradas
		bcf		STATUS,RP0	;Cambia a Bank 0

		call	Delay_500ms

;	    movlw   0xC0		;
;		movwf   ADCON0		;
;		bsf		ADCON0,0	;
;		bsf		ADCON0,2	;
;loop	btfss	PIR1,6
;		goto	loop
;		movf	ADRES,0
;		movwf	VIN
;		bcf		PIR1,6

		clrf	STATUS
		bsf		STATUS,RP0	;Cambia a Bank 1
	    movlw   0x00    	;Pone a w = 00000000
    	movwf   PORTB  		;Pone a PORTB & PORTC como salidas
    	movwf   PORTC
		bcf		STATUS,RP0	;Cambia a Bank 0

		call	LCD_INI

;DIRECCIONES DDRAM
; 0x80 LINEA 1 POSICION 1
; 0xC0 LINEA 2 POSICION 1
; 0x94 LINEA 3 POSICION 1
; 0xD4 LINEA 4 POSICION 1
;
;   1    2    3    4    5    6    7    8    9    10   11   12   13   14   15   16   17   18   19   20
;  ___________________________________________________________________________________________________
; | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 8A | 8B | 8C | 8D | 8E | 8F | 90 | 91 | 92 | 93 |
; |---------------------------------------------------------------------------------------------------|
; | C0 | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9 | CA | CB | CC | CD | CE | CF | D0 | D1 | D2 | D3 |
; |---------------------------------------------------------------------------------------------------|
; | 94 | 95 | 96 | 97 | 98 | 99 | 9A | 9B | 9C | 9D | 9E | 9F | A0 | A1 | A2 | A3 | A4 | A5 | A6 | A7 |
; |---------------------------------------------------------------------------------------------------|
; | D4 | D5 | D6 | D7 | D8 | D9 | DA | DB | DC | DD | DE | DF | E0 | E1 | E2 | E3 | E4 | E5 | E6 | E7 |
; |___________________________________________________________________________________________________|
;
		movlw   0x80		;Set DDRAM Address
		movwf   POSI
		call	LCD_CMD

		call	Delay_50ms

		movlw   0x56		;"V"
		call	LCD_DAT
		call	ADDRESS

		movlw   0x69		;"i"
		call	LCD_DAT
		call	ADDRESS

		movlw   0x6E		;"n"
		call	LCD_DAT
		call	ADDRESS

		movlw   0x3D		;"="
		call	LCD_DAT
		call	ADDRESS

leer	call	Delay_500ms
		movlw   0x84		;Set DDRAM Address
		movwf   POSI
		call	LCD_CMD

		call	LEER_ADC

		movlw	.125
		movwf	mulcnd
		movf	VIN,0
		movwf	mulplr

		call	multiplica

		movf	H_byte,0
		movwf	aar1

		movf	L_byte,0
		movwf	aar0

		call	BIN2BCD

		addlw	0x30

		addwf	aac0,1
		addwf	aac1,1
		addwf	aac2,1
		addwf	aac3,1
		addwf	aac4,1

		sublw	0x30

		addwf	aac0,1
		addwf	aac1,1
		addwf	aac2,1
		addwf	aac3,1
		addwf	aac4,1

		movf	aac4,0
		call	LCD_DAT
		call	ADDRESS

		movf	aac3,0
		call	LCD_DAT
		call	ADDRESS

		movlw   0x2E		;"."
		call	LCD_DAT
		call	ADDRESS

		movf	aac2,0
		call	LCD_DAT
		call	ADDRESS

		movf	aac1,0
		call	LCD_DAT
		call	ADDRESS

		movf	aac0,0
		call	LCD_DAT
		goto	leer





;*****************************************************************************************
;Subroutines
;*****************************************************************************************
LCD_INI:
	clrf	PORTB		;PORTA = w = 00000000
	clrf	PORTC		;PORTB = w = 00000000

	call	Delay_32ms

	movlw   0x38		;Function Set
	call	LCD_CMD

	call	Delay_40us

	movlw   0x0C		;Display ON/OFF Control
	call	LCD_CMD

	call	Delay_40us

	movlw   0x01		;Clear Display
	call	LCD_CMD

	call	Delay_2ms

	movlw   0x06		;Entry Mode Set
	call	LCD_CMD

	call	Delay_50ms

	return

LCD_E:
	bsf		lcd_E		;LCD Enable=1
	nop
	bcf		lcd_E		;LCD Enable=0
	return

LCD_CMD:
	bcf		lcd_E		;LCD Enable=0
	bcf		lcd_RW		;Activate Write operation RW=0
	bcf		lcd_RS		;RS=0
	movwf	PORTB
	bsf		lcd_E		;LCD Enable=1
	bcf		lcd_E		;LCD Enable=0
	return

LCD_DAT:
	bcf		lcd_E		;LCD Enable=0
	bcf		lcd_RW		;Activate Write operation RW=0
	bsf		lcd_RS		;RS=1
	movwf	PORTB
	bsf		lcd_E		;LCD Enable=1
	bcf		lcd_E		;LCD Enable=0
	return

ADDRESS:
	INCF    POSI, 1		;Incrementa posicion del cursor
	movlw   POSI		;Set DDRAM Address
	call	LCD_CMD

	call	Delay_50ms

	return

;*****************************************************************************************
;SUBRUTINA PARA LEER EL CONVERSOR A/D
;*****************************************************************************************
LEER_ADC:
	movlw	b'11000001'
	movwf	ADCON0

	movlw 	.20
	movwf	TEMP1
	decfsz	TEMP1,F
	goto	$-1

  	bsf		ADCON0,GO_DONE

  	movlw 	.20
	movwf	TEMP1
	decfsz	TEMP1,F
	goto	$-1

	btfsc	ADCON0,GO_DONE

	goto	$-1

	movf	ADRES,0
	movwf	VIN

	return

;*****************************************************************************************
;ESTA ES LA SUBRUTINA BUENA DE MULTIPLICACION DE 2 x 8 BITS
;*****************************************************************************************
multiplica:
		clrf	H_byte
		clrf	L_byte
		movlw	8
		movwf	count
		movf	mulcnd,W
		bcf		STATUS,C ; Clear the carry bit in the status Reg.
loop	rrf		mulplr, F
		btfsc	STATUS,C
		addwf	H_byte,Same
		rrf		H_byte,Same
		rrf		L_byte,Same
		decfsz	count, F
		goto	loop

		retlw 0

;*****************************************************************************************
;SUBRUTINA DE BINARIO A BCD
;*****************************************************************************************
BIN2BCD:

;aar0 = binary number low byte
;aar1 = binary number high byte
;aac0 = bcd number ones
;aac1 = bcd number tens
;aac2 = bcd number hundreds
;aac3 = bcd number thousands
;aac4 = bcd number ten-thousands
 
;b16_d5
	swapf   aar0,w	; partial ones sum in low byte
	addwf   aar0,w	;
	andlw   0x0f	;
	skpndc		;
	addlw 	0x16	;
	skpndc		;
	addlw  	0x06	;
	addlw   0x06	;
	skpdc		;
	addlw  	-0x06	; wmax=3:0

	btfsc   aar0,4	; complete ones sum in low byte
	addlw   0x15+0x06
	skpdc 
	addlw  	-0x06	; wmax=4:5
	movwf	aac0	; save sum in aac0
;
;     8+      4+     2+     1+     8+     4+    2+    1+
;    20
;   100      60     30     15+
;   ----------------------------------------------------
;   128      64     32     16      8      4     2     1
;
        swapf   aar1,w	; partial ones sum in high byte
        addwf   aar1,w	;
        andlw   0x0f	;
        skpndc		;
        addlw 	0x16	;
        skpndc		;
        addlw  	0x06	;
        addlw   0x06	;
        skpdc		;
	addlw  	-0x06	; wmax=3:0
;
	btfsc   aar1,0	; complete ones sum in high byte
        addlw   0x05+0x06
        skpdc 
        addlw  	-0x06	; wmax=3:5
;
        btfsc   aar1,4
        addlw   0x15+0x06
        skpdc 
        addlw  	-0x06	; wmax=5:0
;
	addlw	0x06	; include previous sum
	addwf	aac0,w
        skpdc 
        addlw  	-0x06	; wmax=9:5, ones sum ended
;
	movwf	aac0
	movwf	aac1
	swapf	aac1,f
	movlw	0x0f
	andwf	aac0,f	; save total ones sum in aac0
	andwf	aac1,f	; save partial tens sum in aac1
;
;     8+      4+     2+     1+     8+     4+    2+    1+
;                           5+
;    60      80     90     10+                        5+
;   700     300    100     80     40     20    10    50 
; 32000   16000   8000   4000   2000   1000   500   200
; ------------------------------------------------------
; 32768   16384   8192   4096   2048   1024   512   256
;
			; complete tens sum in low and high byte
	rrf	aar1,w	; rotate right high byte once
	andlw	0x0f	; clear high nibble
	addlw	0x06	; adjust bcd
	skpdc
	addlw	-0x06	; wmax=1:5
;
	addlw	0x06	; include previous sum
	addwf	aac1,w
        skpdc 
        addlw  	-0x06	; wmax=2:4
;
        btfsc   aar0,5
        addlw   0x03+0x06
        skpdc 
        addlw  	-0x06	; wmax=2:7
;
        btfsc   aar0,6
        addlw   0x06+0x06
        skpdc 
        addlw  	-0x06	; wmax=3:3
;
        btfsc   aar0,7
        addlw   0x12+0x06
        skpdc 
        addlw  	-0x06	; wmax=4:5
;
        btfsc   aar1,0
        addlw   0x25+0x06
        skpdc 
        addlw  	-0x06	; wmax=7:0
;
        btfsc   aar1,5
        addlw   0x09+0x06
        skpdc 
        addlw  	-0x06	; wmax=7:9
;
        btfsc   aar1,6
        addlw   0x08+0x06
        skpdc 
        addlw  	-0x06	; wmax=8:7
;
        btfsc   aar1,7
        addlw   0x06+0x06
        skpdc 
        addlw  	-0x06	; wmax=9:3, tens sum ended
;
	movwf	aac1	; save total tens sum in aac1
	swapf	aac1,w
	andlw	0x0f	; load partial hundreds sum in w
;
;     8+      4+     2+     1+     8+     4+    2+    1+
;    20+                    5+
;   100+     60+    30+    10+
;   ----------------------------------------------------
;   128      64     32     16      8      4     2     1
;
;     8+      4+     2+     1+     8+     4+    2+    1+
;                           5+
;    60+     80+    90+    10+                        5+
;   700     300    100     80+    40+    20+   10+   50+
; 32000   16000   8000   4000   2000   1000   500   200+
; ------------------------------------------------------
; 32768   16384   8192   4096   2048   1024   512   256
;
			; complete hundreds sum in high byte
        btfsc   aar1,1
        addlw   0x05+0x06
        skpdc 
        addlw  	-0x06	; wmax=1:4
;
        btfsc   aar1,5
        addlw   0x01+0x06
        skpdc 
        addlw  	-0x06	; wmax=1:5
;
        btfsc   aar1,6
        addlw   0x03+0x06
        skpdc 
        addlw  	-0x06	; wmax=1:8
;
        btfsc   aar1,7
        addlw   0x07+0x06
        skpdc 
        addlw  	-0x06	; wmax=2:5, hundreds sum ended
;
	movwf	aac2	; save total hundreds sum in aac2
	swapf	aac2,w
	movwf	aac3	; save partial thousands sum in aac3	
	movlw	0x0f	; clear high nibble
	andwf	aac1,f	;
	andwf	aac2,f	;
	andwf	aac3,f	;
;
;     8+      4+     2+     1+     8+     4+    2+    1+
;                           5+
;    60+     80+    90+    10+                        5+
;   700+    300+   100+    80+    40+    20+   10+   50+
; 32000   16000   8000   4000   2000   1000   500+  200+
; ------------------------------------------------------
; 32768   16384   8192   4096   2048   1024   512   256
;
			; complete thousands sum in low and high byte
	rrf	aar1,w	; rotate right high byte twice
	movwf	aac4	;
	rrf	aac4,w	;
	andlw	0x0f	; clear high nibble
	addlw	0x06	; adjust bcd
	skpdc		;
	addlw	-0x06	; wmax=1:5
;
	addlw	0x06	; include previous sum
	addwf	aac3,w
	skpdc
	addlw	-0x06	; wmax=1:7
;
        btfsc   aar1,6
        addlw   0x16+0x06
	skpdc
	addlw	-0x06	; wmax=3:3
;
        btfsc   aar1,7
        addlw   0x32+0x06
	skpdc
	addlw	-0x06	; wmax=6:5, thousands sum ended
;
	movwf	aac3	; save total thousands sum in aac3
	movwf	aac4	;
	swapf	aac4,f	; save ten-thousands sum in aac4
	movlw	0x0f	; clear high nibble
	andwf	aac3,f	;
	andwf	aac4,f	;


	return

;*****************************************************************************************
;Delay 5 useg subroutine
;*****************************************************************************************
Delay_5us:
	goto D1         ; 2 ciclos delay
D1  goto D2         ; 2 ciclos delay
D2  goto D3         ; 2 ciclos delay
D3  goto D4         ; 2 ciclos delay
D4  goto D5         ; 2 ciclos delay
D5  				; 1 ciclo delay
	return			; 2+2 Fin.

;*****************************************************************************************
;Delay 40 useg subroutine
;*****************************************************************************************
Delay_40us:
		movlw	.18			; 1 set numero de repeticion 
		movwf	PDel0		; 1 |
PLoop0	clrwdt				; 1 clear watchdog
		decfsz	PDel0, 1	; 1 + (1) es el tiempo 0  ?
		goto	PLoop0		; 2 no, loop
PDelL1	goto	PDelL2		; 2 ciclos delay
PDelL2	clrwdt				; 1 ciclo delay
		return				; 2+2 Fin.

;*****************************************************************************************
;Delay 2 mseg subroutine
;*****************************************************************************************
Delay_2ms:
		movlw	.5			; 1 set numero de repeticion  (B)
        movwf	PDel1		; 1 |
PLoop1  movlw	.159		; 1 set numero de repeticion  (A)
        movwf	PDel2		; 1 |
PLoop2  clrwdt				; 1 clear watchdog
        clrwdt				; 1 ciclo delay
        decfsz	PDel2, 1	; 1 + (1) es el tiempo 0  ? (A)
        goto	PLoop2		; 2 no, loop
        decfsz	PDel1, 1	; 1 + (1) es el tiempo 0  ? (B)
        goto	PLoop1		; 2 no, loop
        return				; 2+2 Fin.

;*****************************************************************************************
;Delay 32 mseg subroutine
;*****************************************************************************************
Delay_32ms:
		movlw	.89			; 1 set numero de repeticion  (B)
		movwf	PDel3		; 1 |
PLoop3  movlw	.143		; 1 set numero de repeticion  (A)
        movwf	PDel4		; 1 |
PLoop4  clrwdt				; 1 clear watchdog
        clrwdt				; 1 ciclo delay
        decfsz	PDel4, 1	; 1 + (1) es el tiempo 0  ? (A)
        goto	PLoop4		; 2 no, loop
        decfsz	PDel3, 1	; 1 + (1) es el tiempo 0  ? (B)
        goto	PLoop3		; 2 no, loop
PDelL3  goto	PDelL4		; 2 ciclos delay
PDelL4  goto	PDelL5		; 2 ciclos delay
PDelL5						; 1 ciclo delay
        return				; 2+2 Fin.

;*****************************************************************************************
;Delay 50 mseg subroutine
;*****************************************************************************************
Delay_50ms:
		movlw	.110		; 1 set numero de repeticion  (B)
        movwf	PDel5		; 1 |
PLoop5  movlw	.181		; 1 set numero de repeticion  (A)
        movwf	PDel6		; 1 |
PLoop6  clrwdt				; 1 clear watchdog
        clrwdt				; 1 ciclo delay
        decfsz	PDel6, 1	; 1 + (1) es el tiempo 0  ? (A)
        goto	PLoop6		; 2 no, loop
        decfsz	PDel5, 1	; 1 + (1) es el tiempo 0  ? (B)
        goto	PLoop5		; 2 no, loop
PDelL6  goto	PDelL7		; 2 ciclos delay
PDelL7  goto	PDelL8		; 2 ciclos delay
PDelL8  clrwdt				; 1 ciclo delay
        return				; 2+2 Fin.

;*****************************************************************************************
;Delay 500 mseg subroutine
;*****************************************************************************************
Delay_500ms:
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
		call	Delay_50ms
        return

	end
