; WRITTEN BY PETER BIRNIE
; COPYRIGHT P. B. MICRO DESIGNS - 01494 531709
; DATE 11.8.95
; ITERATION 1.0
; FILE SAVED AS DOTLCD.ASM
; FOR PIC16C74-04/P WDT=off CP=off
; CLOCK 4.00 MHz RESONATOR
; INSTRUCTION CLOCK 1.00 MHz T= 1us
TITLE "DOTLCD.asm - LCD dot matrix driver and string handler"
LIST P=16C74
;----------------------------------------------------------------------------
; Program handle all aspects of setup and display on a dot matrix lcd
; display. Routines are provided to allow display of strings or
; characters, place the cursor and clear the display.
;----------------------------------------------------------------------------
; Register File Assignment
;----------------------------------------------------------------------------
INCLUDE "P16Cxx.INC"
;----------------------------------------------------------------------------
; Physical Port Assignment
;----------------------------------------------------------------------------
LCDPORT EQU RA ; Port A - LCD
;----------------------------------------------------------------------------
; Physical Bit Assignment
;----------------------------------------------------------------------------
; A port assignment
LCDRS EQU 4 ; Lcd register select output
LCDEN EQU 5 ; Lcd enable output
;----------------------------------------------------------------------------
; Constant Assignment
;----------------------------------------------------------------------------
MEMBAS EQU 20h ; Base address of user file registers
CLKR EQU 100h ; Roll over value for rtc - subtract count
; value from this to preset count down time.
DIV256 EQU %00000111 ; 256us prescale setting
; LCD commands
LCDCLER EQU %00000001 ; Clears display, resets curcor
LCDCM EQU %10000000 ; Sets cursor using bits 0 - 6
; Line 1 range - 0 to .15
; Line 2 range - .40 to .55
; NOTE that subroutine LCDCUR2 take the
; value in W in range 0 - 15 and adjusts for
; line 2 offset.
;----------------------------------------------------------------------------
; Variable Assignment
;----------------------------------------------------------------------------
GP1 EQU MEMBAS ; General purpose register
; LCD variables here
STRNUM EQU GP1+1
CHPT EQU STRNUM+1 ; Character string pointer in string.
LCDCH EQU CHPT+1 ; Saves byte to be sent to lcd while
; it is processed.
TABOFF EQU LCDCH+1 ; Table ofset pointer in lcd string lookup
;--------------------------------------------------------------------------
; Macros
;--------------------------------------------------------------------------
;******
; CLKLCD clocks data/command to the lcd by making the EN line
; high then low.
CLKLCD MACRO
SETB LCDPORT.LCDEN ; Lcd enable LOW
CLRB LCDPORT.LCDEN ; Lcd enable HIGH
ENDM
;******
; TABSET sets up the lcd table offset pointer before string output
; starts
TABSET MACRO
MOV W, #%11111111 ; Offset is incremented on each call to
; table - first call must generate zero value
; offset.
MOV TABOFF, W
ENDM
;******
; POINT increments the string pointer offset and adds it to the
; PLC ready for string lookup
POINT MACRO
INC TABOFF
MOV W, TABOFF
ADD PC, W
ENDM
;******
; POINT8 increments the string pointer offset and adds it to the
; PLC ready for string lookup. Sets PCLATH to 8
POINT8 MACRO
MOV W, #8
;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible
; MOVWF PCLATH
MOV PCLATH, W
INC TABOFF
MOV W, TABOFF
ADD PC, W
ENDM
;******
; POINT9 increments the string pointer offset and adds it to the
; PLC ready for string lookup. Sets PCLATH to 9
POINT9 MACRO
MOV W, #9
;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible
; MOVWF PCLATH
MOV PCLATH, W
INC TABOFF
MOV W, TABOFF
ADD PC, W
ENDM
;******
; TSTRTC moves TIMER0 to W reg and sets ZERO status
TSTRTC MACRO
MOV W, RTCC ; Test for timeout
ENDM
;******
; BANK0 selects register file bank 0
BANK0 MACRO
CLRB STATUS.RP0 ; Select BANK 0
ENDM
;******
; BANK1 selects register file bank 1
BANK1 MACRO
SETB STATUS.RP0 ; Select BANK 1
ENDM
;******
; PAGE0 selects rom page 0
PAGE0 MACRO
;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible
; BCF PCLATH,3 ; Select rom page 0
CLRB PCLATH.3 ; Select rom page 0
ENDM
;******
; PAGE1 selects rom page 1
PAGE1 MACRO
;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible
; BSF PCLATH,3 ; Select rom page 1
SETB PCLATH.3 ; Select rom page 1
ENDM
;--------------------------------------------------------------------------
; Vectors
;--------------------------------------------------------------------------
;******
; Reset vector
ORG 000
JMP INIT ; Do a cold start on power up
;******
; Interrupt vector - timer, keypad
ORG 004
JMP INIT ; No interrupt so reset
;--------------------------------------------------------------------------
; Subroutines
;--------------------------------------------------------------------------
;******
; STRING sends the string with number in W register - to the lcd
STRING
MOV STRNUM, W
TABSET ; Xero the offset
PAGE1
CALL DOSTR ; Character from string
PAGE0 ; Restore rom page
RET
;******
; BCDLCD sends the bcd character in W to lcd
BCDLCD OR W, #'00110000' ; Convert to ascii
;******
; PUTLCD sends the ASCII character in W to lcd
PUTLCD
MOV LCDCH, W
PAGE1
CALL CHALCD ; Character to lcd
PAGE0 ; Restore rom page
RET
;******
; CUR1 and CUR2 are indirect subroutine calls to LCDCUR1/2
; Enter with character placement in W in range 0 - 15
CUR1
PAGE1
CALL LCDCUR1 ; Line 1 please
PAGE0
RET
CUR2
PAGE1
CALL LCDCUR2 ; Line 2 please
PAGE0
RET
;******
; LCDCLR is an indirect call to LCDCLR1 on page 1
LCDCLR
PAGE1
CALL LCDCLR1
PAGE0
RET
;******
; WAITGP waits for the number of ms in GP1
WAITGP MOV W, #CLKR-4 ; 1ms timeout in TIMER0
MOV RTCC, W
WAITGPA TSTRTC
;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually.
BNZ WAITGPA ; Wait for rtc to time out
DEC GP1
;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually.
BNZ WAITGP ; Loop until delay is complete
RET ; Exit from WAITGP
;--------------------------------------------------------------------------
; Setup
;--------------------------------------------------------------------------
;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible
;INIT CLRF PCLATH
INIT CLR PCLATH
;******
;
; Set up peripheral control registers.
; Set port data directions: unused port pins set to outputs.
; A port setup
; Outputs
; RA0 - 3 lcd data
; RA4 lcd register select
; RA5 lcd enable
CLR LCDPORT
BANK1
MOV W, #%00000111 ; Select port A as digital
MOV ADCON1, W
MOV W, #%00000000 ; Set port data directions
;*** WARNING: TRIS registers are accessed by MOV !Rx, W (M = $0F or $1F).
; MOVWF TRISA
MOV TRISA, W
BANK0
;******
; Set up timer options
; Timer0 is set for internal, 1/4 ms pre scale
MOV W, #DIV256 ; Set RTC0 for 1/4 ms tick
BANK1
;*** WARNING: OPTION register is accessed only by MOV !OPTION, W.
; MOVWF OPTION_REG
MOV OPTION_REG, W
BANK0
;******
; Reset the lcd
INITA MOV W, #20 ; Delay for 20 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000011 ; Reset
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #6 ; Delay to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000011 ; Reset
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000011 ; Reset
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000010 ; 4 bit interface
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000010 ; 4 bit interface
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #%00001000 ; 2 LINES, 5*7
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000000 ; Display OFF
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #%00001000 ;
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000000 ; Display clear
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #%00000001 ;
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000000 ; Entry mode set
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #%00000110 ;
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
MOV W, #%00000000 ; Display on
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #%00001100 ;
MOV LCDPORT, W ; Command to lcd port
CLKLCD ; Clock the nibble to the lcd
MOV W, #5 ; Delay for 5 ms to let lcd settle
MOV GP1, W
CALL WAITGP ; Wait for lcd
;--------------------------------------------------------------------------
; Program start
;--------------------------------------------------------------------------
; Display demonstration banner
IDLE
CALL LCDCLR ; Not really required here as display has
; just been set up!
MOV W, #3
CALL CUR1 ; Position text on line 1
MOV W, #1 ; 'Microchip' - NOTE that the string is on
; second page of ROM at 0X800.
CALL STRING
; Move cursor for line 2 of banner
MOV W, #0
CALL CUR2 ; Position text on line 2
MOV W, #3 ; '16C74 drives lcd' - NOTE that the string
; is on second page of ROM at 0x900.
CALL STRING
IDLE1 JMP IDLE1 ; Just loop here please
;--------------------------------------------------------------------------
; Second page of ROM
;--------------------------------------------------------------------------
; Text strings and control subroutines must be stored on the correct
; page or this pcogram WILL NOT FUNCTION CORRECTLY.
; Only move code around if you are absoluteley clear as to what you
; are doing!
ORG $800
LAST EQU %10000000 ; Value to add to last character in a string
;******
; DOSTR uses CALLSTR table to direct flow to the correct lookup table
; for lcd strings. Gets string characters and outputs to lcd
DOSTR
MOV W, #8
;*** WARNING: PCLATH register bits are in STATUS PAx bits. Or use PAGE/IREAD if possible
; MOVWF PCLATH ; Keep the pageing ok
MOV PCLATH, W ; Keep the pageing ok
MOV W, STRNUM ; Get the string number
CALL CALLSTR
MOV LCDCH, W
CALL CHALCD ; Character to lcd
SB LCDCH.7 ; Test if end of string flagged - bit 7 set
JMP DOSTR ; Loop until all sent
RET
;******
; CALLSTR is the dispatch table for lcd string lookup
CALLSTR ADD PC, W
NOP
JMP MSG1 ; 'Microchip'
JMP MSG2 ; 'On page 9'
; more jumps can be added here
JMP MSG3 ; '16C74 drives lcd'
;******
; THE TEXT STRINGS!
MSG1 POINT8 ; Use macro POINT8 when the string is in 0x800
; address area
RETW #'M'
RETW #'i'
RETW #'c'
RETW #'r'
RETW #'o'
RETW #'c'
RETW #'h'
RETW #'i'
RETW #'p'+LAST
MSG2 POINT8
RETW #'O'
RETW #'n'
RETW #' '
RETW #'P'
RETW #'a'
RETW #'g'
RETW #'e'
RETW #' '
RETW #'8'+LAST
ORG $900
MSG3 POINT9 ; Use macro POINT9 when the string is in 0x900
; address area
RETW #'1'
RETW #'6'
RETW #'C'
RETW #'7'
RETW #'4'
RETW #' '
RETW #'d'
RETW #'r'
RETW #'i'
RETW #'v'
RETW #'e'
RETW #'s'
RETW #' '
RETW #'l'
RETW #'c'
RETW #'+LAST
;--------------------------------------------------------------------------
; Subroutines to handle the lcd
;--------------------------------------------------------------------------
; NOTE: these must be on page 1 of rom
; ------------------------------------
;*****
; CHALCD writes the character in W register to the lcd.
; On entry, the display character is in LCDCH.
CHALCD
; Get the upper nibble and load to the lcd port
MOV W, <>LCDCH ; Get the ms nibble to ls position
AND W, #07H ; Strip to ms nibble in ls position,
; and mask top bit in case this is the lset
; character in a string
MOV LCDPORT, W ; Data to lcd port
SETB LCDPORT.LCDRS ; Select lcd data
; Clock the ms nibble to the lcd
CLKLCD
; Get the lower nibble and load to the lcd port
MOV W, LCDCH ; Get back the character
AND W, #0FH ; Strip to ms nibble in ls position
MOV LCDPORT, W ; Data to lcd port
SETB LCDPORT.LCDRS ; Select lcd data
; Clock the ls nibble to the lcd.
CLKLCD
CLRB LCDPORT.LCDRS
JMP LCD64 ; Delay then exit from CHALCD
;*****
; COMLCD writes the command in W register to the lcd
; On entry, the command character is in LCDCH.
COMLCD
; Get the upper nibble and load to the lcd port
MOV W, <>LCDCH ; Get the ms nibble to ls position
AND W, #0FH ; Strip to ms nibble in ls position
MOV LCDPORT, W ; Command to lcd port
; Clock the ms nibble to the lcd
CLKLCD
; Get the lower nibble and load to the lcd port
MOV W, LCDCH ; Get back the character
AND W, #0FH ; Strip to ms nibble in ls position
MOV LCDPORT, W ; Command to lcd port
; Clock the ls nibble to the lcd.
CLKLCD
JMP LCD2 ; Delay then exit from COMLCD
;******
; LCDCL1R clears the display and resets the cursor
LCDCLR1 MOV W, #LCDCLER ; LCD clear command
MOV LCDCH, W
JMP COMLCD
;******
; LCDCUR1 sets cursor to position on line 1 using value in W register
LCDCUR1 OR W, #LCDCM ; Cursor move command
MOV LCDCH, W
JMP COMLCD
;******
; LCDCUR2 sets cursor to position on line 2 using value in W register
LCDCUR2 OR W, #LCDCM ; Cursor move command
MOV LCDCH, W
SETB LCDCH.6 ; This bit set for line 2
JMP COMLCD
;******
; LCD64/2 gives a delay of 64us or 1.6ms while the lcd accepts the
; data or command.
; Uses TMR0 - prescale is set to 16us in OPTION.
LCD64 MOV W, #CLKR-3 ; Gives 48/64 us delay
JMP LCDEL
LCD2 MOV W, #CLKR-100 ; Gives 1.6ms delay
LCDEL MOV RTCC, W ; Set TMR0 prescalar
LCDELA TSTRTC
;*** WARNING: MPASM macro BNZ is not supported yet. Replace manually.
BNZ LCDELA ; Wait for TMR0 to time out
RETW #0 ; Exit from CHA/COMLCD routines
END