;****************************************************************************************
;* PIC-micro project													Date: 07.12.09	*
;*																						*
;* FILE: Regulator+LCD.asm			2x16-Characters 					Name: GC		*
;*  								Two-Wire LCD										*
;* Device: PIC16F690				Text in RAM											*
;*									+ADC	+BinDec-Converter							*
;*																						*
;* Limits on ADC-value controls Output RC0												*
;* Uses Two-Wire LCD interface	(RA4 + RA5)												*
;* ADC-value is displayed as 2 digit decimal 											*
;* 																						*
;****************************************************************************************

;			H'<HEX>'		D'<Decimal>'		B'<Binary>'			A'<ASCII>'

; 	Registers og constants are defined here:
INDF		equ H'00'	; Indirect Register (Uses content of FSR)
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
PORTB		equ	H'06'	; Input/output-register B
TRISB		equ	H'06'	; Bank-1, input/output configuration B
PORTC		equ	H'07'	; Input/output-register C
TRISC		equ	H'07'	; Bank-1, input/output configuration C

INTCON		equ	H'0B'	; Interupt Control register (Enable-bits/Flags)
PIR2		equ	H'0D'	; Bank-0, EE-prom interuptflag EEIF = PIR2,4
EEDAT		equ	H'0C'	; Bank-2, EE-Prom data-register R/W
EEADR		equ	H'0D'	; Bank-2, EE-Prom address-register
EECON1		equ H'0C'	; Bank-3, EE-Prom Control register
EECON2		equ	H'0D'	; Bank-3, 

CM1CON0		equ H'19'	; Bank-2, Comparator control register
CM2CON0		equ H'1A'	; Bank-2, Comparator control register
CM2CON1		equ	H'1B'	; Bank-2, Comparator control register
ANSEL		equ H'1E'	; Bank-2, Analog input select register
ANSELH		equ	H'1F'	; Bank-2, Analog input select register
ADRESH		equ H'1E'	; Bank-0, ADC result format
ADCON0		equ	H'1F'	; Bank-0, ADC Conditions and control
ADCON1		equ H'1F'	; Bank-1, ADC Clock control (A/D conversion Clock)



; 	RAM-registers used by routines:
Ux			equ	H'20'	; Ux? (A/D Converter)
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'	; Wr_Ch, Wr_Cmd, TxtOut, Dis_Pos
Tmp_2		equ H'26'	; Wr_Ch, Wr_Cmd, D_Tx
Tmp_3		equ H'27'	; D_Tx, Clr_Buf (Number of Buffer-bits)
Deg_Ref		equ	H'28'	; Deg_C (Offset to subtract from ADC-value)

Nr			equ	H'29'	; BinDec
x100		equ H'2A'	; BinDec
x10			equ H'2B'	; BinDec
x1			equ	H'2C'	; BinDec


#define	Max_	D'121'	; Maximum for Temperature-display
#define	Min_	D'20'	; Minimum for Temperature-display
#define	D_D		PORTA,4	; RA4: Data-input for Two-wire LCD
#define	D_C		PORTA,5	; RA5: Clock-input for Two-wire LCD
#define	Out_1	PORTC,0	; RC0
#define	Out_2	PORTC,1	; RC1
#define	SW1		PORTA,3	; RA3, Switch input

		list p=16F690

		org		H'00'		; Start of code
		
		goto	Init		; Reset Vector 	Located at 0x0000
		nop					;
		nop					;
		nop					;
		nop					; (ISR Vector	Located at 0x0004)

;*************************************** Chip setup ***************************************

Init

; PORT Setup:				; Inputs and outputs are selected
		bsf		STATUS,5	; Bank-1
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_B						; All pins remain inputs - not used
PORT_C	clrf	TRISC		; PORTC= Outputs
		bcf		STATUS,5	; Bank-0
							; Unused comperators are switched off:
		bsf		STATUS,6	; Bank-2
		clrf	CM1CON0		; Disable comparator 1, 				!!! IMPORTANT !!!
		clrf	CM2CON0		; Disable comparator 2, 			PORTC: General purpos I/O
		bcf		STATUS,6	; Bank-0

