
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
