; LCD_F84.ASM
;
; Provides a collection of routines to output to serial PICnLCD at 9600
; Baud inverted.  
;
; LCD_RESET - provides a means for the user to manually reset the LCD
; 	    - brings RA.0 (serial lead) low for 2.5 secs.  During this
;	      time, the user should manually reset the LCD.
;	    - routine then clears the LCD and ouptuts ten dots.
;	    - LCD is then cleared again.
;	    - W and STATUS are saved.
;
; LCD_DELAY - provides a delay of the number of msecs contained in W.
;	    - W and STATUS are saved.	
; LCD_DEBUG 
;	- displays W content and the state of the Z and C flags on line 1.
;       - prints value of location 40H as a character on line 2.
;	- displays values of locations 10, 11, 12, 13 on line 3.
; 	- locations 14, 15, 16, 17 on line 4.
;	- this is followed by a one second delay.  
;	- the W and STATUS registers are saved and restored in returning 
;	  to the calling program. 	 
;
; LCD_CHAR - displays character in W on LCD.  W and STATUS are saved.
; LCD_VAL - converts value in W to two hex characters and displays on LCD.
;
; LCD_BCD_WORD - displays quantity in 41H and 42H as unsigned decimal 
; quantity.  Note, this is limited to 9999 decimal.
;
; This file is intended to be included in another file which calls these
; functions.
;
; PORTA, Bit 0 (terminal 17) ------ TX ----------> to RX on PIC-n-LCD
;
; Uses variables in the range 40-4F.  Code is at program memory locations
; 300 - 3FFH
;
; Copyright, Peter H. Anderson, Morgan State University, June 14, '97
; Added 10 msec timing and trisa to _SERIAL routine - July 22, '97						
; Revised for EEGR417, Feb 17, '98, Added DEBUG, Feb 25, '98, 
; Substantially reworked on March 12, '98, Corrected swap on April 4, '98
;
;
;	LIST p=16f84	; these lines not required when included in 
;			; another file
;	#include <c:\mplab\p16f84.inc>	
;	__CONFIG 11h
	
	RADIX HEX

	CONSTANT _MAX_VAR=4FH

	CONSTANT TX=0	; PORTA, Bit 0

_SER_DATA EQU _MAX_VAR-0	; 4F
_SER_LOOP EQU _MAX_VAR-1	; 4E
_SER_TIME EQU _MAX_VAR-2	; 4D

_TEMP1 EQU _MAX_VAR-3		; 4C
_TEMP2 EQU _MAX_VAR-4		; 4B

_H	EQU _MAX_VAR-3		; 4C				
_L	EQU _MAX_VAR-4		; 4B

_TH	EQU _MAX_VAR-5		; 4A
_HU	EQU _MAX_VAR-6		; 49
_TE 	EQU _MAX_VAR-7		; 48
_UN	EQU _MAX_VAR-8		; 47	

_SAVE_W EQU _MAX_VAR-9		; 46
_SAVE_STAT EQU _MAX_VAR-0A	; 45

_LOOP1	EQU _MAX_VAR-1	; used for pace timing, same location as _SER_LOOP
_LOOP2	EQU _MAX_VAR-2	; used for pace timing, same location as _SER_TIME

_N_MSEC	EQU _MAX_VAR-0B		; 44
_N1	EQU _MAX_VAR-0C		; 43

	ORG 300H

LCD_BCD_WORD:	; displays a natural binary word in locations 41 and 42
	        ; in decimal. 
	MOVWF _SAVE_W		; save W and STATUS
	SWAPF STATUS, W
	MOVWF _SAVE_STAT	
	SWAPF _SAVE_STAT, F	; status saved in true form

	MOVF 41H, W
	MOVWF _H
	MOVF 42H, W
	MOVWF _L

	CLRF _TH
	CLRF _HU
	CLRF _TE
	CLRF _UN
_BCD_1:
	MOVLW .1
	SUBWF _L, F
	BTFSC STATUS, C	; a borrow occurred
	GOTO _INC_DEC
	MOVLW .1
	SUBWF _H, F
	BTFSC STATUS, C
	GOTO _INC_DEC

	SWAPF _TH, W
	IORWF _HU, W
	CALL _LCD_VAL

	SWAPF _TE, W
	IORWF _UN, W
	CALL  _LCD_VAL

	GOTO _RETURN
		