; ADC Setup:				; Conversion clock:
		bsf		STATUS,5	; Bank-1
		movlw	B'00010000'	; Bit<6:4> = 001 => ADC-Clock= Fosc/8
		movwf	ADCON1		;
		bcf		STATUS,5	; Bank-0
							; Analog / Digital input:
		bsf		STATUS,6	; Bank-2
		movlw	B'00000001' ; Makes AN0 analog input for ADC and -
		movwf	ANSEL		; ANS<7:1> are digital inputs
		clrf	ANSELH		; Asosiated pins are digital inputs (ANS<11:8>)
		bcf		STATUS,6	; Bank-0
							; ADC Output, Vref and input channel select
		movlw	B'00000000'	; Bit7=0:	0-------, Makes A/D Result Left justified (8 Bits used)
							; Bit6=0:	-0------, Vref for A/D =VDD
		movwf	ADCON0		; Bit<4:2>	---000--, Channel 0 selected: RA0/AN0= ADC-input
							; Bit1:		------1-, A/D start and Busy test bit
							; Bit0=1:	-------1, Turns on A/D Converter

; Ref Setup:				; 
		movlw	D'21'		; Set Reference temperature (Used by Deg_C)
		movwf	Deg_Ref		; Offset-value: 21deg.

		movlw	D'41'		; Ref_1	:	Low limit
		movwf	Ref_1		; 			( 20deg.)
		movlw	D'51'		; Ref_2	:	High limit
		movwf	Ref_2		; 			( 30deg.)

