Continue to Site

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.

  • 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.

Read LCD display

Status
Not open for further replies.

Goofballzach

New Member
I am working on a project for school. Using a keypad I have set "1" key to display my name. When I press the "*" key, I want to read what's on the LCD and compare it to data stored on the PIC18f4520. Go to the next line and translate it to Japanese. The only problem I am having is getting the PIC to read from the LCD. I am working in Assmebly. Any help would be much appreciated.
 
Code:
;   Oscillator Selection:
    CONFIG  OSC = INTIO67
    CONFIG    WDT = OFF
    CONFIG    MCLRE = ON
    CONFIG    PBADEN = off
    CONFIG    LVP = off
;******************************************************************************
;Variable definitions
; These variables are only needed if low priority interrupts are used.
; More variables may be needed to store other special function registers used
; in the interrupt routines.

;        UDATA
preston EQU    0x20
zach    EQU    0x30
prestonj    EQU    0x50
zachj    EQU    0x40
translate    EQU    0x60
    cblock    0x10
    counta
    countb
    countc
    test

    endc
#define    c1 PORTB,0
#define c2 PORTB,1
#define c3 PORTB,2
#define    r1 PORTB,3
#define    r2 PORTB,4
#define    r3 PORTB,5
#define    r4 PORTB,6
#define    RS PORTD,0
#define RW PORTD,1
#define    EN PORTD,2
;        UDATA_ACS

;EXAMPLE        RES    1    ;example of a variable in access RAM



;******************************************************************************
;Reset vector
; This code will start executing when a reset occurs.

RESET_VECTOR    CODE    0x0000

goto    Main        ;go to start of main code



;******************************************************************************
;Start of main program
; The main program code is placed here.

Main:
    movlw    0x0A
    movwf    ADCON1
    movlw    0x0A
    movwf    CMCON
    call    init  
    call    scan_main
scan_main
    call    scan1    ;subroutines for keypad to check/display
    call    scan2    ;
    call    scan3    ;
    goto    scan_main
init
    clrf    PORTB
    clrf    PORTD    ;
    clrf    PORTC    ;setting up PORTD/PORTC/PORTB
    clrf    TRISC    ;as output
    clrf    TRISD    ;
    clrf    TRISB    ;
    movlw    0xF8
    movwf    TRISB    ;setting portb as output(column) and input(rows)
    bcf        RS    ;clearing R/S and R/W
    bcf        RW    ;
    movlw    0x38    ;initializing
    movwf    PORTC    ;LCD
    call    toggle
    movlw    0x38 
    movwf    PORTC    ;
    call    toggle
    movlw    0x38
    movwf    PORTC    ;
    call    toggle
    movlw    0x0F    ;setting up display and cursor
    movwf    PORTC
    call    toggle
    movlw    0x14    ;turn on display and direction of cursor
    movwf    PORTC
    call    toggle
    movlw    0x01    ;clear display
    movwf    PORTC
    call    toggle
    movlw    0x06    ;character entry mode
    movwf    PORTC
    call    toggle
    bsf        RS
zach_japanese
    movlw    0xBB    ;loading cblock with
    movwf    0x41    ;with hex values for
    movlw    0xDE    ;characters
    movwf    0x42
    movlw    0xAF
    movwf    0x43
    movlw    0xB8
    movwf    0x44
preston_japanese
    movlw    0xCD
    movwf    0x51
    movlw    0xDF
    movwf    0x52
    movlw    0xDA
    movwf    0x53
    movlw    0xBD
    movwf    0x54
    movlw    0xC4
    movwf    0x55
    movlw    0xDD
    movwf    0x56
zach_english
    movlw    'Z'
    movwf    0x31
    movlw    'a'
    movwf    0x32
    movlw    'c'
    movwf    0x33
    movlw    'h'
    movwf    0x34
preston_english
    movlw    'P'
    movwf   0x21
    movlw   'r'
    movwf   0x22
    movlw   'e'
    movwf   0x23
    movlw   's'
    movwf   0x24
    movlw   't'
    movwf   0x25
    movlw   'o'
    movwf   0x26
    movlw   'n'
    movwf   0x27
