Interfacing a Serial LCD with PIC Projects (PIC16C84)

copyright, Peter H. Anderson and H. Paul Roach,
Dept of Electrical Engineering, Morgan State University,
Baltimore, MD 21239, June 14, '97


Note. Routine LCD_CTRL.ASM was revised on July 22, '97 to provide a 10 ms delay between characters. This assures that the receiving processor which controls the LCD has an adequate amount of time to process the received character and can get back to receive the next character.

Introduction.

This discussion deals with interfacing a PIC16C84 with a serial LCD panel such as that sold by Scott Edwards Electronics or the $9.95 basic serial LCD kit which we provide.

A serial LCD may well be a part of your finished design; for example, in prompting the user with screen messages or in displaying data.

However, it is also indispensible in troubleshooting during the debugging stage of your development. Most hobbyists cannot afford an emulator and are faced with the time consuming loop of write the assembly code, simulate, program the 16C84 and try it, and when it doesn't work, it's back to the assembler without much more information as to the problem than, "it didn't work".

The temporary use of a serial LCD during the dugging phase permits you to come away from the "failure" with some information, much like putting in "printfs" in C or using the "debug" command with the Basic Stamps.

Program LCD_CTRL.ASM.

Program LCD_CTRL.ASM is intended to be included in your program using the #include directive. It uses but one I/O bit, (PORTA, Bit 1) to interface with the serial LCD. The code required to output to the serial LCD and perform a few basic control functions is nominally 125 decimal bytes. Seven variables are used. This is overhead you can probably bear in most designs.

In addition to the 125 bytes of program memory, you must put temporary calls in your program code to write either a character or a value to the serial LCD, much like you would use the printf commands in C.

In debugging embedded applications, I have found that I am often interested in whether the program is going "here" or "there". Thus, you may wish to embed commands in your code to print a "." or a "!" or whatever you like when the program executes a particular segment of code.

Program LCD_CTRL.ASM provides code for you to do something like this in your program;

	MOVLW '.'
	CALL LCD_CHAR	; causes character in W to be displayed on LCD

But, we are also usually interested in the value of a variable at a particular point. Thus, you might write the following;

	MOVF BB, W	; get the variable BB in W
	CALL LCD_VAL	; causes value to be displayed on LCD as two Hex
			; characters

Of course, you could be more elegant, at some expense in your time and program memory. Perhaps; "5 BB=__", meaning the code is at point 5 and the value of BB is __.

	MOVLW '5'
	CALL LCD_CHAR	
	MOVLW ' '		; space
	CALL LCD_CHAR	
	MOVLW 'B'
	CALL LCD_CHAR	
	MOVLF 'B'
	CALL LCD_CHAR	
	MOVLW '='
	CALL LCD_CHAR	
	MOVF BB, W
	CALL LCD_VAL

You may wish to clear the LCD panel, go to line 1 or to line 2. Thus,

	CALL LCD_CLR
	CALL LCD_LINE1
	...
	CALL LCD_LINE2

Note that once you have set the cursor to the beginning of either line 1 or line 2, printing to the LCD begins at that point and it is up to you to assure the characters do not run off the LCD panel.

Other discussions focus on using these routines to display strings on the LCD panel and the conversion of either one or two byte natural binary quantities to BCD and displaying the result.

Notes on LCD_CTRL.ASM.

The implementations of LCD_CHAR, LCD_HEX, LCD_CLR, LCD_LINE1 and LCD_LINE2 are all contained in file LCD_CTRL.ASM.

You should be able to include this file in your program with the #include directive.

	#include <LCD_CTRL.ASM>

Note that the code in LCD_CTRL.ASM begins at 0380H. This was done with the idea of avoiding an overlap with your code. Of course, you can change this to whatever is workable.

In writing the various subroutines, I tried to keep the number of nested calls to a minimum as the 16C84 is limited to eight nested calls. I was able to keep the implementations of each higher order subroutine to one call. This is in addition to your call to the higher order subroutine.