; Reset PORT's				; Outputs are reset:
		clrf	PORTA		; PORTA Outputs are cleared (LED's off)
		clrf	PORTC		; PORTC Outputs are cleared


;cccccccccccccccccccccccccc  Characters used by Txt_#X Routines  ccccccccccccccccccccccccc

Txt#1	movlw	A'R'		; R		ASCII-Code !	Display-Characters are loaded into RAM.
		movwf	H'30'		; 	<=	(Text starts at 30h)
		movlw	A'e'		; e
		movwf	H'31'
		movlw	A'g'		; g
		movwf	H'32'
		movlw	A'u'		; u
		movwf	H'33'
		movlw	A'l'		; l	
		movwf	34			
		movlw	A'a'		; a
		movwf	35
		movlw	A't'		; t
		movwf	36
		movlw	A'o'		; o
		movwf	37	
		movlw	A'r'		; r
		movwf	38
		movlw	A'+'		; +
		movwf	39
		movlw	A'L'		; L
		movwf	3A
		movlw	A'C'		; C
		movwf	3B
		movlw	A'D'		; D
		movwf	3C
		movlw	A'*'		; *	<- Star: ends read-out (Se: Txt_Out routine)
		movwf	3D

Txt#2	movlw	A'T'		; T 	<=	(Text starts at 3Eh)
		movwf	3E
		movlw	A'e'		; e
		movwf	3F
		movlw	A'm'		; m
		movwf	40
		movlw	A'p'		; p
		movwf	41
		movlw	A':'		; :
		movwf	42
		movlw	A'*'		; *	<- Star: ends read-out (Se: Txt_Out routine)
		movwf	43

		goto	start


;***********************************    Subroutines   ***********************************


;WWWWWWWWWWWWWWWW Routines for writing and controling the Two-wire display WWWWWWWWWWWWWW

		;	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		; Dly_2 * 772uS
		decfsz	Dly_2,f
		goto	lp_d2
		return

		;	Writes a command to the Display-unit
Wr_Cmd	movwf	Tmp_1		; Save a copy
		swapf	Tmp_1,w		; High nibble first
		andlw	H'0F'		; Preparation of Enable-bit 
		addlw	H'20'		; Command-mode (RS=0)
		movwf	Tmp_2		; Modified copy to Working registe
		call	D_Tx		; Send first part
Wr_Cmd2	movf	Tmp_1,w		; Get data for second part
		andlw	H'0F'		; Preparation of Enable-bit 
		addlw	H'20'		; Command-mode (RS=0)
		movwf	Tmp_2		; Modified copy to Working register 
		call	D_Tx		; Send second part
		movlw	H'05'		; Wait (50 uS)
		call	Delay
		return

		;	Writes a character to the Display-unit
Wr_Ch	movwf	Tmp_1		; Save a copy
		swapf	Tmp_1,w		; High nibble first
		andlw	H'0F'		; Preparation of Enable-bit 
		addlw	H'30'		; Charactermode (RS=1)
		movwf	Tmp_2		; Modified copy to Working registe
		call	D_Tx		; Send first part
		movf	Tmp_1,w		; Get data for second part
		andlw	H'0F'		; Preparation of Enable-bit 
		addlw	H'30'		; Charactermode (RS=1)
		movwf	Tmp_2		; Modified copy to Working register 
		call	D_Tx		; Send second part
		movlw	H'05'		; Wait (50 uS)
		call	Delay
		return

		;	Sends prepared data to display-buffer (6 bits), used by: Wr_Ch
D_Tx	call	Clr_Buf		; Clear the Display-buffer
		movlw	H'06'		; Number of buffered bits 
		movwf	Tmp_3		; 
H_L_?	btfsc	Tmp_2,5		; IF:		Most significant bit is not low
		goto	D_H			; THEN:		Go to D_H
D_L		bcf		D_D			; ELSE:		Set display data-line Low
		goto	D_X			; Go - transmit current bit
D_H		bsf		D_D			; Set display data-line High
D_X		call	D_Ck		; Clock data into display-buffer
		rlf		Tmp_2,f		; Rotate left for next bit
		decfsz	Tmp_3,f		; All done ?
		goto	H_L_?		; Get status of next bit 
		bcf		D_D			; Set display data-line low
		call	D_Ck		; Clock Data forward one more step
E_P		bsf		D_D			; Pulse E-line to transfer data to display-unit	(målt: 15us)
		movlw	H'03'
		call	Delay
		bcf		D_D
		return

		;	Generates a clock-pulse to Two-wire LCD. Used by: D_Tx
D_Ck	bcf		D_C			; Set Display_Clock-line low
		movlw	H'03'		; 
		call	Delay		; Wait (x9 uS)
		bsf		D_C			; Set Display_Clock-line high
		movlw	H'06'		; Wait (x9 uS)
		call	Delay
		bcf		D_C			; Set Display_Clock-line low
		movlw	H'03'		; Wait (x9 uS)
		call	Delay
		return

		;	Clears buffer for Two-wire LCD
Clr_Buf	bcf		D_D			; Set Display Data-line low, 
		movlw	H'08'		; All 8 bits are cleared
		movwf	Tmp_3
CB_lp	call	D_Ck
		decfsz	Tmp_3,f
		goto	CB_lp
		return


;IIIIIIIIIIIIIIIIIIIIII Routines for initialising and Display set-up IIIIIIIIIIIIIIIIIIII

		;	Setup-routine for Display-unit.
Dis_Ini	call	Clr_Buf		; Clear display-buffer

		movlw	H'43'		; Delay after power on (50mS)
		call	Delay2		; Display "wakes up"
		movlw	B'0010'		; 4-bit mode 0,0,1,DL
		movwf	Tmp_1
		call	Wr_Cmd2		; NB!	Only the first 4 bits is needed to select 4-bit mode
		movlw	H'06'		; Wait (4,6mS)
		call	Delay2

Fnc_Set	movlw	B'00101000'	; Switch display to 4-bit mode, 2 display-lines in use
		call	Wr_Cmd		; 4-bit mode 0,0,1,DL	N,F,-,-
		movlw	H'10'		; Wait (50uS)
		call	Delay

Disp_On	movlw	B'00001100'	; Turning ON the Display 1,D,C,B, (1=ON, 0=OFF)
		call	Wr_Cmd		; D: Display ON,	C: Cursor OFF,	B: Blink OFF
		movlw	H'10'		; Wait (50uS)
		call	Delay

Ent_Mod	movlw	B'00000110'	; Entry mode
		call	Wr_Cmd		; 0,1,I/D,S		I/D: Increment/Decrement,	S: Shift display
		movlw	H'10'		; Wait (50 uS)
		call	Delay
		return


Dis_Off	movlw	B'00001000'	; Blanks Display!	RS=0 & Data=0	1,D,C,B,	(1=ON, 0=OFF)
		call	Wr_Cmd		; D: Display OFF,	C: Cursor OFF,	B: Blink OFF
		movlw	H'10'		; Wait (50uS)
		call	Delay
		return

Dis_Clr	movlw	B'00000001'	; Display is cleared, cursor home at start (00)
		call	Wr_Cmd		; RS=0 & Data=0
		movlw	H'06'		; Wait (4,6mS)
		call	Delay2
		return

Cur_Hom	movlw	B'00000010'	; Cursor home at start (00), text remains on display
		call	Wr_Cmd		; RS=0 & Data=0
		movlw	H'06'		; Wait (4,6mS)
		call	Delay2
		return


;wwwwwwwwwwwwwwwwwwwwwwwwwwwwww Text-handeling routines wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww

		;	Value in W holds cursor position for text start on display-unit
Dis_Pos	addlw	H'80'		; Position must be in W. Command-mode (Bit7 must be set)
		movwf	Tmp_1		; Save a copy in Tmp_1
		call	Wr_Cmd
		return

		;	Writes text-string to Display-unit. Trailing * ends read-out.
Txt_Out	movwf	FSR			; Set text-pointer for indirect addressing
Next_C	movf	INDF,w		; Get Character -
		call	Wr_Ch		; 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

Txt_#1	movlw	H'00'		; Text-1 start-position on display
		call	Dis_Pos
		movlw	H'30'		; Address where Txt#1 is Located
		call	Txt_Out
		return

Txt_#2	movlw	H'40'		; Text-2 start-position on display
		call	Dis_Pos
		movlw	H'3E'		; Address where Txt#2 is Located
		call	Txt_Out
		return


;ddddddddddddddddddddddddddddddd Data-handeling routines dddddddddddddddddddddddddddddddd

		;	Converts one byte to a 3-digit Decimal number.
BinDec	clrf	x100		; Reset Registers.
		clrf	x10			; The value to convert must be in register: Nr
		clrf	x1			;
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 starting with 3 	Eks: D'5' => H'35')
		iorlw	H'30'		;
		movwf	x100		;
		movf	x10,w		;
		andlw	H'0F'		; And w with 00001111					H'0F'
		iorlw	H'30'		; Or w with  00110000					H'30'
		movwf	x10			; To make it a Number					H'3X'
		movf	x1,w		;
		andlw	H'0F'		;
		iorlw	H'30'		;
		movwf	x1			;
		return

		;	Write ADC-value as 3 decimal characters to display @ 40h