translate?pushAsterisk  
    movlw    'T'
    movwf    0x61
    movlw    'r'
    movwf    0x62
    movlw    'a'
    movwf    0x63
    movlw    'n'
    movwf    0x64
    movlw    's'
    movwf    0x65
    movlw    'l'
    movwf    0x66
    movlw    'a'
    movwf    0x67
    movlw    't'
    movwf    0x68
    movlw    'e'
    movwf    0x69
    movlw    '?'
    movwf    0x6A
    movlw    ' '
    movwf    0x6B
    movlw    'P'
    movwf    0x6C
    movlw    'u'
    movwf    0x6D
    movlw    's'
    movwf    0x6E
    movlw    'h'
    movwf    0x6F
    movlw   ' '
    movwf   0x70
    movlw    '*'
    movwf   0x71
    return
scan3
    bsf    c3    ;sending a hi to column3
    btfsc    r1    ;checking row 1
    call    asterisk ;translate subroutine
    call    delay
    btfsc    r2    ;checking row 2
    call    seven    ;7 display subroutine
    call    delay
    btfsc    r3    ;checking row 3
    call    four    ;4 display subroutine
    call    delay
    btfsc    r4    ;checking row 4
    call    one    ;1 display subroutine
    call    delay
    bcf    c3    ;clear column3 to check other columns
    return
scan2
    bsf    c2    ;sending a hi to column3
    btfsc    r1    ;checking row 1
    call    zero    ;0 display subroutine
    call    delay
    btfsc    r2    ;checking row 2
    call    eight    ;8 display subroutine
    call    delay
    btfsc    r3    ;checking row 3
    call    five    ;5 display subroutine
    call    delay
    btfsc    r4    ;checking row 4
    call    two    ;2 display subroutine
    call    delay
    bcf    c2    ;sending a low to column2 to check other columns
    return
scan1
    bsf    c1    ;sending a hi to column1
    btfsc    r1    ;checking row 4
    call    pound    ;clear display subroutine
    call    delay
    btfsc    r2    ;checking row 4
    call    nine    ;9 display subroutine
    call    delay
    btfsc    r3    ;checking row 4
    call    six    ;6 display subroutine
    call    delay
    btfsc    r4    ;checking row 4
    call    three    ;3 display subroutine
    call    delay
    bcf    c1    ;sending a low to column1 to check other column
    return
one
    call    prestonE_set
    call    translate_set
    return
two
    call    zachE_set
    call    translate_set
    return
three
    call    prestonj_set
    call    translate_set
    return
four
    call    zachj_set
    call    translate_set
    return
five
    movlw    '5'    ;subroutine displays 5 on LCD
    movwf    PORTC
    call     toggle
    return
six
    movlw    '6'    ;subroutine displays 6 on LCD
    movwf    PORTC
    call     toggle
    return 
seven
    movlw    '7'    ;subroutine displays 7 on LCD
    movwf    PORTC
    call    toggle
    return
eight
    movlw    '8'    ;subroutine displays 8 on LCD
    movwf    PORTC
    call    toggle
    return
nine
    movlw    '9'    ;subroutine displays 9 on LCD
    movwf    PORTC
    call    toggle
    return
zero
    movlw    '0'    ;subroutine displays 0 on LCD
    movwf    PORTC
    call    toggle
    return
pound    ;Clear LCD
    bcf    RS    ;subroutine clears the LCD
    movlw    0x01
    movwf    PORTC
    call    toggle
    return 
asterisk
    bcf        RS
    movlw    0x094
    movwf    PORTC
    call    toggle
    bsf        RS
    movlw    'G'
    movwf    PORTC
    call    toggle
 
 
;**read whats at that address(change portC to input?)
    ;cpfseq    0x21    ;checking for Preston in english
    ;goto    Ast1
    ;**move to line 3
 

    ;Ast1
    ;    cpfseq    0x51    ;checking for Preston in japanese
        ;goto    Ast2
    ;    **move to line 3
    ;Ast2
    ;    cpfseq    0x31    ;checking for Zach in english
    ;    goto    Ast3
    ;    **move to line 3

    ;Ast3
    ;    cpfseq    0x41    ;checking for Zach in Japanese
    ;    return
    ;    **move to line 3


        return




;        *****EXTENSIVELY USED SUBROUTINES*****
port_set1
    bcf        RW
    bcf        RS
    clrf    PORTC
    clrf    TRISC
    movlw    0x090
    movwf    PORTC
    call    toggle
    call    prestonj_set
    return
