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 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 #includeat 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