DisADC	Call	Ux?
		movf	Ux,w		; Save a copy of Ux in Nr
		movwf	Nr
		call	BinDec
		movlw	H'40'		; Writes 3 Decimal digits @ 40h
		call	Dis_Pos		; -> 40h (Start of line 2)
		movf	x100,w
		call	Wr_Ch
		movf	x10,w
		call	Wr_Ch
		movf	x1,w
		call	Wr_Ch
		return

	
DisTemp		;	Checks if Ux is below Min_ value
Dis_L	movf	Ux,w		; Get Ux to W
		sublw	Min_		; Subtract Ux from Min_		(Min_ = D'21')
		btfss	STATUS,0	; IF:		Ux < Min_		(w<f =>	C-bit=1)
		goto	Dis_H		; THEN:		Check if high limit is exeded
		goto	Dis_E		; ELSE:		Display -- for error
			;	Checks if Ux exceeds Max_ value
Dis_H	movlw	Max_		; Get Max_ to W
		subwf	Ux,w		; Subtract Max_ from Ux		(Max_ = D'121')
		btfss	STATUS,0	; IF:		Ux > Max_		(w<f =>	C-bit=1)
		goto	Dis_Tp		; THEN:		Go display the temperature
		goto	Dis_E		; ELSE:		Display -- for error
			;	Displays temperature as 2 Decimal characters
