;*********************************************************************************************************
;************************************   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
TenK    equ 0x33	;Decenas de millar del numero de la conversion BIN2BCD
Thou    equ 0x34	;Unidades de millar del numero de la conversion BIN2BCD
Hund    equ 0x35	;Centenas del numero de la conversion BIN2BCD
Tens    equ 0x36	;Decenas del numero de la conversion BIN2BCD
Ones    equ 0x37	;Unidades del numero de la conversion BIN2BCD

		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

		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

		call	BIN2BCD

		addlw	0x30

		addwf	Ones,1
		addwf	Tens,1
		addwf	Hund,1
		addwf	Thou,1
		addwf	TenK,1

		sublw	0x30

		addwf	Ones,1
		addwf	Tens,1
		addwf	Hund,1
		addwf	Thou,1
		addwf	TenK,1

		movf	TenK,0
		call	LCD_DAT
		call	ADDRESS

		movf	Thou,0
		call	LCD_DAT
		call	ADDRESS

		movlw   0x2E		;"."
		call	LCD_DAT
		call	ADDRESS

		movf	Hund,0
		call	LCD_DAT
		call	ADDRESS

		movf	Tens,0
		call	LCD_DAT
		call	ADDRESS

		movf	Ones,0
		call	LCD_DAT
		goto	leer

;*****************************************************************************************
;Subroutines
;*****************************************************************************************
LCD_INI:
	clrf	PORTB		;PORTB = w = 00000000
	clrf	PORTC		;PORTC = 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   0xC0		;
		movwf   ADCON0		;
		bsf		ADCON0,0	;

		call	Delay_5us
		call	Delay_5us

		bsf		ADCON0,2	;

Lloop	btfss	PIR1,6
		goto	Lloop

		movf	ADRES,0
		movwf	VIN
		bcf		PIR1,6
		return

;*****************************************************************************************
;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 TOMADA DE PIC MICROCONTROLLER
;         http://www.piclist.org/techref/microchip/math/radix/b2bu-16b5d.htm
;*****************************************************************************************
BIN2BCD:
;Takes hex number in NumH:NumL  Returns decimal in ;TenK:Thou:Hund:Tens:Ones

;input
;=A3*163 + A2*162 + A1*161 + A0*160
;=A3*4096 + A2*256 + A1*16 + A0

;NumH            EQU H_byte	;AD3M   ;A3*16+A2
;NumL            EQU L_byte	;AD3L	;A1*16+A0

;share variables
;=B4*104 + B3*103 + B2*102 + B1*101 + B0*100
;=B4*10000 + B3*1000 + B2*100 + B1*10 + B0

	swapf	H_byte,w	;w  = A2*16+A3
	andlw   0x0F    ;w  = A3		*** PERSONALLY, I'D REPLACE THESE 2
	addlw   0xF0	;w  = A3-16	*** LINES WITH "IORLW b'11110000B' " -AW
	movwf   Thou	;B3 = A3-16
	addwf   Thou,f	;B3 = 2*(A3-16) = 2A3 - 32
	addlw   .226	;w  = A3-16 - 30 = A3-46
	movwf   Hund	;B2 = A3-46
	addlw   .50	;w  = A3-46 + 50 = A3+4
	movwf   Ones	;B0 = A3+4

	movf    H_byte,w	;w  = A3*16+A2
	andlw   0x0F	;w  = A2
	addwf   Hund,f	;B2 = A3-46 + A2 = A3+A2-46
	addwf   Hund,f	;B2 = A3+A2-46  + A2 = A3+2A2-46
	addwf   Ones,f	;B0 = A3+4 + A2 = A3+A2+4
	addlw   .233	;w  = A2 - 23
	movwf   Tens	;B1 = A2-23
	addwf   Tens,f	;B1 = 2*(A2-23)
	addwf   Tens,f	;B1 = 3*(A2-23) = 3A2-69 (Doh! thanks NG)

	swapf   L_byte,w	;w  = A0*16+A1
	andlw   0x0F	;w  = A1
	addwf   Tens,f	;B1 = 3A2-69 + A1 = 3A2+A1-69 range -69...-9
	addwf   Ones,f	;B0 = A3+A2+4 + A1 = A3+A2+A1+4 and Carry = 0 (thanks NG)

	rlf     Tens,f	;B1 = 2*(3A2+A1-69) + C = 6A2+2A1-138 and Carry is now 1 as tens register had to be negitive
	rlf     Ones,f	;B0 = 2*(A3+A2+A1+4) + C = 2A3+2A2+2A1+9 (+9 not +8 due to the carry from prev line, Thanks NG)
	comf    Ones,f	;B0 = ~(2A3+2A2+2A1+9) = -2A3-2A2-2A1-10 (ones complement plus 1 is twos complement. Thanks SD)

;;Nikolai Golovchenko [golovchenko at MAIL.RU] says: comf can be regarded like:
;;      comf Ones, f
;;      incf Ones, f
;;      decf Ones, f
;;First two instructions make up negation. So,
;;Ones  = -1 * Ones - 1 
;;      = - 2 * (A3 + A2 + A1) - 9 - 1 
;;      = - 2 * (A3 + A2 + A1) - 10

	rlf     Ones,f	;B0 = 2*(-2A3-2A2-2A1-10) = -4A3-4A2-4A1-20

	movf    L_byte,w	;w  = A1*16+A0
	andlw   0x0F	;w  = A0
	addwf   Ones,f	;B0 = -4A3-4A2-4A1-20 + A0 = A0-4(A3+A2+A1)-20 range -215...-5 Carry=0
	rlf     Thou,f	;B3 = 2*(2A3 - 32) = 4A3 - 64

	movlw   0x07	;w  = 7
	movwf   TenK	;B4 = 7

;B0 = A0-4(A3+A2+A1)-20	;-5...-200
;B1 = 6A2+2A1-138	;-18...-138
;B2 = A3+2A2-46		;-1...-46
;B3 = 4A3-64		;-4...-64
;B4 = 7			;7
; At this point, the original number is
; equal to TenK*10000+Thou*1000+Hund*100+Tens*10+Ones 
; if those entities are regarded as two's compliment 
; binary.  To be precise, all of them are negative 
; except TenK.  Now the number needs to be normal- 
; ized, but this can all be done with simple byte 
; arithmetic.

        movlw   .10	;w  = 10
Lb1:			;do
        addwf   Ones,f	; B0 += 10
        decf    Tens,f	; B1 -= 1
        btfss   3,0
	;skip no carry
         goto   Lb1	; while B0 < 0
	;jmp carry
Lb2:			;do
        addwf   Tens,f	; B1 += 10
        decf    Hund,f	; B2 -= 1
        btfss   3,0
         goto   Lb2	; while B1 < 0
Lb3:			;do
        addwf   Hund,f	; B2 += 10
        decf    Thou,f	; B3 -= 1
        btfss   3,0
         goto   Lb3	; while B2 < 0
Lb4:			;do
        addwf   Thou,f	; B3 += 10
        decf    TenK,f	; B4 -= 1
        btfss   3,0
         goto   Lb4	; while B3 < 0

	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
