;****************************************************************************************
;* PIC microproject														Date: 10.11.07	*
;*																						*
;* FILE: Display-5					2x16-Characters 					Navn: GC		*
;*  																					*
;* Device: PIC16F684				Indirect Addressing									*
;*									+ADC	+Knap	+BinDec-Converter					*
;*																						*
;* Limits on ADC-value controls LED D0													*
;* SW1 clears display and controls LED D1												*
;* ADC-value is displayed as ASCII-character and 3 digit decimal (BinDec)				*
;*																						*
;****************************************************************************************

;	H'<HEX>'	D'<Decimal>'	B'<Binary>'		A'<ASCII>'

; 	Registers and constants are defined here:
INDF	equ H'00'	; Indirect Register (Uses content of FSR)
PCL		equ H'02'	; Program Counter Low byte address
STATUS	equ	H'03'	; Status-register
FSR		equ H'04'	; Indirect Data Memory Address Pointer
PORTA	equ	H'05'	; Input/output-register A
TRISA	equ	H'05'	; Bank-1, input/output configuration A
PORTC	equ	H'07'	; Input/output-register C
TRISC	equ	H'07'	; Bank-1, input/output configuration C

CMCON0	equ H'19'	; Comparator control register
ANSEL	equ H'11'	; Bank-1, Analog select register (ADC conversion Clock)
ADRESH	equ H'1E'	; ADC result-high register
ADRESL	equ H'1E'	; Bank-1, ADC result-low register
ADCON0	equ H'1F'	; ADC Control register 
ADCON1	equ H'1F'	; Bank-1, ADC Control register

; 	RAM-registers used by routines:
Ux		equ	H'20'	; Ux? (ADConverter)
Ref_1	equ	H'21'	; Low_?
Ref_2	equ H'22'	; High_?
Dly_1	equ H'23'	; Delay
Dly_2	equ H'24'	; Delay2
Tmp_1	equ H'25'	; Vr_Char, TxtOut, Dis_Pos
Tmp_2	equ H'26'	; 
Tmp_3	equ H'27'	; 
Tmp_4	equ	H'28'	; 
Nr		equ	H'29'	; BinDec
x100	equ H'2A'	; BinDec, DisADC
x10		equ H'2B'	; BinDec, DisADC
x1		equ	H'2C'	; BinDec, DisADC

Text_1	equ H'30'	; Startlocation of Txt#1

		list p=16F684

		org		H'05'		; Start of program  (05)

;*************************************** Chip setup *************************************


Bank_1	bsf		STATUS,5	; Switch to Bank-1 for setup

PORT_A	movlw	B'11001111'	; RA0 is ADC-input
		movwf	TRISA		; RA5 and RA4 are digital outputs
							; RA2 and RA1 are digital inputs (Tristate)

PORT_C	clrf	TRISC		; PORTC= Outputs (TRISC<5:0>= 000000)
							; Bit5=RS, Bit4=Strobe, Bit<3:0>=Data (Nibble)

		movlw	B'00000001'	; RA0: ADC-Input, All other pins = digital I/O
		movwf	ANSEL		; 
		movlw	B'00010000' ; Bit<6:4> ADC Clock=Fosc/8
		movwf	ADCON1

Bank_0	bcf		STATUS,5	; Switch back to Bank-0