port_set
    bcf        RW
    bcf        RS
    clrf    PORTC
    clrf    TRISC
    bsf        RS
    movlw    'B'
    movwf    PORTC
    call    toggle
    return
 

toggle
    bsf    EN    ;set Enable high
    call    delay
    bcf    EN    ;set Enable low to write letter
    call    delay
    return
zachE_set
    movlw    0x04
    movwf    test
    lfsr    0,zach    ;setting pointer to send letter to LCD
    bcf        RW
    bsf        RS    ;setting R/S to allow characters to be written
zachE_name
    incf    FSR0L,1    ;increment to next location
    movff    INDF0,PORTC    ;moving pointer value to PortC
    call    toggle 
    call    delay
    decfsz    test
    goto    zachE_name    ;First name
    return
zachj_set
    movlw    0x04
    movwf    test
    lfsr    0,zachj    ;setting pointer to send letter to LCD
    bcf        RW
    bsf        RS    ;setting R/S to allow characters to be written
zachj_name
    incf    FSR0L,1    ;increment to next location
    movff    INDF0,PORTC    ;moving pointer value to PortC
    call    toggle 
    call    delay
    decfsz    test
    goto    zachj_name    ;First name
    return
prestonE_set
    movlw    0x07
    movwf    test
    lfsr    0,preston    ;setting pointer to send letter to LCD
    bcf        RW
    bsf        RS    ;setting R/S to allow characters to be written
prestonE_name
    incf    FSR0L,1    ;increment to next location
    movff    INDF0,PORTC    ;moving pointer value to PortC
    call    toggle 
    call    delay
    decfsz    test
    goto    prestonE_name    ;First name
    return
prestonj_set
    movlw    0x06
    movwf    test
    lfsr    0,prestonj    ;setting pointer to send letter to LCD
    bcf        RW
    bsf        RS    ;setting R/S to allow characters to be written
prestonj_name
    incf    FSR0L,1    ;increment to next location
    movff    INDF0,PORTC    ;moving pointer value to PortC
    call    toggle 
    call    delay
    decfsz    test
    goto    prestonj_name    ;First name
    return
translate_set
    bcf        RS
    movlw    0x40
    movwf    PORTC
    call    toggle
    movlw    0x0C0
    movwf    PORTC
    call    toggle
    movlw    0x11
    movwf    test
    lfsr    0,translate    ;setting pointer to send letter to LCD
    bcf        RW
    bsf        RS    ;setting R/S to allow characters to be written
translate_name
    incf    FSR0L,1    ;increment to next location
    movff    INDF0,PORTC    ;moving pointer value to PortC
    call    toggle 
    call    delay
    decfsz    test
    goto    translate_name    ;First name
    return
delay
    movlw    0x0f
    movwf    countc
    movlw    0x2f
    movwf    countb
;    movlw    0x02
;    movwf    counta
loop
;    decfsz    counta,1
;    goto    loop
    decfsz    countb,1
    goto    loop
    decfsz    countc,1
    goto    loop
    return


;******************************************************************************
;End of program

END
 
Last edited:
Please use code tags. That is, begin with {code=asm} and end with {/code}. Replace curly brackets/braces with brackets.

What LCD are you using? Is it HD44780 compatible (if character)? 4-bit or 8-bit mode?

John
 
Also you don't seem to be using any time delayed set up procedure if it is HD44780 compatible.
Edit as John said for Code tags
Max.
 
I'm using 20x4 line HD44780 and using 8 bit mode.

Could you show me an example of what you mean for the code tags? I have programmed in only ASM
 
Last edited:
I described code tags in my post above. Here is a snippet of some code in which I inserted the tags so you can see what they look like:
upload_2015-12-2_15-18-36.png


Of course, the words "code=asm" and "/code" don't appear in the post. Here is what a portion of that post looks like using code tags:

Code:
PutCmd
     bcf       RS
     goto      $+2
PutDat
    bsf       RS
     swapf     WREG,f
     movwf     PORTC

Also, be sure to use spaces, not tabs in your code.

I agree with Max, you don't have any delays in your initialization. That won't work. You also need delays later in the code or you need to wait for the Busy Flag (BF) to clear.

John
 
It is also handy to use a colon on a label.
e.g. PutCmd:
If doing a search for a routine.
Max.
 
I do have a delay routine if you look at the bottom. I have it built to my toggle as well. Thank you for the info I have fixed my original code
 
