; LCD.ASM, FOR THE INDUSTROLOGIC DIO51
; SHOWS HOW TO INTIALIZE AND WRITE CHARACTERS TO A TEXT CHARACTER LCD MODULE

				;LCD R/W PIN IS GROUNDED FOR WRITE ONLY
LCDEN	BIT	P0.0		;LCD ENABLE (CHIP SELECT), HIGH PULSE
LCDRS	BIT	P0.1		;LCD RS (REGISTER SELECT) 1=DATA, 0=CONTROL
SPARE2	BIT	P0.2		;NO CONNECTION
SPARE3	BIT	P0.3		;NO CONNECTION
LCDD4	BIT	P0.4		;LCD D4
LCDD5	BIT	P0.5		;LCD D5
LCDD6	BIT	P0.6		;LCD D6
LCDD7	BIT	P0.7		;LCD D7

CHR	EQU	20H		;STORAGE CHARACTER

	ORG	0		;RESTART VECTOR

	CALL	LCDINI		;INITIALIZE THE LCD MODULE


START:	MOV	DPTR,#MSG	;POINT TO MESSAGE
	CALL	WRMSG		;WRITE MESSAGE POINTED TO BY DPTR
	CALL	SECDEL		;DELAY 1 SECOND

	MOV	CHR,#'A'	;CHARACTER TO START WITH
REPEAT:	MOV	A,#6		;CURSOR POSITION
	CALL	LCDCUR		;SET LCD CURSOR COMMAND
	MOV	A,CHR		;CHARACTER TO DISPLAY
	CALL	WRDAT		;WRITE DATA (NORMAL CHARACTER)
	INC	CHR		;NEXT CHARACTER
	MOV	A,CHR		;GET CHARACTER TO TEST IT
	CALL	SECDEL		;DELAY 1 SECOND
	CJNE	A,#'[',REPEAT	;NEXT CHARACTER
	MOV	A,#01H		;CLEAR DISPLAY (AND SET DDRAM TO ADDRESS 0), 1.64ms
	CALL	WRCTL		;WRITE CONTROL (COMMAND)
	CALL	MS5		;DELAY 5ms
	JMP	START


MSG:	DB	'Hello',0	;MESSAGE STRING TERMINATED WITH ZERO



SECDEL:	MOV	R7,#10		;ONE SECOND DELAY
SD1:	CALL	MS100		;100 MILLISECOND DELAY
	DJNZ	R7,SD1
	RET


MS100:	MOV	R6,#200		;100 MILLISECOND DELAY
MS101:	CALL	US500		;500 MICROSECOND DELAY
	DJNZ	R6,MS101
	RET



;-----------------------------------------------------------------------------
; Hitachi HD44780 LCD controller programming information
; When reset the following commands are performed in the LCD firmware:
; Display clear
; Function set: 8 bit data, 1 line display, 5x7 dots
; Display on/off/control: display, cursor, and blink off
; Entry mode set: increment cursor, no shift of display

;Suggested initialization from data sheet:
;15ms delay
;function set 8 bit data, 1 line, 5x7 dots
;4.1ms delay
;function set 8 bit data, 1 line, 5x7 dots
;100us delay
;function set 8 bit data, 1 line, 5x7 dots
;4.1ms delay
;function set 4 bit data length, etc.
;40us delay


				;INITIALIZE DISPLAY
LCDINI:	CALL	MS20		;WAIT AT LEAST 15MS FOR POWERUP
	MOV	P0,#30H		;8 BIT DATA, 1 LINE, 5x7 CHARACTERS
				;(CONTROL SIGNALS IN LOWER NIBBLE ALL LOW)
	MOV	R2,#3		;LCD INFO SAYS DO THIS THREE TIMES
LCDIL:	CALL	LCDLAT		;SET AND CLEAR ENABLE SIGNAL SUBROUTINE
	CALL	MS5		;DELAY 5ms (MORE THAN REQUIRED FOR 2 OF THESE)
	DJNZ	R2,LCDIL
	MOV	P0,#20H		;4 BIT DATA, 1 LINE, 5x7 CHARACTERS, 40uS
				;(CONTROL SIGNALS IN LOWER NIBBLE ALL LOW)
	CALL	LCDLAT		;SET AND CLEAR ENABLE SIGNAL SUBROUTINE
	CALL	US500		;DELAY 500 MICROSECONDS
				;INITIALIZATION DONE, ALL DATA MUST NOW BE 4 BIT

				;NOW WE CAN USE THE WRCTL AND WRDAT SUBROUTINES

				;DO SOME COMMANDS TO SET UP THE DISPLAY
	MOV	A,#0EH		;DISPLAY ON, CURSOR ON, CURSOR NO BLINK
	CALL	WRCTL		;WRITE CONTROL (COMMAND)
	CALL	US500		;DELAY 500 MICROSECONDS

	MOV	A,#06H		;NO SHIFT, INCREMENT CURSOR, 40us
	CALL	WRCTL		;WRITE CONTROL (COMMAND)
	CALL	US500		;DELAY 500 MICROSECONDS

				;SOME LCD MODULES BASED ON THE KS0062
				;LCD CONTROLLER WILL NOT WORK WITHOUT A CLEAR DISPLAY
	MOV	A,#01H		;CLEAR DISPLAY (AND SET DDRAM TO ADDRESS 0), 1.64ms
	CALL	WRCTL		;WRITE CONTROL (COMMAND)
	CALL	MS5		;DELAY 5ms

	RET