ADC		movlw	H'07'		; CM<2:0>=111	=>			!!! IMPORTANT !!!
		movwf	CMCON0		; Disable comparator, 		General purpose I/O

		movlw	B'00000000'	; Bit7=0:	0-------, Makes ADC Result Left justified (8 Bits used)
							; Bit6=0:	-0------, Vref for ADC =VDD
		movwf	ADCON0		; Bit<4:2>	---000--, Channel 0 selected: RA0/AN0= ADC-input
							; Bit1:		------1-, ADC start and Busy test bit
							; Bit0=1:	-------1, Turns on AD-Converter

		movlw	D'85'		; Ref_1	:	Low limit
		movwf	Ref_1		; (85/255:  ca.33%)

		movlw	D'170'		; Ref_2	:	High limit
		movwf	Ref_2		; (170/255: ca.66%)

		clrf	PORTA		; PORTA Outputs are cleared (LED's off)
		clrf	PORTC		; PORTC Outputs are cleared


; Text_1							Characters used by Txt#1 Routine

		movlw	A'H'		; H		ASCII-Code !	Display-Characters are loaded into RAM.
		movwf	H'30'		; 	<=	(Text starts at 30h)
		movlw	A'T'		; T
		movwf	H'31'
		movlw	A'X'		; X
		movwf	H'32'
		movlw	A'-'		; -
		movwf	H'33'
		movlw	A'E'		; E		
		movwf	H'34'			
		movlw	A's'		; s
		movwf	H'35'
		movlw	A'b'		; b
		movwf	H'36'
		movlw	A'j'		; j
		movwf	H'37'
		movlw	A'e'		; e
		movwf	H'38'
		movlw	A'r'		; r
		movwf	H'39'
		movlw	A'g'		; g
		movwf	H'3A'
		movlw	A' '		; <Blank>
		movwf	H'3B'
		movlw	A'2'		; 2
		movwf	H'3C'
		movlw	A'0'		; 0
		movwf	H'3D'
		movlw	A'0'		; 0
		movwf	H'3E'
		movlw	A'7'		; 7
		movwf	H'3F'
		movlw	A'*'		; *		Star: ends read-out (Se: Txt#1 subroutine)
		movwf	H'40'

		goto	start

;***********************************   Subroutines   ************************************

		;	Outputs:	LED's are on PICkit-1 USB demo-board
Led_0	movlw	B'010000'	; Turns on D0
		movwf	PORTA		; 
		return				;

Led_1	movlw	B'100000'	; Turns on D1
		movwf	PORTA		;
		return				;

		;	Signaling to Display-unit that Data is ready (4-bit)
Strobe1	bsf		PORTC,5		; Set RS=1 for writing Characters to Display-unit
Strobe	movlw	H'01'		; (Set RS=0 for writing commands to Display-unit)
		call	Delay		; Wait (9 uS)
		bsf		PORTC,4		; Write PORTC-data to display
		movlw	H'01'		; Wait (9 uS)
		call	Delay
		bcf		PORTC,4
		movlw	H'01'		; Wait (9 uS)
		call	Delay
		return

		;	Short delays used by:	Delay2, Ux?, Strobe, Various Display-routines
Delay	movwf	Dly_1		; Store W in Dly_1 (23H)
lp_d	decfsz	Dly_1,f		;   
		goto	lp_d		; 
		return				; 

		; 	Long delays used by:	Various Display-routines
Delay2	movwf	Dly_2		; Store W in Dly_2 (24H)
		movlw	H'00'		
lp_d2	call	Delay		; 
		decfsz	Dly_2,f
		goto	lp_d2
		return

		;	Setup-routine for Display-unit.
Dis_Ini	movlw	H'43'		; Delay after power on (50mS)
		call	Delay2		; Display "wakes up"

		bcf		PORTC,5		; RS=0, Command mode
		movlw	B'0010'		; 4-bit mode
		movwf	PORTC
		call	Strobe
		movlw	H'06'		; Wait (4,6mS)
		call	Delay2

Fnc_Set	movlw	B'0010'		; Switch display to 4-bit mode
		movwf	PORTC
		call	Strobe
		movlw	B'1000'		; 2 display-lines in use
		movwf	PORTC
		call	Strobe
		movlw	H'10'		; Wait (50uS)
		call	Delay

Disp_On	movlw	B'0000'		; Turning ON the Display 
		movwf	PORTC
		call	Strobe
		movlw	B'1100'		; 1,D,C,B		D: Display ON,	C: Cursor OFF,	B: Blink OFF,
		movwf	PORTC		; 				 (1=ON, 0=OFF)
		call	Strobe
		movlw	H'10'		; Wait (50uS)
		call	Delay

Ent_Mod	movlw	B'0000'		; Entry mode
		movwf	PORTC
		call	Strobe
		movlw	B'0110'		; 0,1,I/D,S		I/D: Increment/Decrement,	S: Shift display
		movwf	PORTC		; 	->
		call	Strobe
		movlw	H'10'		; Wait (50 uS)
		call	Delay
		return


Dis_Off	clrf	PORTC		; Blanks Display!	RS=0 & Data=0
		call	Strobe
		movlw	B'1000'		; 1,D,C,B		
		movwf	PORTC		; D: Display OFF,	C: Cursor OFF,	B: Blink OFF,	(1=ON, 0=OFF)
		call	Strobe
		movlw	H'10'		; Wait (50uS)
		call	Delay
		return

Dis_Clr	clrf	PORTC		; Display is cleared, cursor home at start (00)
		call	Strobe		; RS=0 & Data=0
		movlw	B'0001'		; 
		movwf	PORTC
		call	Strobe
		movlw	H'06'		; Wait (4,6mS)
		call	Delay2
		return

Cur_Hom	clrf	PORTC		; Cursor home at start (00), text remains on display
		call	Strobe		; RS=0 & Data=0
		movlw	B'0010'		; 
		movwf	PORTC
		call	Strobe
		movlw	H'06'		; Wait (4,6mS)
		call	Delay2
		return

		;	Writes single characters to Display-unit
Wr_Char	movwf	Tmp_1		; save a copy
		swapf	Tmp_1,w		; Swap high-nibble to low-nibble, 
		movwf 	PORTC		; Send high-nibble first!
		call	Strobe1		; Set RS=1 (by using: Strobe1) for writing to display-unit
		movf	Tmp_1,w		; Send low-nibble
		movwf 	PORTC
		call	Strobe1
		movlw	H'10'		; Wait (50 uS)
		call	Delay
		return


		;	Writes text-string to Display-unit. Trailing * ends read-out.
Txt#1	movlw	Text_1		; Text starting address
TxtOut	movwf	FSR			; Set text-pointer for indirect addressing
Next_C	movf	INDF,w		; Get Character -
		call	Wr_Char		; Write Character to Display-unit
		incf	FSR,f		; Move pointer to next character
		movf	INDF,w		; Get next character -
		movwf	Tmp_1		; save a copy
		sublw	A'*'		; Test for last character = *
		btfss	STATUS,2	; Z=1 ?
		goto	Next_C		; No!	Continue
		return

		;	Write ADC-value as ASCII caracter
Dis_Ux	movlw	H'40'		; Set Display-pointer at 40h
		call	Dis_Pos		; -> 40h (Left, on displayline 2)
		call	Ux?
		call	Wr_Char		; Write ADC-value as ASCII character @ 40h !
		return

		;	Displays AD-Converter value in 3 digits Decimal characters
DisADC	call 	BinDec		; Converts 8-bits to 3-digit Decimal number for Display.
		movlw	H'4D'		; Writes ADC in 3 digits Decimal characters @ 4Dh
		call	Dis_Pos		; -> 4Dh (Right, on display-line 2)
		movf	x100,w
		call	Wr_Char
		movf	x10,w
		call	Wr_Char
		movf	x1,w
		call	Wr_Char
		Return

		;	Value in W holds cursor position for text start on display-unit
Dis_Pos	movwf	Tmp_1		; Save a copy in Temp_1
		swapf	Tmp_1,w		; High nibble first !		NB:Bit<3:0>on PORTC =Data Out
		movwf	PORTC		; Bit5=RS, Bit4=Strobe, 
		bcf		PORTC,5		; RS=0	for command mode
		bsf		PORTC,3		; ADD mode
		call	Strobe		; Transfer data to display-unit
		movf	Tmp_1,w
		movwf	PORTC		; Low nibble next.
		bcf		PORTC,5		; RS=0	for command mode
		call	Strobe		; Transfer data to display-unit
		movlw	H'10'
		call	Delay		; Wait 50us
		return


		;	Reads ADC-value
Ux?		bsf		ADCON0,0	; Turn on ADC Converter
		movlw	D'4'		; W contains delay-value for Dly_1 (23h)
		call	Delay		; Delay
		bsf		ADCON0,1	; GO, Start AD-Conversion
loop1	btfsc	ADCON0,1	; Done ?	(Bit1: ADC Start and Busy test-bit)
		goto	loop1		; No, try again
		movf	ADRESH,w	; Yes, 
		movwf	Ux			; store result in Ux
		bcf		ADCON0,0	; Turn off AD-Converter
		return				; Go back to Main program


		;	Checks if Ux is below Ref_1 value
Low_?	movf	Ux,w		; Get Ux to W
		subwf	Ref_1,w		; Subtract Ux from Ref_1
		btfss	STATUS,0	; Ux < Ref_1 ?
		return				; No, Go back to Main program
		clrf	PORTA		; Yes, Switch off LED D0.
		return				; Go back to Main program


		;	Checks if Ux exceeds Ref_2 value
High_?	movf	Ref_2,w		; Get Ref_2 to W
		subwf	Ux,w		; Subtract Ref2 from Ux
		btfss	STATUS,0	; Ux > Ref_2 ?			(C-bit=1)
		return				; No, Go back to Main program
		call	Led_0		; Yes, Switch on LED D0.
		return				; Go back to Main program


		;	Checks if SW1 is pressed on PIC-Kit1
Knap	btfsc	PORTA,3		; Is SW1= ON?	(Input low)
		return				; No, proceed in Main program
		bsf		PORTA,5		; Yes, SW1 is ON, turn on LED D1
		call	Dis_Clr		; Display is cleared
lp_k	btfss	PORTA,3		; SW1 still ON?
		goto	lp_k		; Yes, check again!
		bcf		PORTA,5		; No, SW1 is OFF, turn OFF Led1
		call	Txt#1
		call	Dis_Ux		
		return				; Proceed in Main program


		;	Converts 8-bits to 3-digit Decimal number.
BinDec	clrf	x100		; Reset Registers.
		clrf	x10			;
		clrf	x1			;

		movf	Ux,w		; Get Ux to W
		movwf	Nr			; Save a copy in Nr	 		W -> Nr
Dig_3	movlw	D'100'		;
		subwf	Nr,w		; Subtract 100 from Nr 
		btfss	STATUS,0	;
		goto	Dig_2		;
		movwf	Nr			; Remainder in w to Nr	 	W -> Nr
		incf	x100,f		; Number of hundred's
		goto	Dig_3		;

Dig_2	movlw	D'10'		;
		subwf	Nr,w		; Subtract 10 from Nr
		btfss	STATUS,0	;
		goto	Dig_1		;
		movwf	Nr			; Remainder in w to Nr		W -> Nr
		incf	x10,f		; Number of ten's
		goto	Dig_2		;

Dig_1	movf	Nr,w		; 
		movwf	x1			; Remainder goes in register: x1 

Prep_N	movf	x100,w		; Preparing characters for display
		andlw	H'0F'		; (Numbers start with 3 	Eks: 5 => H'35')
		iorlw	H'30'		;
		movwf	x100		;
		movf	x10,w		;
		andlw	H'0F'		; And w with 00001111
		iorlw	H'30'		; Or w with  00110000
		movwf	x10			;
		movf	x1,w		;
		andlw	H'0F'		;
		iorlw	H'30'		;
		movwf	x1			;
		return


;************************************* Main program *************************************

start	call	Dis_Ini		; Display-unit setup
		call	Txt#1		; Write Text_1
New		call	Ux?			; Read ADC!
		call	Low_?		; Ux < Ref_1		=> LED D0 = OFF
		call	High_?		; Ux > Ref_2		=> LED D0 = ON	
		call	Knap		; KNAP activated	=> LED D1 = ON	Clears Display
		call	Dis_Ux		; Displays ADC-value as ASCII character
		call	DisADC		; Displays ADC-value as 3 digit decimal number
		goto	New			; New measurement

		end					; Program ends here


;*********************************** Programming a Device *******************************

;	  Select:
;
;	1.Configure		Select Device...	16f684
;	2.Configure		Configuration Bits	Clock:								Internal-RC,-
;																			No Clock
;
;										WatchDogTimer:						Off
; 										Master Clear Enable:				Internal
; 										Internal External Switch Over Mode:	Disabled
; 										Monitor Clock Fail-safe: 			Disabled
;
;	3.Project		Quickbuild 	*.asm
;	4.Programmer	Select Programmer	(PICkit 1)
;	5.Programmer	Program Device 		(Or Yellow Icon)



;**********************************    Connections:    **********************************

;			Colour	DISPLAY			J3 Pin No.	16F684	PICKit1

;			BK		 1 -				14		GND.
;			BN		 2 +				13		+5_SWITCHED
;			RD		 3 Contrast			 -
;			OR		 4 RS				 4		RC5	(Register Select)
;			YE		 5 R/W				 -			(GND=>W)
;			GN		 6 E				 5		RC4	(Strobe)
;			BL		 7 D4				10		RC0	(D4)
;			PU		 8 D5				11		RC1	(D5)
;			GR		 9 D6				12		RC2	(D6)
;			HW		10 D7				 6		RC3	(D7)
