PIC16C84 - Outputting Strings to a Serial LCD

copyright, Peter H. Anderson, Dept of Electrical Engineering,
Morgan State University, Baltimore, MD 21239, July 20, '97

Introduction.

This discussion illustrates how to output strings to a serial LCD.

Program OUT_STR1.ASM.

This program simply clears the LCD and writes the classic string "Hello World" to the serial LCD.

In routine OUT_STR1, a string index is initialized to zero. The index is loaded into the W register, followed by a call to STR_1_LOOKUP which is simply a table of characters. The value of the W register is added to the PCL program counter and the character at that address is returned in the W register.

For example, if the string index is zero, the value of W when making the call to STR_1_LOOKUP is the same. Thus, the "zeroth" character ("H") is returned in W.

Note that the assembler directive

	DT "Hello World", 0

is used.

The assembler handles this as a series of RETLW instructions. That is;

	RETLW "H"
	RETLW "e"
	RETLW "l"
	etc
	RETLW "d"	
	RETLW 0

The returned character is then tested as to whether it is a NULL character and if so, the routine OUT_STR1 is exited. Otherwise, the character is output to the LCD and the string index is incremented. This continues until the NULL character is encountered.

Note the ADDLW 0 instruction which follows the call to the lookup table. The reason for this instruction, which does not alter the value of the W register, is to perform an arithmetic operation on the content of the W register to determine if the value is zero. Note that the RETLW instruction does not affect any of the STATUS register flags.

; Program OUT_STR1.ASM
;
; Outputs the string "Hello World" to a serial LCD or similar.
;
; PORTA, Bit 1 (terminal 18) ------ TX ----------> to RX on Serial LCD
;
; Note that program LCD_CTRL.ASM is included at the end of this program
;
; copyright, Peter H. Anderson, MSU, July 19, '97

	LIST p=16c84
#include <c:\mplab\p16c84.inc>	
	__CONFIG 11h

	CONSTANT VARS=0CH	; starting point for variables

STR_INDEX	EQU VARS+0

	ORG 000H	        
	
MAIN:
	CALL LCD_CLR		; clear the LCD
	CALL OUT_STR_1		; output the string "Hello World"
	
DONE:	GOTO DONE
	
OUT_STR_1:
	CLRF STR_INDEX
OUT_STR_11:
	MOVF STR_INDEX, W
	CALL STR_1_LOOKUP	; fetch the character
	ADDLW 0			; be sure flags are testing character
	BTFSC STATUS, Z
	GOTO OUT_STR_12		; done if null		
	CALL LCD_CHAR
        INCF STR_INDEX, F
	GOTO OUT_STR_11		; keep going
OUT_STR_12:
	RETURN

STR_1_LOOKUP:
	ADDWF PCL, F
	DT "Hello World", 0

#include <a:\lcd\lcd_ctrl.asm>	
	END

Program OUT_STR2.ASM.

This program shows how to output strings and how to convert a natural binary quantity to BCD so as to display "Temperature = XX.X Degrees C", where the XX.X is a variable.

In routine MEASURE, variables T_C_HI and T_C_LO are dummied to 16H and 80H, respectively. This might be the result of a temperature measurement using the DS1621 where the whole value of temperature is in T_C_HI and the fractional value is in the most significant bit of T_C_LO. That is, if the most significant bit of T_C_LO is a logic zero, the fractional value is 0.0; if it is a logic one, the fractional value is 0.5.

Thus, values of 16H and 80H in T_C_HI and T_C_LO corresponds to a deciaml temperature of 22.5.

In routine, OUT_STR1, the string "Temperature = " is output using the same technique described above.

The whole value of temperature, T_C_HI is passed to routine BCD_1_BYTE via variable LO_BYTE. This is converted to BCD and output to the serial LCD.

A decimal point is then output using routine LCD_CHAR.

The most significant bit of T_C_LO is then tested and either a "0" or a "5" is output.

In routine, OUT_STR2, the string " Degrees C" is output.

		
; Program OUT_STR2.ASM
;
; Program displays "Temperature = 22.5 Degrees C".
;
; Routine OUT_STR1 outputs "Temperature = ".  T_C_HI is then converted
; from natural binary to BCD and output to the serial LCD using routine 
; BCD_1_BYTE.  This is followed by a decimal point.  Then, either "0" or
; "5" is output depending on the most significant bit of T_C_LO.  This is 
; followed by a call to OUT_STR2 which outputs " Degrees C"
;
; PORTA, Bit 1 (terminal 18) ------ TX ----------> to RX on Serial LCD
;
; Note that program LCD_CTRL is included at the end of this program.
;
; copyright, Peter H. Anderson, MSU, July 19, '97

	LIST p=16c84
#include <c:\mplab\p16c84.inc>	
	__CONFIG 11h

	CONSTANT VARS=0CH	; starting point for variables

