Displaying Decimal Quantities on a Serial LCD

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

Introduction

This discussion deals with the conversion of natural binary quantities to BCD, suitable for display on a serial LCD or monitor. Routines are presented which accept either one or two natural binary bytes and display them on the serial LCD in decimal.

Program LCD_CTRL.ASM

Another discussion presents some simple routines which may be included in your application to control a serial LCD. These routines include;

	LCD_CLR		; clears serial LCD
	LCD_LINE1 	; locates cursor at beginning of line 1
	LCD_LINE2	; same except line 2
	LCD_CHAR	; displays the character in W on LCD
	LCD_VAL		; converts quantity in W and displays the two
			; characters

For example, assume you are making measurements using a DS1621 Digital Thermometer and after each reading you have the 8-bit representation in variable T_C. Assume the measured temperature is 104 degrees C.

One might be tempted to;

	MOVF T_C, W
	CALL LCD_VAL

The result which appears on the LCD panel will be 68. Note that the value in T_C is stored in natural binary and thus the result is displayed in hexadecimal. This is perfectly adequate for debugging, but Americans rejected the metric system. Even if they accept degrees C, they sure are not going to go for degrees C displayed in hexadecimal; "The temperature today is 1EH degrees C".

Program BCD_1.ASM

Thus, program BCD_1.ASM presents a program which allows you to do this;

	MOVF T_C, W
	MOVWF LO_BYTE
	CALL BCD_1

This will cause the temperature to appear in decimal as 104, not as 68.

The technique used is to successively subtract 100 from LO_BYTE while incrementing DEC_COUNT in a BCD fashion and then outputting DEC_COUNT on the serial LCD. If the hundreds digit is zero, it is replaced with a space.

The remainder of LO_BYTE is then decremented, while incrementing DEC_COUNT in a BCD fashion. DEC_COUNT is then displayed on the serial LCD.

Program BCD_2.ASM

Program BCD_2.ASM extends this to a two byte natural binary quantity, but is limited to values in the range 0000H - 270FH or 0 - 9999 decimal. The natural binary quantity to be displayed in decimal is transferred to subroutine BCD_2 using variables H_BYTE and LO_BYTE. The technique is similar to that used in BCD_1.ASM, except the successive subtraction of 100s involves borrowing from the HI_BYTE. Note that leading zero suppression is not implelented in BCD_2.ASM. Note that both of these rouyines require use of program LCD_CTRL.ASM.

; BCD_1.ASM 
; 
; Illustrates how to convert a one byte natural binary quantity to BCD.
; This is limited to FF H or 255 decimal.  
;
; The result is output to a serial LCD.  If the hundreds character is 0
; it is suppressed.
;
; The natural binary quantity is passed to subroutine BCD_1 in variable
; LO_BYTE.  
;
; The algorithm is one of successively subtracting 100 from the one byte 
; natural binary while incrementing a variable DEC_COUNT in a BCD 
; fashion. This is then output to serial LCD.  If it is zero, a space is  
; ouput in place of the leading.
;
; The remainder is then decremented in a natural binary fashion while 
; incrementing DEC_COUNT in BCD.  DEC_COUNT is then output to the serial 
; LCD.
;
; Note that LCD_CTRL.ASM is included at the end of the program.
;
; Copyright, Peter H. Anderson, Morgan State University, July 3, '97

 
	LIST p=16c84	; these lines not required when included in 
			; another file
#include <c:\mplab\p16c84.inc>	
	__CONFIG 11h

	CONSTANT VARS=0CH

LO_BYTE		EQU VARS+0
DEC_COUNT	EQU VARS+1	; used by BCD_1_BYTE routine
T_C		EQU VARS+2	; used for illustration

	ORG 000H
	
MAIN:
	; as an example, perform a temperature measurement
	; assume result is in T_C

	MOVLW 78H	; but i will dummy it to 120 degrees
	MOVWF T_C

	CALL LCD_CLR
	CALL LCD_LINE1
		
	MOVF T_C, W	; get the temperature
	MOVWF LO_BYTE	; place it in LO_BYTE

	CALL BCD_1_BYTE	; convert to BCD and display on serial LCD

DONE:			; endless loop
	GOTO DONE
	
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_VAL		; 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


; BCD_2.ASM 
; 
; Illustrates how to convert a two byte natural binary quantity to BCD.
; This is limited to XXXX H or 9999 decimal.  
;
; The result is output to a serial LCD.  There is no leading zero
; suppression.
;
; The natural binary quantity is passed to subroutine BCD_2 in variables
; HI_BYTE and LO_BYTE.  
;
; The algorithm is one of successively subtracting 100 from the two byte 
; natural binary while incrementing a variable DEC_COUNT in a BCD fashion.
; This is then output to serial LCD.
;
; The remainder is then decremented in a natural binary fashion while 
; incrementing DEC_COUNT in BCD.  DEC_COUNT is then output to the serial
LCD.
;
; Note that LCD_CTRL.ASM is included at the end of the program.
;
; Copyright, Peter H. Anderson, Morgan State University, July 3, '97

 
	LIST p=16c84	; these lines not required when included in 
			; another file
	#include <c:\mplab\p16c84.inc>	
	__CONFIG 11h

	CONSTANT VARS=0CH

HI_BYTE		EQU VARS+0
LO_BYTE		EQU VARS+1
DEC_COUNT	EQU VARS+2	; used by BCD_2_BYTE routine

	ORG 000H
	
MAIN:
	CALL LCD_CLR
	CALL LCD_LINE1
	MOVLW 3H		; dummy up 03CA H
	MOVWF HI_BYTE
	MOVLW 0CAH
	MOVWF LO_BYTE
	CALL BCD_2_BYTE		; display BCD value on serial LCD
DONE:
	GOTO DONE
	
BCD_2_BYTE:
BCD_2_HUNDS:
	CLRF DEC_COUNT
BCD_2_HUNDS1:
	MOVLW .100
	SUBWF LO_BYTE, F	; LO_BYTE=LO_BYTE-100
	BTFSS STATUS, C		; no borrow
	GOTO HUNDS_BORROW
	CALL INC_DEC_COUNT	; if no borrow
	GOTO BCD_2_HUNDS1	; keep going

HUNDS_BORROW:
	MOVLW .1
        SUBWF HI_BYTE, F
	BTFSS STATUS, C		; did not go from 00 to FF
	GOTO BCD_2_HUNDS2	; done with subtracting 100s

	CALL INC_DEC_COUNT	; if not done
	GOTO BCD_2_HUNDS1	; keep going

BCD_2_HUNDS2:
	MOVF DEC_COUNT, W	; get the count
	CALL LCD_VAL		; and display it
	MOVLW .100
	ADDWF LO_BYTE, F	; add back any falsely subtracted 100

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

BCD_2_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