jakeselectronics
Member
Hey everyone.
It's know it's been done 1000's of times before, BUT, I'm interested to know if the way I'm doing it is a good way.
So basically I'm driving a 4x16 LCD (44780 controlled) in 4-bit mode.
I set aside 64 bytes of ram (in bank 1) to use as LCD Character place holders.
Throughout the program if I want to write something to the display I simply move it to the RAM placeholders
I use TIMER0 to cause an interrupt and refresh the display every 0.0655 seconds/15.26Hz.
The ISR updates the display writing everything that is held in these RAM locations to the LCD.
Here are the code snippets pulled from my program.
My hardware setup
Definitions & RAM placeholders for 64 charaters of LCD (4x16)
Another RAM byte used for flags. Flags represent which screen to display
Text tables, used for printing strings of characters.
LCD one off Setup
TIMER0 interrupt
LCD Communication routines
LCD Screens
So, for example, in my main code, I do this.
And then when I want to print something to the LCD, such as temperatures on the temperatures screen, i do this:
Preload the LCD character RAM placeholder into the FSR, call BCD2ASCII where it converts the temperature data from BCD and places the ASCII equivelent into the RAM placeholders stating at RAM address "LCD_DISPLAY_R4C11"
Or, if i simply wanted to print a 'H' on the 3rd line in the first column, I could do this and the interrupt and update routines take care of the rest.
So, what do you think?
Is this a good way of driving an LCD?
How do-you/would-you do it?
It's know it's been done 1000's of times before, BUT, I'm interested to know if the way I'm doing it is a good way.
So basically I'm driving a 4x16 LCD (44780 controlled) in 4-bit mode.
I set aside 64 bytes of ram (in bank 1) to use as LCD Character place holders.
Throughout the program if I want to write something to the display I simply move it to the RAM placeholders
I use TIMER0 to cause an interrupt and refresh the display every 0.0655 seconds/15.26Hz.
The ISR updates the display writing everything that is held in these RAM locations to the LCD.
Here are the code snippets pulled from my program.
My hardware setup
Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; PIC16F628A Microcontroller ;
; ____ ____ ;
; BUZZER VREF/AN2/RA2 -| 1 - 18 |- RA1/AN1 TEMPERATURE SENSOR 1 ;
; PUSH BUTTON 1 CPM1/AN3/RA3 -| 2 17 |- RA0/AN0 TEMPERATURE SENSOR 2 ;
; PUSH BUTTON 2 CMP2/T0CKI/RA4 -| 3 16 |- RA7/OSC1/CLKIN CRYSTAL OSC ;
; PUSH BUTTON 3 VPP/MCLR/RA5 -| 4 15 |- RA6/OSC2/CLKOUT CRYSTAL OSC ;
; VSS -| 5 14 |- VDD ;
; LCD RS INT/RB0 -| 6 13 |- RB7/T1OSC1/PGD LCD D7 ;
; LCD RW DT/RX/RB1 -| 7 12 |- RB6/T1OSCO/T1CLKI/PGC LCD D6 ;
; LCD E CK/TX/RB2 -| 8 11 |- RB5 LCD D5 ;
; PWM OUT CCP1/RB3 -|_9____10_|- RB4/PGM LCD D4 ;
; ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Definitions & RAM placeholders for 64 charaters of LCD (4x16)
Code:
#DEFINE LCD_PORT PORTB
#DEFINE LCD_TRIS TRISB
#DEFINE LCD_E PORTB, 2
#DEFINE LCD_RW PORTB, 1
#DEFINE LCD_RS PORTB, 0
CBLOCK H'20' ;
LCD_DATA ;
LOOKUP_TABLE_POINTER ;
LCD_ADDRESS ;
ENDC
CBLOCK H'A0' ; Place in Bank 1 (General Purpose Registers 80 Bytes)
LCD_DISPLAY_R1C1
LCD_DISPLAY_R1C2
LCD_DISPLAY_R1C3
LCD_DISPLAY_R1C4
LCD_DISPLAY_R1C5
LCD_DISPLAY_R1C6
LCD_DISPLAY_R1C7
LCD_DISPLAY_R1C8
LCD_DISPLAY_R1C9
LCD_DISPLAY_R1C10
LCD_DISPLAY_R1C11
LCD_DISPLAY_R1C12
LCD_DISPLAY_R1C13
LCD_DISPLAY_R1C14
LCD_DISPLAY_R1C15
LCD_DISPLAY_R1C16
LCD_DISPLAY_R2C1
LCD_DISPLAY_R2C2
LCD_DISPLAY_R2C3
LCD_DISPLAY_R2C4
LCD_DISPLAY_R2C5
LCD_DISPLAY_R2C6
LCD_DISPLAY_R2C7
LCD_DISPLAY_R2C8
LCD_DISPLAY_R2C9
LCD_DISPLAY_R2C10
LCD_DISPLAY_R2C11
LCD_DISPLAY_R2C12
LCD_DISPLAY_R2C13
LCD_DISPLAY_R2C14
LCD_DISPLAY_R2C15
LCD_DISPLAY_R2C16
LCD_DISPLAY_R3C1
LCD_DISPLAY_R3C2
LCD_DISPLAY_R3C3
LCD_DISPLAY_R3C4
LCD_DISPLAY_R3C5
LCD_DISPLAY_R3C6
LCD_DISPLAY_R3C7
LCD_DISPLAY_R3C8
LCD_DISPLAY_R3C9
LCD_DISPLAY_R3C10
LCD_DISPLAY_R3C11
LCD_DISPLAY_R3C12
LCD_DISPLAY_R3C13
LCD_DISPLAY_R3C14
LCD_DISPLAY_R3C15
LCD_DISPLAY_R3C16
LCD_DISPLAY_R4C1
LCD_DISPLAY_R4C2
LCD_DISPLAY_R4C3
LCD_DISPLAY_R4C4
LCD_DISPLAY_R4C5
LCD_DISPLAY_R4C6
LCD_DISPLAY_R4C7
LCD_DISPLAY_R4C8
LCD_DISPLAY_R4C9
LCD_DISPLAY_R4C10
LCD_DISPLAY_R4C11
LCD_DISPLAY_R4C12
LCD_DISPLAY_R4C13
LCD_DISPLAY_R4C14
LCD_DISPLAY_R4C15
LCD_DISPLAY_R4C16
ENDC
Another RAM byte used for flags. Flags represent which screen to display
Code:
LCD_SCREEN_SELECT EQU H'76' ; -------0
; ------1- Welcome Screen
; -----2-- Temperatures Screen
; ----3--- Settings Screen a
; ---4---- Settings Screen b
; --5----- Settings Screen c
; -6------ Manual Control Screen
; 7-------
Text tables, used for printing strings of characters.
Code:
; Must be at top of program to attempt to keep Lookup Table in first 255 lines of the Program Memory
LOOKUP_TABLE_TEXT
ADDWF PCL, F ;
RETLW A'E' ; EFFECTIVE
RETLW A'F' ;
RETLW A'F' ;
RETLW A'E' ;
RETLW A'C' ;
RETLW A'T' ;
RETLW A'I' ;
RETLW A'V' ;
RETLW A'E' ;
RETLW A' ' ;
CLRW ; Effects Z bit, used to indicate end of print sequence
RETURN ;
RETLW A'W' ; WATER TEMP
RETLW A'A' ;
RETLW A'T' ;
RETLW A'E' ;
RETLW A'R' ;
RETLW A' ' ;
RETLW A'T' ;
RETLW A'E' ;
RETLW A'M' ;
RETLW A'P' ;
CLRW ;
RETURN ;
RETLW A'C' ; CONTROLLER
RETLW A'O' ;
RETLW A'N' ;
RETLW A'T' ;
RETLW A'R' ;
RETLW A'O' ;
RETLW A'L' ;
RETLW A'L' ;
RETLW A'E' ;
RETLW A'R' ;
CLRW ;
RETURN ;
RETLW A'T' ; Temperatures:
RETLW A'e' ;
RETLW A'm' ;
RETLW A'p' ;
RETLW A'e' ;
RETLW A'r' ;
RETLW A'a' ;
RETLW A't' ;
RETLW A'u' ;
RETLW A'r' ;
RETLW A'e' ;
RETLW A's' ;
RETLW A':' ;
CLRW ;
RETURN ;
RETLW A'C' ; Coolant
RETLW A'o' ;
RETLW A'o' ;
RETLW A'l' ;
RETLW A'a' ;
RETLW A'n' ;
RETLW A't' ;
CLRW ;
RETURN ;
RETLW A'C' ; Column
RETLW A'o' ;
RETLW A'l' ;
RETLW A'u' ;
RETLW A'm' ;
RETLW A'n' ;
CLRW ;
RETURN ;
RETLW A'P' ; Pump Speed
RETLW A'u' ;
RETLW A'm' ;
RETLW A'p' ;
RETLW A' ' ;
RETLW A'S' ;
RETLW A'p' ;
RETLW A'e' ;
RETLW A'e' ;
RETLW A'd' ;
CLRW ;
RETURN ;
RETLW B'11011111' ; (Celcius Character)
CLRW ;
RETURN ;
RETLW A'%' ; %
CLRW ;
RETURN ;
RETLW A'S' ; Settings:
RETLW A'e' ;
RETLW A't' ;
RETLW A't' ;
RETLW A'i' ;
RETLW A'n' ;
RETLW A'g' ;
RETLW A's' ;
RETLW A':' ;
CLRW ;
RETURN ;
RETLW A'P' ; Pump Min
RETLW A'u' ;
RETLW A'm' ;
RETLW A'p' ;
RETLW A' ' ;
RETLW A'M' ;
RETLW A'i' ;
RETLW A'n' ;
CLRW ;
RETURN ;
RETLW A'C' ; Control
RETLW A'o' ;
RETLW A'n' ;
RETLW A't' ;
RETLW A'r' ;
RETLW A'o' ;
RETLW A'l' ;
RETLW A':' ;
CLRW ;
RETURN ;
RETLW A'M' ; Manual
RETLW A'a' ;
RETLW A'n' ;
RETLW A'u' ;
RETLW A'a' ;
RETLW A'l' ;
CLRW ;
RETURN ;
RETLW A'A' ; Automatic
RETLW A'u' ;
RETLW A't' ;
RETLW A'o' ;
RETLW A'm' ;
RETLW A'a' ;
RETLW A't' ;
RETLW A'i' ;
RETLW A'c' ;
CLRW ;
RETURN ;
LOOKUP_TABLE_LOOP
; Execute loop and use lookup table to print text
MOVF LOOKUP_TABLE_POINTER, W ;
CALL LOOKUP_TABLE_TEXT ;
BTFSC STATUS, Z ; Z bit affected by CLRW instruction
RETURN
MOVWF INDF ;
INCF FSR ;
INCF LOOKUP_TABLE_POINTER, F ;
GOTO LOOKUP_TABLE_LOOP ;
LCD one off Setup
Code:
LCD_INITIALISE
BCF LCD_RS ; LCD treats data as a Command
BCF LCD_RW ; Write mode
CALL DELAY_100mS
MOVF LCD_PORT, W ;
ANDLW B'00001111' ; Keep lower nible of LCD_PORT unchanged, zero upper nibble
IORLW b'00110000' ; lower nibble must be zero, upper nibble is lower nibble of LCD Command (Function Set; 8-bit mode)
MOVWF LCD_PORT
CALL TOGGLE_E
CALL DELAY_5mS
MOVF LCD_PORT, W ;
ANDLW B'00001111' ; Keep lower nible of LCD_PORT unchanged, zero upper nibble
IORLW b'00110000' ; lower nibble must be zero, upper nibble is lower nibble of LCD Command (Function Set; 8-bit mode)
MOVWF LCD_PORT
CALL TOGGLE_E
CALL DELAY_5mS
MOVF LCD_PORT, W ;
ANDLW B'00001111' ; Keep lower nible of LCD_PORT unchanged, zero upper nibble
IORLW b'00110000' ; lower nibble must be zero, upper nibble is lower nibble of LCD Command (Function Set; 8-bit mode)
MOVWF LCD_PORT
CALL TOGGLE_E
CALL DELAY_5mS
MOVF LCD_PORT, W ;
ANDLW B'00001111' ; Keep lower nible of LCD_PORT unchanged, zero upper nibble
IORLW b'00100000' ; lower nibble must be zero, upper nibble is lower nibble of LCD Command (Function Set; 4-bit mode)
MOVWF LCD_PORT
CALL TOGGLE_E
CALL DELAY_5mS
; LCD now in 4-bit mode
MOVLW b'00101000' ; FUNCTION SET (4-bit, 2 line, 5x7 matrix)
CALL LCD_WRITE
MOVLW b'00001000' ; DISPLAY ON/OFF & CURSOR (Display off, underline off, blink off)
CALL LCD_WRITE
MOVLW b'00000001' ; CLEAR DISPLAY
CALL LCD_WRITE
MOVLW b'00000110' ; CHARACTER ENTYRY MODE (Increment, shift off)
CALL LCD_WRITE
MOVLW b'00001100' ; DISPLAY ON/OFF & CURSOR (Display on, underline off, blink off)
CALL LCD_WRITE
TIMER0 interrupt
Code:
TMR0_INTERRUPT
; Refresh display
UPDATE_LCD
BCF STATUS, IRP ; Indirect addressing Bank 0/1
MOVLW LCD_DISPLAY_R1C1 ; Initialise pointer to RAM
MOVWF FSR ; (File Select Register)
BCF LCD_RS ; LCD treats data as a COMMAND
MOVLW b'10000000' ; DISPLAY ADDRESS R1C1
CALL LCD_WRITE
CALL WRITE_16_CHAR
BCF LCD_RS ; LCD treats data as a COMMAND
MOVLW b'11000000' ; DISPLAY ADDRESS R2C1
CALL LCD_WRITE
CALL WRITE_16_CHAR
BCF LCD_RS ; LCD treats data as a COMMAND
MOVLW b'10010000' ; DISPLAY ADDRESS R3C1
CALL LCD_WRITE
CALL WRITE_16_CHAR
BCF LCD_RS ; LCD treats data as a COMMAND
MOVLW b'11010000' ; DISPLAY ADDRESS R4C1
CALL LCD_WRITE
CALL WRITE_16_CHAR
BCF INTCON, TMR0IF ;
CLRF TMR0
GOTO WHICH_INTERRUPT
LCD Communication routines
Code:
CLEAR_LCD_DISPLAY_RAM
; Write ascii 'blank space' charater to ram used for holding display charaters as b'00000000' shows a weird charater
MOVLW D'64' ;
MOVWF COUNT ; Set COUNT to number of registers to write
BCF STATUS, IRP ; Indirect addressing Bank 0/1
MOVLW LCD_DISPLAY_R1C1 ; Initialise pointer to RAM
MOVWF FSR ; (File Select Register)
BLANK_NEXT_GPR
MOVLW A' ' ; ASCII charater for blank space
MOVWF INDF ; Write to GPR
INCF FSR, F ; Increment RAM address pointer
DECFSZ COUNT, F ; Countdown, if zero; done
GOTO BLANK_NEXT_GPR ; Not zero, do again
RETURN
WRITE_16_CHAR
; This is a looping routine that writes 1 line (16 charaters at a time) to the display.
BSF LCD_RS ; LCD treats data as a character
MOVLW D'16' ;
MOVWF COUNT_ISR ;
NEXT_CHARACTER
MOVF INDF, W ;
CALL LCD_WRITE ;
INCF FSR, F ; Increment pointer
DECFSZ COUNT_ISR, F ;
GOTO NEXT_CHARACTER ;
RETURN
LCD_WRITE
; 4-bit data send routine
MOVWF LCD_DATA ; Move contents of W (could be command or charater data) to GPR
MOVLW B'00001111' ;
ANDWF LCD_PORT, F ; Zero upper nibble of LCD_PORT while leaving lower nibble unchanged
MOVF LCD_DATA, W ; Move contents of LCD_DATA to W. Original file register unchanged
ANDLW B'11110000' ; Zero lower nibble of W
IORWF LCD_PORT, F ; Move data to LCD Data Lines leaving lower nibble unchanged
CALL TOGGLE_E ; Enter
CALL LCD_CHECK_BUSY ; Wait while LCD complates exectuion
MOVLW B'00001111' ;
ANDWF LCD_PORT, F ; Zero upper nibble of LCD_PORT while leaving lower nibble unchanged
SWAPF LCD_DATA, W ; Swap upper and lower nibble of LCD_DATA to send next nibble to LCD
ANDLW B'11110000' ; Zero lower nibble of W
IORWF LCD_PORT, F ; Move data to LCD Data Lines leaving lower nibble unchanged
CALL TOGGLE_E ; Enter
CALL LCD_CHECK_BUSY ; Wait while LCD complates exectuion
RETURN
TOGGLE_E
BSF LCD_E ;
BCF LCD_E ;
RETURN
LCD_CHECK_BUSY ;
; Save LCD, RS state
BCF FLAGS, 2 ;
BTFSC LCD_RS ;
BSF FLAGS, 2 ;
BCF LCD_RS ;
BSF LCD_RW ;
; Switch to Bank 1 and change LCD comms IO to inputs while maintaining rest of port IO direction (set elsewhere in code)
BSF STATUS, RP0 ; Bank 1
MOVF LCD_TRIS, W ;
IORLW B'11110000' ; 0000 xxxx = LCD Comms Lines
MOVWF LCD_TRIS ;
BCF STATUS, RP0 ; Bank 0
LCD_READ_STATUS
BSF LCD_E ; Data is avaiable when E line is high
NOP ; Wait to make sure data is valid
BTFSC LCD_PORT, 7 ; Test busy flag of LCD
GOTO LCD_READ_STATUS ; LCD is busy, check again
BCF LCD_E ; LCD ready, lower E line
; Switch to Bank 1 and change LCD comms IO to outputs while maintaining rest of port IO direction (set elsewhere in code)
BSF STATUS, RP0 ; Bank 1
MOVF LCD_TRIS, W ;
ANDLW B'00001111' ; 0000 xxxx = LCD Comms Lines
MOVWF LCD_TRIS ;
BCF STATUS, RP0 ; Bank 0
; Reinstate RS
BTFSS FLAGS, 2 ;
GOTO $+2 ;
BSF LCD_RS ;
; Change back to write mode
BCF LCD_RW ;
RETURN
LCD Screens
Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; SCREEN 1 ;
; ;
; +----------------+ ;
; | EFFECTIVE | ;
; | | ;
; | WATER TEMP | ;
; | CONTROLLER | ;
; +----------------+ ;
; ;
; ;
; SCREEN 2 ;
; ;
; +----------------+ ;
; |Temperatures: | ;
; | Coolant 23.9*| ;
; | Column 25.0*| ;
; |Pump Speed 99.9%| ;
; +----------------+ ;
; ;
; ;
; SCREEN 3a ;
; ;
; +----------------+ ;
; |Settings: | ;
; | >Coolant 55.0*| ;
; | Column 45.0*| ;
; | Pump Min 60.0%| ;
; +----------------+ ;
; ;
; ;
; SCREEN 3b ;
; ;
; +----------------+ ;
; |Settings: | ;
; | Coolant 55.0*| ;
; | >Column 45.0*| ;
; | Pump Min 60.0%| ;
; +----------------+ ;
; ;
; ;
; SCREEN 3c ;
; ;
; +----------------+ ;
; |Settings: | ;
; | Coolant 55.0*| ;
; | Column 45.0*| ;
; | >Pump Min 60.0%| ;
; +----------------+ ;
; ;
; ;
; ;
; SCREEN 4 ;
; ;
; +----------------+ ;
; | | ;
; | | ;
; | | ;
; | | ;
; +----------------+ ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LCD_PRINT_ACTIVE_SCREEN
MOVWF LCD_SCREEN_SELECT ;
BTFSC LCD_SCREEN_SELECT, 1 ; Check LCD Screen Select flag bit
CALL LCD_SCREEN_1 ; Print Screen 1
BTFSC LCD_SCREEN_SELECT, 2 ; Check LCD Screen Select flag bit
CALL LCD_SCREEN_2 ; Print Screen 2
BTFSC LCD_SCREEN_SELECT, 3 ; Check LCD Screen Select flag bit
CALL LCD_SCREEN_3 ; Print Screen 3a
BTFSC LCD_SCREEN_SELECT, 4 ; Check LCD Screen Select flag bit
CALL LCD_SCREEN_3 ; Print Screen 3b
BTFSC LCD_SCREEN_SELECT, 5 ; Check LCD Screen Select flag bit
CALL LCD_SCREEN_3 ; Print Screen 3c
BTFSC LCD_SCREEN_SELECT, 6 ; Check LCD Screen Select flag bit
CALL LCD_SCREEN_4 ; Print Screen 4
RETURN
LCD_SCREEN_1
; Clear LCD & wipe RAM
MOVLW b'00000001' ; LCD 'Clear Display' Command
CALL LCD_WRITE ; Execute command
CALL CLEAR_LCD_DISPLAY_RAM ; Set all Display Character RAM to blank (Ascii charater ' ')
; Effective
MOVLW LCD_DISPLAY_R1C4 ; Set position on the LCD to start printing text,
MOVWF FSR ;
MOVLW D'0' ; and at which point of lookup table to print from
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Delay to give line by line scroll effect
CALL DELAY_100mS ;
CALL DELAY_100mS ;
CALL DELAY_100mS ;
; WATER TEMP
MOVLW LCD_DISPLAY_R3C4 ;
MOVWF FSR ;
MOVLW D'12' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; CONTROLLER
MOVLW LCD_DISPLAY_R4C4 ;
MOVWF FSR ;
MOVLW D'24' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
;
CALL DELAY_1S
RETURN
LCD_SCREEN_2
; Clear LCD & wipe RAM
MOVLW b'00000001' ;
CALL LCD_WRITE ;
CALL CLEAR_LCD_DISPLAY_RAM ;
; Temperatures:
MOVLW LCD_DISPLAY_R1C1 ;
MOVWF FSR ;
MOVLW D'36' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Coolant
MOVLW LCD_DISPLAY_R2C3 ;
MOVWF FSR ;
MOVLW D'51' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; (Celcius Charater)
MOVLW LCD_DISPLAY_R2C16 ;
MOVWF FSR ;
MOVLW D'80' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Column
MOVLW LCD_DISPLAY_R3C3 ;
MOVWF FSR ;
MOVLW D'60' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; (Celcius Charater)
MOVLW LCD_DISPLAY_R3C16 ;
MOVWF FSR ;
MOVLW D'80' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Pump Speed
MOVLW LCD_DISPLAY_R4C1 ;
MOVWF FSR ;
MOVLW D'68' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; %
MOVLW LCD_DISPLAY_R4C16 ;
MOVWF FSR ;
MOVLW D'83' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
RETURN
LCD_SCREEN_3
; Clear LCD & wipe RAM
MOVLW b'00000001' ;
CALL LCD_WRITE ;
CALL CLEAR_LCD_DISPLAY_RAM ;
; Settings:
MOVLW LCD_DISPLAY_R1C1 ;
MOVWF FSR ;
MOVLW D'86' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Coolant
MOVLW LCD_DISPLAY_R2C3 ;
MOVWF FSR ;
MOVLW D'51' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; (Celcius Charater)
MOVLW LCD_DISPLAY_R2C16 ;
MOVWF FSR ;
MOVLW D'80' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Column
MOVLW LCD_DISPLAY_R3C3 ;
MOVWF FSR ;
MOVLW D'60' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; (Celcius Charater)
MOVLW LCD_DISPLAY_R3C16 ;
MOVWF FSR ;
MOVLW D'80' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Pump Min
MOVLW LCD_DISPLAY_R4C3 ;
MOVWF FSR ;
MOVLW D'97' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; %
MOVLW LCD_DISPLAY_R4C16 ;
MOVWF FSR ;
MOVLW D'83' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Display Coolant Set Point
; Rearrange Temperature data and convert to BCD
MOVF COOLANT_SET_L, W ;
MOVWF DS18B20_DATA_ADJUST_L ;
MOVF COOLANT_SET_H, W ;
MOVWF DS18B20_DATA_ADJUST_H ;
CALL DS18B20_DATA_ADJUST ;
MOVLW LCD_DISPLAY_R2C11 ; Initialise pointer to RAM
MOVWF FSR ; (File Select Register)
; Convert to BCD result to ASCII charaters
CALL BCD2ASCII
; Display Column Set Point
; Rearrange Temperature data and convert to BCD
MOVF COLUMN_SET_L, W ;
MOVWF DS18B20_DATA_ADJUST_L ;
MOVF COLUMN_SET_H, W ;
MOVWF DS18B20_DATA_ADJUST_H ;
CALL DS18B20_DATA_ADJUST ;
MOVLW LCD_DISPLAY_R3C11 ; Initialise pointer to RAM
MOVWF FSR ; (File Select Register)
; Convert to BCD result to ASCII charaters
CALL BCD2ASCII
; Display Column Set Point
CALL DISPLAY_PWM_DC
; Place arrow next to currently active setting
BSF STATUS, RP0 ; Bank 1
MOVLW B'01111110' ; Right Arrow Character
BTFSC LCD_SCREEN_SELECT, 3 ; GPR in universal bank
MOVWF LCD_DISPLAY_R2C2 ; GPR in bank 2
BTFSC LCD_SCREEN_SELECT, 4 ;
MOVWF LCD_DISPLAY_R3C2 ;
BTFSC LCD_SCREEN_SELECT, 5 ;
MOVWF LCD_DISPLAY_R4C2 ;
MOVLW A' ' ; Blank Character
BTFSS LCD_SCREEN_SELECT, 3 ; GPR in universal bank
MOVWF LCD_DISPLAY_R2C2 ; GPR in bank 2
BTFSS LCD_SCREEN_SELECT, 4 ;
MOVWF LCD_DISPLAY_R3C2 ;
BTFSS LCD_SCREEN_SELECT, 5 ;
MOVWF LCD_DISPLAY_R4C2 ;
BCF STATUS, RP0 ; Bank 0
RETURN
LCD_SCREEN_4
; Clear LCD & wipe RAM
MOVLW b'00000001' ;
CALL LCD_WRITE ;
CALL CLEAR_LCD_DISPLAY_RAM ;
; Control:
MOVLW LCD_DISPLAY_R1C1 ;
MOVWF FSR ;
MOVLW D'107' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Manual
MOVLW LCD_DISPLAY_R2C3 ;
MOVWF FSR ;
MOVLW D'117' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
; Austomatic
MOVLW LCD_DISPLAY_R3C3 ;
MOVWF FSR ;
MOVLW D'125' ;
MOVWF LOOKUP_TABLE_POINTER ;
CALL LOOKUP_TABLE_LOOP ;
RETURN
So, for example, in my main code, I do this.
Code:
; Set LCD Screen with screen 1
; This method of setting a flag instead of just calling the 'LCD_SCREEN_1' routine is used so
; various pushbutton functions can be differentiated depending on which screen is active.
MOVLW B'00000010' ; Set Screen 1 Flag
CALL LCD_PRINT_ACTIVE_SCREEN
; Set LCD Screen with screen 2
MOVLW B'00000100' ; Set Screen 2 Flag
CALL LCD_PRINT_ACTIVE_SCREEN
And then when I want to print something to the LCD, such as temperatures on the temperatures screen, i do this:
Preload the LCD character RAM placeholder into the FSR, call BCD2ASCII where it converts the temperature data from BCD and places the ASCII equivelent into the RAM placeholders stating at RAM address "LCD_DISPLAY_R4C11"
Code:
; BCD2ASCII Pre call instructions
MOVLW LCD_DISPLAY_R4C11 ; Initialise pointer to RAM
MOVWF FSR ; (File Select Register)
CALL BCD2ASCII
Or, if i simply wanted to print a 'H' on the 3rd line in the first column, I could do this and the interrupt and update routines take care of the rest.
Code:
BSF STATUS, RP0 ; Bank 0
MOVLW A'H' ; Letter 'H' Character
MOVWF LCD_DISPLAY_R3C1 ; RAM in bank 1
BCF STATUS, RP0 ; Bank 0
So, what do you think?
Is this a good way of driving an LCD?
How do-you/would-you do it?