_INC_DEC:
	CLRWDT
	INCF _UN, F
	MOVLW .10
	SUBWF _UN, W
	BTFSS STATUS, Z
	GOTO _BCD_1

	CLRF _UN
	
	INCF _TE, F
	MOVLW .10
	SUBWF _TE, W
	BTFSS STATUS, Z
	GOTO _BCD_1

	CLRF _TE
	
	INCF _HU, F
	MOVLW .10
	SUBWF _HU, W
	BTFSS STATUS, Z
	GOTO _BCD_1

	CLRF _HU

	INCF _TH, F
	GOTO _BCD_1

LCD_RESET:	
	MOVWF _SAVE_W		; save W and STATUS
	SWAPF STATUS, W
	MOVWF _SAVE_STAT
	SWAPF _SAVE_STAT, F	; save in true form

	BSF STATUS, RP0
	BCF TRISA, 0
	BCF STATUS, RP0
	
	BCF PORTA, 0		; output a zero to LCD

	MOVLW .10
	MOVWF _N1
_RESET_1:
	MOVLW .250	
	MOVWF _N_MSEC
	CALL _DELAY_N
	DECFSZ _N1, F
	GOTO _RESET_1

	MOVLW 0CH
	CALL _LCD_CHAR

	MOVLW .10
	MOVWF _N1
_RESET_2:
	MOVLW "."
	CALL _LCD_CHAR
	DECFSZ _N1, F
	GOTO _RESET_2	

	MOVLW .4	; one second delay
	MOVWF _N1

_RESET_3:
	MOVLW .250	
	MOVWF _N_MSEC
	CALL _DELAY_N
	DECFSZ _N1, F
	GOTO _RESET_3

	MOVLW 0CH
	CALL _LCD_CHAR

	GOTO _RETURN

LCD_DELAY:			; delays number of msecs in W
	MOVWF _SAVE_W		; save W and STATUS
	SWAPF STATUS, W
	MOVWF _SAVE_STAT
	SWAPF _SAVE_STAT, F	; save in true form

	MOVF  _SAVE_W, W	; get W
	MOVWF _N_MSEC
	CALL _DELAY_N

	GOTO _RETURN

LCD_DEBUG:
	MOVWF _SAVE_W		; save W and STATUS
	SWAPF STATUS, W
	MOVWF _SAVE_STAT
	SWAPF _SAVE_STAT, F

	MOVLW 0CH		; clear the LCD
	CALL _LCD_CHAR

	MOVLW "W"		; W=
	CALL _LCD_CHAR
	MOVLW "="
	CALL _LCD_CHAR
	MOVF _SAVE_W, W		; display value of W in hex
	CALL _LCD_VAL

	MOVLW " "
	CALL _LCD_CHAR
	
	MOVLW "Z"		; Z=
	CALL _LCD_CHAR
	MOVLW "="
	CALL _LCD_CHAR

	BTFSS _SAVE_STAT, Z
	MOVLW "0"
	BTFSC _SAVE_STAT, Z
	MOVLW "1"
	
	CALL _LCD_CHAR		; display either a zero or one

	MOVLW " "
	CALL _LCD_CHAR
	
	MOVLW "C"		; C=
	CALL _LCD_CHAR
	MOVLW "="
	CALL _LCD_CHAR

	BTFSS _SAVE_STAT, C
	MOVLW "0"
	BTFSC _SAVE_STAT, C
	MOVLW "1"
	CALL _LCD_CHAR		; display either a zero or a one

	MOVLW 0DH		; go to second line
	CALL _LCD_CHAR
	MOVLW 0AH
	CALL _LCD_CHAR	
	
	MOVF 40H, W		; display location 40H as a char
	CALL _LCD_CHAR

	MOVLW 0DH		; go to third line
	CALL _LCD_CHAR
	MOVLW 0AH
	CALL _LCD_CHAR

	MOVLW 10H		; initialize pointer to RAM location 10
	MOVWF FSR
	
	MOVLW .4		; four values on line
	MOVWF _N1
_DEBUG_1:
	MOVF INDF, W
	CALL _LCD_VAL		; display values in loc 10, 11, 12, 13
	INCF FSR, F
	MOVLW " "
	CALL _LCD_CHAR
	DECFSZ _N1, F
	GOTO _DEBUG_1
	
	MOVLW 0DH		; go to 4th line
	CALL _LCD_CHAR
	MOVLW 0AH
	CALL _LCD_CHAR

	MOVLW .4		; same for 14, 15, 16 and 17
	MOVWF _N1