Dis_Tp	call 	Deg_C		; Deg_C converts 8-bits to a 3-digit Decimal number.
		movlw	H'4C'		; -> Position 4C 	(End of Display-line 2)
		call	Dis_Pos		; 
		movf	x10,w
		call	Wr_Ch
		movf	x1,w
		call	Wr_Ch
		movlw	H'DF'		; <DF>= HEX-Value for degree character
		call	Wr_Ch
		movlw	A'C'		; C: for Celcius
		call	Wr_Ch
		return
Dis_E   movlw	H'4C'		; Displays -- ,		meaning ouside range from Min_ to Max_
		call	Dis_Pos		; -> Position 4C 	(Near the end of Display-line 2)
		movlw	A'-'
		call	Wr_Ch
		movlw	A'-'
		call	Wr_Ch
		movlw	H'DF'		; <DF>= HEX-Value for degree character
		call	Wr_Ch
		movlw	A'C'		; C: for Celcius
		call	Wr_Ch
		return

		;	This routine calculates the temperature and convert it to decimal.
Deg_C	Call	Ux?	
		movf	Deg_Ref,w	; Get Reference temperature (Deg_Ref=Offset-value)
		subwf	Ux,w		; Subtract Deg_Ref from w 
Nr_Out	movwf	Nr
		call	BinDec		; Convert it to decimal.
		return

;IIIIIIIIIIIIIIIIIIIIIIIIIIIIII  Input Outpt & ADC Routines  IIIIIIIIIIIIIIIIIIIIIIIIIIII

		;	Reads ADC-value
Ux?		bsf		ADCON0,0	; Turn on A/D Converter
		movlw	D'4'		; W contains delay-value for Dly_1 (23h)
		call	Delay		; Delay		(ADC Sample & Hold Setup-time)
		bsf		ADCON0,1	; GO, Start A/D Conversion
loop1	btfsc	ADCON0,1	; Done ?	(Bit1: A/D Start and Busy test-bit)
		goto	loop1		; No, try again (Conversion still in progress)
		movf	ADRESH,w	; Yes, 
		movwf	Ux			; Store result in Ux
		bcf		ADCON0,0	; Turn off A/D 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
		bcf		Out_1		; Yes, Switch off RC0.
		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
		bsf		Out_1		; Yes, Switch on RC0.
		return				; Go back to Main program

Reg_Out	call	Ux?
		call	Low_?
		call	High_?
		return

Switch	btfsc	SW1			; Is SW1= ON?	(Input low ?)
		return				; No, proceed
		bsf		Out_2		; Yes, turn on DS2
lp_k	btfss	SW1			; SW1 still ON?
		goto	lp_k		; Yes, check again!
		bcf		Out_2		; No, turn off DS2
		return				; Proceed


;************************************* Main program *************************************

start						
		call	Dis_Ini		; Display-unit setup
		call	Cur_Hom		; Cursor home (00)
		call	Txt_#1		; Write Text_1
		call	Txt_#2		; Write Text_2
New		call	Reg_Out		; Read ADC and set Output accordingly
		call	DisTemp		; Displays temperature
		call	Switch		; Is SW1 activated ?
		goto	New			; New measurement

		end					; Program ends here


;*********************************** Programming a Device *******************************

;	  Select:
;
;	1.Configure		Select Device...	16f690
;	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 2)
;	5.Programmer	Program Device 		(Or Yellow Icon)





;********************************    Display Connections:    ****************************

;		Colour	 Pin Nr.	Function

;		BK		 1 			-
;		BN		 2 			+
;		RD		 3 			Contrast
;		OR		 4 			RS
;		YE		 5 			R/W	(GND=>W)
;		GN		 6 			E
;		BL		 7 			D4
;		PU		 8 			D5
;		GR		 9 			D6
;		HW		10 			D7


; 		Temperature sensor: 10k NTC in series vith 10k trim (temp. adjust).