;OTHER LCD COMMANDS-
;01D=01H=CLEAR DISPLAY, 1.64ms
;02D=02H=HOME CURSOR, 40us to 1.64 ms
;08D=08H=DISPLAY OFF, 40us
;12D=0CH=DISPLAY ON, CURSOR OFF, 40us
;14D=0EH=DISPLAY ON, CURSOR ON, NO BLINK, 40us
;15D=0FH=DISPLAY ON, CURSOR ON, BLINK, 40us
;16D=10H=MOVE CURSOR LEFT, 40us
;17D=11H=MOVE CURSOR RIGHT, 40us


				;SET LCD CURSOR
				;ENTER WITH DDRAM ADDRESS IN ACC
LCDCUR:	ORL	A,#80H		;ADD BIT FOR "SET DDRAM"
	CALL	WRCTL		;WRITE CONTROL (COMMAND)
	CALL	US500		;DELAY 500 MICROSECONDS
	RET



				;WRITE MESSAGE POINTED TO BY DPTR
WRMSG:	MOV	A,#0		;NO OFFSET
	MOVC	A,@A+DPTR	;GET NEXT CHARACTER IN STRING
	JZ	WRMSG1		;EXIT IF TERMINATING ZERO
	CALL	WRDAT		;WRITE DATA (NORMAL CHARACTER)
	CALL	US500		;DELAY 500 MICROSECONDS
	INC	DPTR		;POINT TO NEXT CHARACTER
	SJMP	WRMSG		;AND REPEAT
WRMSG1:	RET


				;WRITE DATA (NORMAL CHARACTER)
WRDAT:	PUSH	ACC		;SAVE LOWER NIBBLE
	CLR	ACC.0		;KEEP ENABLE/CHIP SELECT LOW FOR NOW
	SETB	ACC.1		;REGISTER SELECT HIGH FOR WRITE DATA
	MOV	P0,A		;SEND TO PORT
	CALL	LCDLAT		;ENABLE/CHIP SELECT HIGH, THEN LOW
	POP	ACC		;RESTORE LOWER NIBBLE
	SWAP	A		;SWAP NIBBLES
	CLR	ACC.0		;KEEP ENABLE/CHIP SELECT LOW FOR NOW
	SETB	ACC.1		;REGISTER SELECT HIGH FOR WRITE DATA
	MOV	P0,A		;SEND TO PORT
	CALL	LCDLAT		;ENABLE/CHIP SELECT HIGH, THEN LOW
	RET


				;WRITE CONTROL (COMMAND)
WRCTL:	PUSH	ACC		;SAVE LOWER NIBBLE
	CLR	ACC.0		;KEEP ENABLE/CHIP SELECT LOW FOR NOW
	CLR	ACC.1		;REGISTER SELECT LOW FOR WRITE CONTROL
	MOV	P0,A		;SEND TO PORT
	CALL	LCDLAT		;ENABLE/CHIP SELECT HIGH, THEN LOW
	POP	ACC		;RESTORE LOWER NIBBLE
	SWAP	A		;SWAP NIBBLES
	CLR	ACC.0		;KEEP ENABLE/CHIP SELECT LOW FOR NOW
	CLR	ACC.1		;REGISTER SELECT LOW FOR WRITE CONTROL
	MOV	P0,A		;SEND TO PORT
	CALL	LCDLAT		;ENABLE/CHIP SELECT HIGH, THEN LOW
	RET


LCDLAT:	SETB	LCDEN		;ENABLE/CHIP SELECT HIGH
	NOP			;VERY SHORT DELAY
	NOP
	NOP
	NOP
	CLR	LCDEN		;ENABLE/CHIP SELECT LOW
	RET


				;DELAY ROUTINES FOR LCD

				;FOR 22.1184MHZ CRYSTAL
MS20:	MOV	R6,#40		;20MS DELAY FOR AFTER POWER UP
MS21:	CALL	US500		;500 MICROSECOND DELAY
	DJNZ	R6,MS21
	RET

MS5:	MOV	R6,#10		;5MS DELAY AFTER CERTAIN DISPLAY FUNCTIONS
MS6:	CALL	US500		;500 MICROSECOND DELAY
	DJNZ	R6,MS6
	RET
				;500 MICROSECOND DELAY
US500:	MOV	R5,#229		;ABOUT 250 MICROSECONDS
	DJNZ	R5,$
	MOV	R5,#229		;ABOUT 250 MICROSECONDS
	DJNZ	R5,$
	RET


	END
