1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

PIC ASM LCD. Check out my code.

Discussion in 'Microcontrollers' started by jakeselectronics, Apr 17, 2017.

  1. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    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
    Code (text):

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;                                                                                                       ;
    ;                                      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 (text):

    #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 (text):

    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 (text):

      ; 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 (text):

    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 (text):

    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 (text):

    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 (text):

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;                                                                                                       ;
    ;                                               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 (text):

      ; 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 (text):

      ; 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 (text):

            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?
     
    • Like Like x 1
  2. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Greetings, Jake:

    I played with this several years ago. I was trying to simplify writing to the LCD and eliminate the ~50-us LCD inter-write delay by writing to the display in my ISR. Basically, I would write one character to the display from a buffer during each 250-us (500 cycle) interrupt for a ~117-Hz refresh rate on my 2x16 display. The method works well but there's no way to use the LCD 'cursor' so if you need a blinking cursor you have to "roll your own". Anyway, check out the code and video...

    Have fun... Cheerful regards, Mike

    Code (text):

    /********************************************************************
     *                                                                  *
     *  Project: 12F1822 LCD Buffer Experiment                          *
     *   Source: 12F1822_LCD_Buffer_Experiment.c                        *
     *   Author: Mike McLaren, K8LH                                     *
     *  (C)2012: Micro Application Consultants, All Rights Reserved     *
     *     Date: 26-Jun-12                                              *
     *  Revised: 26-Jun-12                                              *
     *                                                                  *
     *  12F1822 Interrupt Driven Buffered LCD Experiment                *
     *                                                                  *
     *                                                                  *
     *      IDE: MPLAB 8.84 (tabs = 4)                                  *
     *     Lang: SourceBoost BoostC v7.05, Lite/Free version            *
     *                                                                  *
     ********************************************************************/

       #include <system.h>

       #pragma DATA _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF
       #pragma DATA _CONFIG2, _LVP_OFF & _PLLEN_OFF

       #pragma CLOCK_FREQ 8000000   // 8-MHz INTOSC

      /******************************************************************
       *  function prototypes                                           *
       ******************************************************************/
      /******************************************************************
       *  type definitions                                              *
       ******************************************************************/

       typedef unsigned char u08;
       typedef unsigned int u16;

       #define r08 rom unsigned char

      /******************************************************************
       *  variables and constants                                       *
       ******************************************************************/

          char temp;                //
          char count = 0;           //
          char huns;                //
          char tens;                //
          char ones;                //

          char lcd[33] = { "        HH:MM:SS                " };

          #define line1 0
          #define line2 16

          #define D4 0              // RA0
          #define D5 1              // RA1
          #define D6 2              // RA2
          #define D7 4              // RA4
          #define E  5              // RA5
          #define RS 0              // RA0(RC output)

      /*
       *  assembly language helpers
       */
          #define clrc  bcf   _status,C
          #define setc  bsf   _status,C
          #define skpz  btfss _status,Z
          #define skpnz btfsc _status,Z
          #define skpc  btfss _status,C
          #define skpnc btfsc _status,C

      /******************************************************************
       *  functions                                                     *
       ******************************************************************/

       void PutNyb()                //
       { asm movlw   1<<E           //
         asm btfsc   _temp,0        // b0 = 0?  yes, skip, else
         asm iorlw   1<<D4          //
         asm btfsc   _temp,1        // b1 = 0?  yes, skip, else
         asm iorlw   1<<D5          //
         asm btfsc   _temp,2        // b2 = 0?  yes, skip, else
         asm iorlw   1<<D6          //
         asm btfsc   _temp,3        // b3 = 0?  yes, skip, else
         asm iorlw   1<<D7          //
         asm movwf   _porta         // LCD D4..D7 = data1, E = 1
         asm bcf     _porta,E       // LCD E = 0
       }                            //

       void PutLCD()
       { asm movwf   _temp          // save WREG data byte
         asm swapf   _temp,F        //
         PutNyb();                  //
         asm swapf   _temp,F        //
         PutNyb();                  //
       }                            //

       void PutCMD(char pdata)      //
       { porta.RS = 0; PutLCD();    //
       }                            //

       void PutDAT(char pdata)      //
       { porta.RS = 1; PutLCD();    //
       }                            //


      /******************************************************************
       *  main init                                                     *
       ******************************************************************/

       void main()
       { ansela = 0;                // make pins digital
         trisa = 0b00000000;        // porta all outputs
         porta = 0;                 // all output latches low
         osccon = 0b01110010;       // initialize 8-MHz INTOSC
         while(!oscstat.HFIOFS);    // wait until OSC stable

        /*                                                              *
         *  HD44780 4-bit "initialize by instruction" procedure         *
         *                                                              */
         delay_ms(100);             //
         porta.RS = 0;              // RS=0
         temp = 0x03;               // hi nibble of "8-bit" command
         PutNyb(); delay_ms(4);     // step 1 (send nibble only)
         PutNyb(); delay_us(160);   // step 2 (send nibble only)
         PutNyb(); delay_us(160);   // step 3 (send nibble only)
         temp = 0x02;               // hi nibble of "4-bit" command
         PutNyb(); delay_us(160);   // select 4-bit interface mode

         PutCMD(0x28);              // 4-bit, 2-lines, 5x7 font
         delay_us(50);              //
         PutCMD(0x0C);              // display on, currsor & blink off
         delay_us(50);              //
         PutCMD(0x06);              // cursor inc, shift off
         delay_us(50);              //
         PutCMD(0x01);              // clear display
         delay_ms(2);               // required delay

        /*                                                              *
         *  setup TMR2 for 250-usec interrupts (8-MHz clock)            *
         *                                                              */
         tmr2 = 0;                  //
         t2con = 0b00000001;        // 00000001
                                    // -0000--- TOUTPS<3:0>, postscale 1
                                    // -----0-- TMR2ON, timer off
                                    // ------01 T2CKPS<1:0>, prescale 4
                                    // produces 2-usec 'ticks'
         pr2 = 125-1;               // 125 'ticks' = 250-usec interrupts
         pie1 = 1<<TMR2IE;          // enable Timer 2 interrupts
         pir1 = 0;                  // clear peripheral interrupt flags
         intcon.PEIE = 1;           // enable peripheral interrupts
         intcon.GIE = 1;            // enable global interrupts
         t2con.TMR2ON = 1;          // turn TMR2 on  

        /****************************************************************
         *  main loop                                                   *
         ****************************************************************/

         while(1)                   //
         {                          //
           delay_ms(250);           //
           delay_ms(250);           //

           lcd[line1+10] ^= (':'^' ');
           lcd[line1+13] ^= (':'^' ');

           delay_ms(250);           //

           count++;                 //
           huns = count/100;        //
           tens = (count/10)%10;    //
           ones = count%10;         //
          /*
           *  updating the display takes 9 cycles (4.5 us)
           */
           lcd[line1+2] = huns|'0'; //
           lcd[line1+3] = tens|'0'; //
           lcd[line1+4] = ones|'0'; //

           delay_ms(240);           //

           lcd[line1+10] ^= (':'^' ');
           lcd[line1+13] ^= (':'^' ');
         }                          //
       }

      /******************************************************************
       *                                                                *
       ******************************************************************/

       void interrupt()             // 250 usec (500 cycle) interrupts
       { static char line = 0xC0;   // sync buffer index & DDRAM address
         static char bndx = 0;      //  "

         pir1.TMR2IF = 0;           // clear TMR2 interrupt flag

        /*                                                              *
         *  write 32 data characters and two "DDRAM address" commands,  *
         *  one write per 250-usec interrupt, to refresh the buffered   *
         *  display once every 8.5-msecs (~117-Hz).                     *
         *                                                              */

         if(line & 0x80)            // if "new line"
           PutCMD(line ^= 0x40);    // set DDRAM address (0x80 or 0xC0)
         else                       // not "new line" so
           PutDAT(lcd[bndx++]);     // refresh display, bump index
      // if(bndx == 80)             // for 4x20 display
      //   bndx = 0;                //
      // if(bndx % 40 == 0)         //
      //   line ^= 0x80             // toggle b7 pseudo "new line" flag
         bndx &= 31;                // pseudo %32, 0..31 inclusive
         if((bndx & 15) == 0)       // if new line (0 or 16)
           line ^= 0x80;            // toggle b7 pseudo "new line" flag
       }
     
     
    • Like Like x 1
  3. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    Hey Mike!
    Sorry, I can't read C. But I sort of understand from your worded description.
    And by trying to read your C code and reading the line descriptions it looks very similar to what I'm doing except instead of refreshing the display completely in the interrupt, you have a shorter interrupt cycle where you update each character 1 by 1.

    So your buffer, are you using a ram byte for each character?
    Is that what this is?
    Code (text):

    char lcd[33] = { "       HH:MM:SS               " };
     
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA

    Hey, Jake. I'm grillin' and will be back after dinner with some explanations...
     
  6. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    Oh man, can you bring me back some. :woot:
     
  7. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Yes, that's a 32 character RAM buffer (C requires a 33rd byte for a nul string terminator).
     
  8. jakeselectronics

    jakeselectronics Member

    Joined:
    May 2, 2009
    Messages:
    401
    Likes:
    5
    Location:
    Macedon Ranges, Australia
    Arr cool. Well, our versions are quite similar then, all bar the interrupt.
    Onto my next question then. I'll start a new thread as it's regarding a different topic.
     
  9. Rich D.

    Rich D. Member

    Joined:
    Feb 3, 2014
    Messages:
    252
    Likes:
    20
    Location:
    West Chester, PA
    That's the same method I've used on several projects. At the time I didn't realize I couldn't use the automatic cursor on the LCD. Instead I used a "<" character next to the desired cursor position, but that wasn't ideal.

    If I had to do it again I would code it basically the same way, but instead of consistent updates every fraction of a second, I would have the routine that writes out the data to the LCD check a flag for any updates first. If no updates have been made to the character data and the update flag was not set, the update would not occur, allowing for the cursor to flash. Since my application doesn't require constant updates, the cursor has plenty of time to flash while the user is doing other things. My projects were done in assembly. The LCD refresh routine was not interrupt driven since there were more important timing uses for the interrupts, but done once every N-number of loops of the main code. Works well except for the cursor is a bit odd.
     

Share This Page