Last edited:
How long is that delay in toggle?

See comments in code:
Code:
toggle
   bsf   EN    ;set Enable high
   call   delay
;COMMENT: You do not need a long delay here.   The controller probably requires on the order of 450 ns. ;Thus, at 8 MHz, I do not use any delay.
    bcf    EN    ;set Enable low to write letter
   call   delay
;COMMENT: Here, you need 50 to 100 usecs, not a long delay.
    return

For initialization, you need the delays spelled out for your LCD.
This delay is quite short:
Code:
loop
;    decfsz    counta,1
;    goto    loop
    decfsz    countb,1
    goto    loop
    decfsz    countc,1
;COMMENT: Once countb goes to zero, it is not replenished, so the loop for countc just adds ;to the first.  That is, the loops are not nested.
    goto    loop
    return


EDIT: Sorry, that delay at 20 MHz is 2.1846 msecs. I forgot that your countb goes to 0xFF after the skip. That is not the usual way I write a delay.

John
 
Last edited:
My delay is about 1/4 of a second. My LCD has no problems initializing, and when I press 1-9, *, # on the keypad they all work. My goal is:
Line 1 LCD : Zach(1-9 on keypad is English or Japanese name, and # will clear the LCD screen)
Line 2 LCD: Translate? Press *(when I push * key I want it to move to the next line and print the Japanese or English translation)
Line 3 LCD: (Zach would be translated to Japanese on this line)
Line 4 LCD: (Not used )

I can get Line 1 and Line 2 to work no problem. The issue I am running into is reading the name in Line 1 on the LCD and moving that value to the WReg so I can do a bunch of cpfseq commands to get the proper translation to show on the Line 3. When I attempted to read the LCD, I set the DDRAM address to 0X00(First letter for the name), set RS and RW high, changed PORTC to INPUT, then toggled EN, I moved PORTC to WReg but the only thing that happened was the curser moved to the next space. This tells me it did the read operation but did not make it to the WReg. Im not sure what I need to do.
 
Your code doesn't include any instructions for switching banks. The TRIS registers are in different banks from the PORT registers. So, if you're trying to change a port from output to input so that you can read the LCD, then it will fail, because the TRIS hasn't be changed.
 
He's using an 18F device, Bob (note the "lfsr" instructions). Most common special function registers are accessed via the "access bank"... no bank switching necessary...
 
I have found another way of dealing with this issue. I am now sending the names to the LCD and at the same time sending what is written to the LCD in a location on the PIC. If anyone does know how too read data on the LCD please let me know as it may help future endeavors. Thank you all for the assistance it was much appreciated.
 
You read it exactly how you write it but you set the R/W line high.

Mike.
 
Hey Mike (Pommie), could I impose, please?

I've never tried to read from DDRAM on an LCD. At what point when you pulse the LCD 'E' line does the LCD put data at the current DDRAM address onto the LCD data lines? Is it when 'E' goes high or when 'E' goes low?

TIA... Regards, Mike
 
Sirs,
When I attempted to read the LCD, I set the DDRAM address to 0X00(First letter for the name), set RS and RW high, changed PORTC to INPUT, then toggled EN, I moved PORTC to WReg but the only thing that happened was the curser moved to the next space. This tells me it did the read operation but did not make it to the WReg. Im not sure what I need to do.
When reviewing the data sheet with RS and RW high it will read but the sheet says internal operation...with internal operation being said i dont know if we can extract that info.( When checking the busy flag you only set RW high, you can check the busy flag and read the address counter, but the counter will only let you the location not what is displayed at that location.)--my assumption--The data sheet does not say internal operation for the busy flag/address counter read..

Zach
 
Here is what I do to read the BF, which involves reading the whole port:
Code:
WNB                           ;WaitNotBusy -- working
     bcf       STATUS,0       ;set up Carry bit as RS flag
     btfsc     RS
     bsf       STATUS,0

;actual segment you need begins here:
     banksel   TRISC          ;                                                 |B1
     movlw     0x0F           ;BF requires reading the whole port               |B1
     movwf     TRISC          ;PORTC bits<0:3>set as inputs                     |B1
     banksel   PORTC          ;                                                 |B0
     bcf       RS             ;read BF Cmd
     bsf       RW        
Busy
     bsf       E          
     bcf       E
     movf      PORTC,w        ;high nibble from LCD is in low nibble of port
                              ;deleted (movwf temp)NB: DB7 is in temp,3 or WREG,3
     bsf       E              ;have to read twice, second nibble ignored
     bcf       E              ;required 2nd read, do notneed to move it
     btfsc     WREG,3         ;temp,3 if not modified per above
     goto      Busy           ;busy, test again
     bcf       RW             ;BF is clear, reconstruct TRISB, RS, and return
;end of segment of interest

     banksel   TRISC          ;                                                 |B1
     clrf      TRISC          ;                                                 |B1
     banksel   PORTA          ;                                                 |B0
     bcf       RS
     btfsc     STATUS,0
     bsf       RS
     return
NOTE: RS is low, as a read is an instruction. My processor (16F1518) is only an enhanced mid-range, so I do need to handle Banks. Oscillator was internal at 8 MHz, so no delay is needed in toggling E. Also, it is for 4-bit mode.

EDIT: I was too targeted on reading the BF and address. For data alone, RS is high.

John
 
Last edited:
While spending a few hours on the highway this morning, it occurred to me that we have not asked, nor have you (OP) said what you expect the read value to mean. Except for reading the busy flag, there seems to be relatively little real experience reading a character LCD on this forum.

When I was working with a graphical LCD (GLCD) in 8-bit parallel mode, I did read back bytes from the LCD using routines provided by Pommie. What you get are the 8 pixels that make up one row/column of a character. As an example, if the character is 5X7, you would end up reading each of the 5 bytes for that character. One does not read what the ASCII equivalent for those 5 bytes is. If your intent is to read the ASCII value, then you will need some sort of pattern recognition algorithm. I am not sure the LCD character display works the same way.

Check pages 18-20 of the datasheet:
upload_2015-12-4_17-23-44.png


But, I did a little playing this afternoon with reading CGRAM using hardware simulation with an ICD3 and got results that were consistent with the hypothesis that you will not return an ASCII hex code, but rather the hex equivalent of the patterns shown in the snipping above. In other words, it seems to act like the GLCD. Those results are very preliminary.

Regards, John
 
Since CGRAM contains pixel data, that makes sense. However, DDRAM contains ASCII character data and so that's what you should be able to read...
 
GOT IT:
NB: This is hardware simulation in 4-bit mode. No attempt was made to create a useful routine. Processor = 16F1518 @ 8 MHz, internal oscillator

Here is the Watch window from reading the second character, "e" (location 0x81) in Hello World. The ASCII value of "e" (ox65) is in the Temp register:

Read e Capture.PNG

And here is the code:
Code:
ReadLCD                       ;based on WNB 12.04.15
     clrf      temp
     movlw     0x81    
;set LCD address of character to read, NB:cursor auto advances
    call      PutCmd
;     banksel   LATC           ;                                                |B2
;     clrf      LATC           ;                                                |B2
     clrf      PORTC
     banksel   TRISC          ;                                                 |B1
     movlw     0x0F           ;set lower nibble PORTC to input                  |B1
     movwf     TRISC          ;                                                 |B1
     banksel   PORTC          ;                                                 |B0
     bsf       RS             ;set to read data
     bsf       RW             ;set to read data

     bsf       E              ;toggle E
     bcf       E
     movf      PORTC,w        ;high nibble from LCD is in low nibble of port
     swapf     WREG,f
     movwf     temp           ;move high bits from LCD to high bits of register                
 
     bsf       E              ;have to read twice in 4-bit mode
     bcf       E              ;
     movf      PORTC,w
     andlw     0x0F           ;masks upper nibble of PORTC, may not be necessary
                              ;unless those pins are used for something
     iorwf     temp,f         ;put lower nibble in temp bits<3:0>
     nop
     bcf       RW             ;BF is clear, reconstruct TRISB, RS, and return
     banksel   TRISC          ;                                                 |B1
     clrf      TRISC          ;                                                 |B1
     banksel   PORTA          ;                                                 |B0
     return
Here is the main part of the code showing how I scrolled through the individual letters/positions:

Code:
     movlw     'H'
     call      PutDat
;     call      ReadLCD
;     nop
    movlw     'e'
    call      PutDat
     call      ReadLCD
     nop

Although the example here doesn't show it, you can print the entire "Hello", then go back and read position 0x80 ("H"). Have fun.

John
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top