T_C_HI	EQU VARS+0		; the quantity to be displayed
T_C_LO  EQU VARS+1

STR_INDEX	EQU VARS+2	; used by OUT_STR routines.

LO_BYTE		EQU VARS+3	; used by BCD_1_BYTE routine
DEC_COUNT	EQU VARS+4	

	ORG 000H	        

	BSF STATUS, RP0		; RP1 = 0, RP0 = 1, BANK1
	CLRF TRISB		; make all PortB bits outputs
	BCF STATUS, RP0		; bank 0
	
MAIN:
	
	CALL	MEASURE	        
                
; at this point T_C_HI contains the temperature in degrees C
; The high bit in T_C_LO idicates whether it is .0 or .5
; this may be displayed on a serial LCD or similar or logged to
; EEPROM.
	CALL 	DISPLAY
DONE:	GOTO DONE
	

MEASURE:	; this is a dummy routine where T_C_HI and T_C_LO are
		; loaded with a value.
		; ordinarily this would be a part of a measurment process

	MOVLW 	16H	; 22 degrees C
	MOVWF 	T_C_HI
	MOVLW	80H	; 0.5 degrees C
	MOVWF	T_C_LO
	RETURN

DISPLAY:
	CALL LCD_CLR
	CALL OUT_STR_1		; "Temperature = "
	MOVF T_C_HI, W
	MOVWF LO_BYTE
	CALL BCD_1_BYTE		; Display whole number
	MOVLW "."
	CALL LCD_CHAR		; followed by a decimal point
	BTFSS T_C_LO, 7
	MOVLW "0"		; and then either a zero or one
	BTFSC T_C_LO, 7
	MOVLW "5"
	CALL LCD_CHAR
	CALL OUT_STR_2		; " degrees C"
	RETURN

OUT_STR_1:
	CLRF STR_INDEX
OUT_STR_11:
	MOVF STR_INDEX, W
	CALL STR_1_LOOKUP	; fetch the character
	ADDLW 0			; set flags
	BTFSC STATUS, Z
	GOTO OUT_STR_12		; done if null		
	CALL LCD_CHAR
        INCF STR_INDEX, F
	GOTO OUT_STR_11		; keep going
OUT_STR_12:
	RETURN

STR_1_LOOKUP:
	ADDWF PCL, F
	DT "Temperature = ", 0

OUT_STR_2:
	CLRF STR_INDEX
OUT_STR_21:
	MOVF STR_INDEX, W
	CALL STR_2_LOOKUP	; fetch the character
	ADDLW 0			; set flags
	BTFSC STATUS, Z
	GOTO OUT_STR_22		; done if null		
	CALL LCD_CHAR
        INCF STR_INDEX, F
	GOTO OUT_STR_21		; keep going
OUT_STR_22:
	RETURN

STR_2_LOOKUP:
	ADDWF PCL, F
	DT " Degrees C", 0

BCD_1_BYTE:
BCD_1_HUNDS:
	CLRF DEC_COUNT
BCD_1_HUNDS1:
	MOVLW .100
	SUBWF LO_BYTE, F	; LO_BYTE=LO_BYTE-100
	BTFSS STATUS, C		; no borrow
	GOTO BCD_1_HUNDS2
	CALL INC_DEC_COUNT	; if no borrow
	GOTO BCD_1_HUNDS1	; keep going

BCD_1_HUNDS2:
	MOVF DEC_COUNT, W	; get the count
	BTFSC STATUS, Z		; if not zero
	MOVLW " "		; otherwise put in a space
	CALL LCD_CHAR		; and display it

	MOVLW .100
	ADDWF LO_BYTE, F	; add back any falsely subtracted 100

BCD_1_UNITS:
	CLRF DEC_COUNT		; now for the units
BCD_1_UNITS1:
	MOVLW .1
	SUBWF LO_BYTE, F
	BTFSS STATUS, C		; did not go from 00 to FF
	GOTO BCD_1_UNITS2	; done with units
	
	CALL INC_DEC_COUNT	; else increment and keep going
	GOTO BCD_1_UNITS1	

BCD_1_UNITS2:
	MOVF DEC_COUNT, W	; get the number of units
	CALL LCD_VAL		; and display

	RETURN

INC_DEC_COUNT:			; increments counter in BCD fashion

	INCF DEC_COUNT, F
	MOVF DEC_COUNT, W
	ANDLW 0FH
	SUBLW .9		; W = low nibble - 9
	BTFSC STATUS, C		; low nibble is in range of A - F
	GOTO INC_DEC_COUNT_DONE

	MOVF DEC_COUNT, W
	ADDLW .6
	MOVWF DEC_COUNT

INC_DEC_COUNT_DONE:
	RETURN

#include <a:\lcd\lcd_ctrl.asm>	
	END