;******************************************************************** ; ; Hitachi LCD Display routines ; Karl Grabe, Cork, Ireland ; 09 May 95 Initial ; 10 May 95 8 Bit data port to LCD ; 13 Jun 95 4 bit data path on hi port nybble ; 17 Jun 95 4 bit data path on low port nybble ; Preserve other nybble's Tris and I/O state ; 22 Jun 95 Binary to BCD routines, PrintBCDw, PrintBCDlo ; 19 Jul 95 Remove LatchData to save a subroutine call ; ; Declare the following in main program along with ram: ; ; LCD_DATA : Port connected to LCD for 4/8 bit data xfer ; LCD_TRIS : TRIS port associated with LCD_DATA port ; E, RW, RS : Enable, read/write and instruction/data for LCD ; FourBit : True if using 4 bit data path to lcd (else 8) ; DataHi : True if using hi nybble of port, else lo nybble ; LineEnd : Number of characters in line 1 LCD ram ; (jump to line two when cursor passes LineEnd) ; LineLenght : Number of physical characters on a display line ; ; RAM: ; Cursor ; LCD Cursor Posn ; TablePtr ; Table message pointer ; CHAR ; Save char/inst to print ; CHAR2 ; Save char to print ; MsgLen ; Lenght of a table message ; WhichMsg ; Save message pointer (CenMsg) ; LCD_T2 ; Temp 4 bit xfer to port: Wh2LCDl ; LCD_T ; Reading busy flag: Busy_Q ;******************************************************************** INCLUDE LCD.inc ; Hitachi LCD command codes page ;******************************************************************** ; ; 'High' level LCD routines ; ;******************************************************************** ; Clear LCD and return cursor to position 0 on line 1 ClearHome CallW LCD_CMD, CLR_HOME ; Clear and home clrf Cursor ; Set our cursor to 0 return ; Print a message in Table pointed to by w DispMsg movwf TablePtr ; TablePtr holds start of message address call Table andlw h'FF' ; Check if at end of message (zero btfsc STATUS,Z ; returned at end) goto out_msg call PrintW ; Display character movf TablePtr,w ; Point to next character addlw 1 goto DispMsg out_msg return ; Get message length of message in Table to by w ; Lenght returned in w MesLen clrf MsgLen NextChar movwf TablePtr ; TablePtr holds start of message address call Table andlw h'FF' ; Check if at end of message (zero btfsc STATUS,Z ; returned at end) goto out_len incf MsgLen, f movf TablePtr,w ; Point to next character addlw 1 goto NextChar out_len movfw MsgLen RETURN ; Display a message centered on the lcd ; W is a pointer to the message in table CenMsg movwf WhichMsg ; Save the message pointer call ClearHome movfw WhichMsg ; Get message pointer Call MesLen ; Get the message lenght sublw LineLenght ; Find display blank spaces movwf MsgLen clrc ; (prevent problems with rrf) rrf MsgLen, w ; Devide by 2 Call PosCurs ; Position cursor movfw WhichMsg ; Get message pointer call DispMsg ; Print message in mid screen return ; Position cursor at position W (0...) ; If cursor > LineEnd then move to correct position on line 2 PosCurs movwf CHAR ; Save new cursor position movwf Cursor ; Used by Print to switch lines sublw LineEnd-1 ; Carry clear for w > LineEnd skpnc goto NoMov ; On line 1 movlw LineEnd ; Move to start of 2nd line... subwf CHAR, w ; .. by subtracting LineEnd addlw LINE_2 ; Add line 2 offset for command movwf CHAR NoMov movfw CHAR addlw DD_POS_MASK ; Mask with DD address command call LCD_CMD ; Postion cursor return ; Shift display one character to the right ; Note: Shifts both lines in a two line display... ; Some one line dislays are logically 2 lines so the shift ; won't be as expected. ShiftRight CallW LCD_CMD, SHIFT_MASK | SHIFT_DISP | SHIFT_RIGHT return ; Shif display one character to the left ShiftLeft CallW LCD_CMD, SHIFT_MASK | SHIFT_DISP | SHIFT_LEFT return PAGE ;******************************************************************** ; ; Integer Printing routines for LCD display ; ;******************************************************************** ;******************************************************************** ; PrintIntW ; Print Integer pointed to by W on LCD as 5 digits. ; ; Input: ; W: Pointer to lower (least significant) byte of integer ; ; Uses: ; FSR, L_byte, H_byte ; Calls: ; B2_BCD, PrintBCDw, PrintBCDlo ;******************************************************************** ; PrintIntW movwf FSR movfw INDF movwf L_byte ; Least sig byte of integer incf FSR, f movfw INDF movwf H_byte ; Most sig byte of integer PrintInt ; Call here with H, L_byte loaded call B2_BCD movlw R0 ; Most significant Digits movwf FSR call PrintBCDlo ; No need to print leading digit.. movlw R1 ; ..it's always zero call PrintBCDw movlw R2 ; LSD call PrintBCDw return ; Print w as an short integer using 3 lcd digits PrintWint movwf L_byte ; copy to print register clrf H_byte call B2_BCD movlw R1 ; Most significant Digits movwf FSR call PrintBCDlo ; No need to print leading digit.. movlw R2 ; ..it's always zero call PrintBCDw return ; Print a 2 byte ingeger in EE ram pointed to by W PrintEEintW movwf EEADR ; EE address of low byte Call ReadEEw ; Read EE data movwf L_byte ; Save for printing incf EEADR, f ; EE address of hi byte Call ReadEEw ; Read EE data movwf H_byte ; Save for printing goto PrintInt ;******************************************************************** ; PrintBCDw ; Print BCD byte (2 digits) pointed to by W ; PrintBCDlo ; Print least significant BCD byte (1 digit) ; ; Input: ; W: Pointer to byte ; Uses: ; FSR ; Calls: ; PrintW ;******************************************************************** PrintBCDw movwf FSR swapf INDF, w ; Get hi nybble andlw h'0F' addlw '0' ; Number to ACSII char call PrintW PrintBCDlo ; Just print the lower BCD nybble movfw INDF andlw h'0F' addlw '0' call PrintW return page ;******************************************************************** ; ; LCD low level communication routines ; Set FourBit for 4 bit data xfer to LCD, else 8 bit. ; Set DataHi for 4 bit xfer on Port hi nybble, else low nybble ; ;******************************************************************** ;******************************************************************** ; Initialise the LCD Display ;******************************************************************** if (FourBit) ; Data path 4 bit InitLCD clrf Cursor ; Set to start of display BCF LCD_RW ; Write to display BCF LCD_RS ; Display in instrucion mode CallW Wait10ms, d'1' ; Wait for LCD to power up theCmd set FUNC_MASK | DL4 | L2 | F5x7 movlw theCmd if (DataHi) call Wh2LCDh ; mov W hi to Port hi nybble else call Wh2LCDl ; mov W hi to Port low nybble endif ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off CallW Wait10ms, d'1' ; Can't use Busy_Q yet ; Repeat data with LCD_CMD, this time use 2 data xfers and Busy_Q works now CallW LCD_CMD, theCmd ; Display on, cursor theCmd set DISP_MASK | DISP_ON | CURS_OFF | BLINK_OFF CallW LCD_CMD, theCmd ; Cursor direction, shift on or off theCmd set ENTRY_MASK | INC_CURS | SHIFT_OFF ; Entry mode CallW LCD_CMD, theCmd Return else ; Data Path is 8 bit InitLCD clrf Cursor ; Set to start of display BCF LCD_RW ; Write to display BCF LCD_RS ; Display in instrucion mode CallW Wait10ms, d'1' ; Wait for LCD to power up ; Data width ; CallW LCD_CMD, FUNC_MASK | DL8 | L2 | F5x7 ; 4/8 bit, lines, font movlw FUNC_MASK | DL8 | L2 | F5x7 movwf LCD_DATA ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off CallW Wait10ms, d'1' ; Can't use Busy_Q yet ; Display on, cursor CallW LCD_CMD, DISP_MASK | DISP_ON | CURS_OFF | BLINK_OFF ; Cursor direction, shift on or off CallW LCD_CMD, ENTRY_MASK | INC_CURS | SHIFT_OFF ; Entry mode clrf Cursor ; Cursor at start of display Return endif page ;******************************************************************** ; ; Print a char in W to the LCD display ; Move to line 2 if necessary ; ;******************************************************************** if (FourBit) ; Use 4 bit High nybble data xfer to LCD PrintW movwf CHAR2 ; Save the char to print MOVFW Cursor ; Get the cursor XORLW LineEnd ; Check if its at the end of the line SKPZ goto Line1 CallW LCD_CMD, DD_POS_MASK | LINE_2 ; Yes, move to line 2 Line1 movfw CHAR2 ; Get back char to print call Busy_Q BSF LCD_RS ; Data mode if (DataHi) call Wh2LCDh ; W hi to LCD port Hi else call Wh2LCDl ; W hi to LCD port lo endif ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off swapf CHAR2, W ; Get low nybble if (DataHi) call Wh2LCDh ; W hi to LCD port Hi else call Wh2LCDl ; W hi to LCD port lo endif movwf LCD_DATA ; Send low nybble ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off incf Cursor,f ; Move to next LCD posn RETURN else ; 8 Bit data xfer PrintW movwf CHAR2 ; Save the char to print MOVFW Cursor ; Get the cursor XORLW LineEnd ; Check if its at the end of the line SKPZ goto Line1 CallW LCD_CMD, DD_POS_MASK | LINE_2 ; Yes, move to line 2 Line1 movfw CHAR2 ; Get back char to print call Busy_Q BSF LCD_RS ; Data mode MOVWF LCD_DATA ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off incf Cursor,f ; Move to next LCD posn RETURN endif page ;******************************************************************** ; ; Do an LCD command in w ; LCD assumed to be in write mode after Busy_Q ; Leave LCD in Instrucion mode ; ;******************************************************************** if (FourBit) ; 4 Bit data path, high nybble used LCD_CMD call Busy_Q ; Saves command in W and CHAR BCF LCD_RS ; Instruction mode if (DataHi) call Wh2LCDh ; W hi to LCD port hi else call Wh2LCDl ; W hi to LCD port lo endif ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off swapf CHAR, W ; Get lower nybble if (DataHi) call Wh2LCDh ; W hi to LCD port hi else call Wh2LCDl ; W hi to LCD port lo endif ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off return else ; 8 Bit data path LCD_CMD call Busy_Q BCF LCD_RS ; Instruction mode MOVWF LCD_DATA ; Latch data out to display bsf LCD_E ; Validate data on LCD bus IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF BCF LCD_E ; LCD has data, E off return endif if (FourBit) ;******************************************************************** ; Move the high nybble of W to the Hi byte of LCD_DATA ; Only Required in 4 bit modes ;******************************************************************** if (DataHi) Wh2LCDh MovWhFh LCD_DATA ; Mov W(hi) to LCD_DATA(hi) return else Wh2LCDl MovpWhFl LCD_DATA, LCD_T2 ; Mov W(hi) to LCD_DATA(low) return endif endif page ;************************************************************** ; Checks the busy flag, returns when not busy ; Uses: W, CHAR, LCD_T ; ; Outputs: ; LCD_T - Returned with busy/address ; W is preserved ; W also saved in CHAR ; ; Leave LCD in Write mode, and command mode ; ;************************************************************** if (FourBit) ; otherwise 8 bit port xfer if (DataHi) ; 4 Bit Data path, Xfer on HIGH port nybble Busy_Q movwf CHAR ; Save the char first BSF STATUS,RP0 ; Select Register page 1 ; Port tri-State: 0=Output movlw h'f0' iorwf LCD_TRIS, f ; Hi port nybble to inputs ; ..leave low nybble alone BCF STATUS, RP0 ; Select Register page 0 BCF LCD_RS ; Set LCD for command mode BSF LCD_RW ; Read LCD StillBusy bsf LCD_E ; LCD puts valid data on bus NOP ; E must stay hi for >450ns IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF ; First Transfer: LCD hi data into the Hi nybble of W MOVFW LCD_DATA BCF LCD_E ; Tristate LCD again andlw h'F0' ; mask out lower nybble MOVWF LCD_T ; Save LCD data bsf LCD_E ; LCD puts valid data on bus NOP ; E must stay hi for >450ns IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF ; Second Transfer: LCD low nybble into low nybble of W swapf LCD_DATA, w ; Put lower nybble in hi w BCF LCD_E ; Tristate LCD again andlw h'0F' iorwf LCD_T, f ; Combine nybbles BTFSC LCD_T, 7 ; Check busy flag, high=busy GOTO StillBusy ; Wait 'till bit 7 is clear BCF LCD_RW ; Default: write to lcd... ; ..Before switching port to o/p BSF STATUS, RP0 ; Select Register page 1 ; Port tri-State: 0=Output movlw h'0F' andwf LCD_TRIS, f ; Hi nubble tris to outpurs BCF STATUS, RP0 ; Select Register page 0 MOVFW CHAR ; Restor char to print RETURN else ; .. if (DataHi) ; 4 Bit Data path, Xfer on LOW port nybble Busy_Q movwf CHAR ; Save the char first BSF STATUS,RP0 ; Select Register page 1 ; Port tri-State: 0=Output movlw h'0F' ; Low nybble iorwf LCD_TRIS, f ; Lo port nybble to inputs ; ..leave hi nybble alone BCF STATUS, RP0 ; Select Register page 0 BCF LCD_RS ; Set LCD for command mode BSF LCD_RW ; Read LCD StillBusy bsf LCD_E ; LCD puts valid data on bus NOP ; E must stay hi for >450ns IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF ; First Transfer: LCD hi data into the lo nybble of W MOVFW LCD_DATA ; Get hi half of data First BCF LCD_E ; Tristate LCD again andlw h'0F' ; mask out higher nybble MOVWF LCD_T ; Save LCD data swapf LCD_T, F ; Put hi LCD data in hi LCD_T ; Second Transfer: LCD lo data into the lo nybble of W bsf LCD_E ; LCD puts valid data on bus NOP ; E must stay hi for >450ns IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP ENDIF movfw LCD_DATA ; Put lower nybble in low w BCF LCD_E ; Tristate LCD again andlw h'0F' ; Mask out hi nybble iorwf LCD_T, f ; Combine nybbles BTFSC LCD_T, 7 ; Check busy flag, high=busy GOTO StillBusy ; Wait 'till bit 7 is clear BCF LCD_RW ; Default: write to lcd... ; ..Before switching port to o/p BSF STATUS, RP0 ; Select Register page 1 ; Port tri-State: 0=Output movlw h'F0' andwf LCD_TRIS, f ; Hi nubble tris to outpurs BCF STATUS, RP0 ; Select Register page 0 MOVFW CHAR ; Restor char to print RETURN endif ; .. if (DataHi) else ; ... if (FourBit) ; 8 Bit Data path Busy_Q movwf CHAR ; Save the char first BSF STATUS,RP0 ; Select Register page 1 ; Port tri-State: 0=Output MOVLW B'11111111' ; Port to outputs MOVWF LCD_TRIS ; I/O BCF STATUS, RP0 ; Select Register page 0 BCF LCD_RS ; Set LCD for command mode BSF LCD_RW ; Read LCD StillBusy bsf LCD_E ; LCD puts valid data on bus NOP ; E must stay hi for >450ns IF F_OSC > 5000000 ; 10 Mhz clock = 400ns instruction cycle NOP endif MOVFW LCD_DATA BCF LCD_E ; Tristate LCD again MOVWF LCD_T ; Save LCD data BTFSC LCD_T, 7 ; Check busy flag, high=busy GOTO StillBusy ; Wait 'till bit 7 is clear BCF LCD_RW ; Default to write to lcd BSF STATUS, RP0 ; Select Register page 1 ; Port tri-State: 0=Output MOVLW B'00000000' ; PortB MOVWF LCD_TRIS ; I/O BCF STATUS, RP0 ; Select Register page 0 MOVFW CHAR ; Restor char to print RETURN endif ; .. if (FourBit) page ; - Mchip library routines: ; ;******************************************************************** ; Binary To BCD Conversion Routine ; This routine converts a 16 Bit binary Number to a 5 Digit ; BCD Number. This routine is useful since PIC16C55 & PIC16C57 ; have two 8 bit ports and one 4 bit port ( total of 5 BCD digits) ; ; The 16 bit binary number is input in locations H_byte and ; L_byte with the high byte in H_byte. ; The 5 digit BCD number is returned in R0, R1 and R2 with R0 ; containing the MSD in its right most nibble. ; ; Performance : ; Program Memory : 35 ; Clock Cycles : 885 ; NB uses FSR ; 22 Jun-95: mod kg, use cblock in main for ram registers instead of EQU ;*******************************************************************; ; ;count equ 16 ;temp equ 17 ; ;H_byte equ 10 ;L_byte equ 11 ;R0 equ 12 ; RAM Assignments ;R1 equ 13 ;R2 equ 14 ; ; include "mpreg.h" ; B2_BCD bcf STATUS,0 ; clear the carry bit movlw .16 movwf count clrf R0 clrf R1 clrf R2 loop16 rlf L_byte, f rlf H_byte, f rlf R2, f rlf R1, f rlf R0, f ; decfsz count, f goto adjDEC RETLW 0 ; adjDEC movlw R2 movwf FSR call adjBCD ; movlw R1 movwf FSR call adjBCD ; movlw R0 movwf FSR call adjBCD ; goto loop16 ; adjBCD movlw 3 addwf 0,W movwf temp btfsc temp,3 ; test if result > 7 movwf 0 movlw 30 addwf 0,W movwf temp btfsc temp,7 ; test if result > 7 movwf 0 ; save as MSD RETLW 0