Note that the variables used in the various subroutines occupy the upper portion of the general purpose register area (29H - 2FH). This leaves 0CH - 28 for your use.

Note that all of variables and labels in LCD_CTRL.ASM begin with the underscore character; for example;

	_SEROUT

This is to avoid duplications with labels you may wish to use in your program.

All subroutines save the W register and STATUS in temporary locations and restore them prior to returning to the program.

A 10 msec delay between characters has been incorporated in the _SEROUT routine. This assures that the processor controlling the LCD has an adequate amount of time to process the command and get back to receive the next character.

Example.

Program STEP_2.ASM used as an example in showing how to use all of the functions in LCD_CTRL.ASM.

The program successively outputs states to energize a single winding, two adjacent winding, the next single winding, etc. Thus, variable INDEX is incremented from 0 to 7 and then back to zero and this is mapped into the appropriate pattern which is output to the stepper.

Note that calls to functions LCD_CTRL have been inserted to display the value of INDEX on line 1 and the PATT on line 2.

In this program the delay between outputting patterns to the stepper has been increased to 250 msecs to allow the user to view the LCD.

; STEP_2.ASM
;
; Controls a stepping motor driver on lower four bits of Port B.  
;
; (Typical drivers might include a ULN2803 Octal Driver, 2N2222 or TIP122
; transistors or power FETs.  See Parallel Port Manual - Vol 1).
; 
; INDEX is incremented from 0 to 7 and then back to 0.  INDEX is mapped
; into a stepping motor pattern using the RETLW lookup technique and the
; pattern is output.  This is followed by a delay.  The duration of the 
; delay controls the speed of the stepper.
;
; copyright, LaQuiesia Smith, MSU, March '97
;
; Updated to include calls to LCD_CTRL.ASM to display INDEX and PATT on
; serial LCD.  Note #include  at bottom of program.
; Uses PORTA, Bit 1 to interface to serial LCD.
;
; Peter H. Anderson, MSU, June 14, '97

	LIST P=PIC16C84

	__CONFIG 11h
#include <P16C84.INC>

INDEX	EQU 0CH

LOOP1	EQU 10H
LOOP2	EQU 11H

	ORG 000H

	BCF STATUS, RP1		; bank 1
	BSF STATUS, RP0
	CLRF TRISB		; all bits on PORTB outputs
	BCF STATUS, RP0

INIT_INDEX:
	CLRF INDEX		; start INDEX at zero
	
GEN_PATT:
	CALL LCD_CLR		; clear the LCD	
     	MOVF INDEX, W		; copy count into w

	CALL LCD_LINE1
	CALL LCD_VAL		; display INDEX on line1

	CALL PATT		; returns the correct pattern in w

	CALL LCD_LINE2		
	CALL LCD_VAL		; display PATT on line 2

	MOVWF PORTB		; output PATT to PORTB
	
	CALL DELAY		; 250 msecs to see the LCD
	INCF INDEX, F		; increment INDEX to next pattern
	
	MOVF INDEX, W
	SUBLW 	.8		; INDEX - 8
	BTFSC	STATUS, Z	; if Z = 0, not zero and skip next
	GOTO	INIT_INDEX	; if Z=1
	GOTO	GEN_PATT

PATT:
	ADDWF	PCL, F		; add w to the program counter
	
	RETLW	01H		; stepping motor patterns
	RETLW	03H
	RETLW	02H

	RETLW	06H
	RETLW	04H
	RETLW	0CH
	RETLW	08H	
	
DELAY:				; provides nominal 250 msec delay
	MOVLW	.250
	MOVWF 	LOOP1
OUTTER:
	MOVLW	.110
	MOVWF 	LOOP2
INNER:
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	DECFSZ	LOOP2, F
	GOTO INNER
	DECFSZ 	LOOP1, F
	GOTO OUTTER
	RETURN

#include <A:\LCD_CTRL.ASM>

	END