_DEBUG_2:
	MOVF INDF, W
	CALL _LCD_VAL
	MOVLW " "
	CALL _LCD_CHAR
	INCF FSR, F
	DECFSZ _N1, F
	GOTO _DEBUG_2
	
	MOVLW .250
	MOVWF _N_MSEC

	CALL _DELAY_N		; 250 msecs
	CALL _DELAY_N		
	
	CALL _DELAY_N		
	CALL _DELAY_N		

	GOTO _RETURN
	
LCD_VAL:	; converts byte in W to two characters and outputs
	MOVWF _SAVE_W		; save W and STATUS
	SWAPF STATUS, W
	MOVWF _SAVE_STAT
	SWAPF _SAVE_STAT, F	; save it in true form

	MOVF _SAVE_W, W		; get back W
_LCD_VAL:
	MOVWF _TEMP1		; save a copy of W
	MOVF PCLATH, W
	MOVWF _TEMP2		; save PCLATH

	MOVLW .3		; page 3
	MOVWF PCLATH
	
	SWAPF _TEMP1, W	; high nibble now in lo nibble of W
	ANDLW 0FH	; 
	CALL _HEX_LOOK
	CALL _SEROUT

	MOVF _TEMP1, W
	ANDLW 0FH
	CALL _HEX_LOOK
	CALL _SEROUT

	MOVF _TEMP2, W
	MOVWF PCLATH		; previous value of PCLATH
	GOTO _RETURN

_HEX_LOOK:
	ADDWF PCL, F
	DT "0", "1", "2", "3", "4", "5", "6", "7"
	DT "8", "9", "A", "B", "C", "D", "E", "F"

LCD_CHAR:	; outputs character in W to LCD
	MOVWF _SAVE_W		; save W and STATUS
	SWAPF STATUS, W
	MOVWF _SAVE_STAT
	SWAPF _SAVE_STAT, F	; save in true form

	MOVF _SAVE_W, W		; get back W
_LCD_CHAR:
	CALL _SEROUT
	MOVLW .10
	MOVWF _N_MSEC
	CALL _DELAY_N
	GOTO _RETURN

_SEROUT:			; transmits content of W at 9600 Baud

	MOVWF	_SER_DATA

	BSF STATUS, RP0		; make TX bit an output 
	BCF TRISA, TX		; 
	BCF STATUS, RP0
	BCF PORTA, TX		; set to stop bit

	MOVLW   .255
        MOVWF	_SER_TIME    	; be sure stop bit has been high present
_SEROUT1:			; for some time
	DECFSZ  _SER_TIME, F
	GOTO _SEROUT1

	MOVLW 	.9
	MOVWF	_SER_LOOP

	BCF	STATUS, C	; set C to 0, start bit

_SEROUT2:
	BTFSC	STATUS, C
	BCF	PORTA, TX	; send a one
	BTFSS	STATUS, C
	BSF	PORTA, TX	; or a zero

	MOVLW   .31
        MOVWF	_SER_TIME     	; one bit delay.  104 usecs at 9600 baud
_SEROUT3:
	DECFSZ  _SER_TIME, F
        GOTO _SEROUT3

	;NOP			; CHANGE
        	
	RRF	_SER_DATA, F	; least sign bit now in C
	DECFSZ	_SER_LOOP, F	; does not affect status
	GOTO 	_SEROUT2	; next character

	BCF	PORTA, TX	; send stop bit
	
	RETURN

_DELAY_N:	; delays number of msecs specified in _N_MSEC
	MOVF  _N_MSEC, W
	MOVWF _LOOP1
_DELAY_1:
	MOVLW	.247	; close to 1.0 msec delay when set to .247
	MOVWF 	_LOOP2
_DELAY_2:
	
	CLRWDT
	DECFSZ	_LOOP2, F	; decrement and leave result in LOOP2 
				; skip next statement if zero
	GOTO _DELAY_2
	DECFSZ 	_LOOP1, F
	GOTO _DELAY_1
	RETURN

_RETURN:
	SWAPF _SAVE_STAT, W
	MOVWF _TEMP2
	SWAPF _TEMP2, W
	MOVWF STATUS
	SWAPF _SAVE_W, W	; get back W without altering STATUS
	MOVWF _TEMP2
	SWAPF _TEMP2, W

	RETURN