; 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