I recently purchased a 20x4 backlit LCD from a surplus shop. It seems to be in good working order, however, I am having difficulty getting the last character in the 3rd and 4th lines to display properly.
The controller is a legit HD44780A00, and there are four HD44100H ICs on it as well. Unfortunately I don't know the manufacturer of the module, but it has "V0020240 Rev. B" silkscreened on the back.
I'm using the 8-bit interfacing method, connecting the display to the dedicated LCD port on my brand-new Rev.5 8051 devkit from pjrc.com. I took the website-provided 2x15 display code and modified it to output a single character to a specific LCD address, allowing me to randomly step through memory to try and determine the memory map for the device.
Rows 1 and 2 work as expected:
Row 1: 01h - 14h (20 chars) Row 2: 41h - 54h (20 chars)
Rows 3 and 4 are problematic:
Row 3: 15h - 27h (19 chars) - 28h does not work Row 4: 55h - 67h (19 chars) - 68h does not work.
Oddly, 40h or 28h puts a character at the end of the 4th row, and I need to use 6Ah to get something at the end of the 3rd row.
Could this be an oddball hardware problem, or am I missing something?
Here's the code, if that may help:
.equ locat, 0xF300 ;Location for this program .equ lcd_command_wr, 0xFE00 .equ lcd_status_rd, 0xFE01 .equ lcd_data_wr, 0xFE02 .equ lcd_data_rd, 0xFE03 .equ esc, 0x003E ;paulmon2's check for esc key
.org locat .db 0xA5,0xE5,0xE0,0xA5 ;signiture bytes .db 35,255,0,0 ;id (35=prog) .db 0,0,0,0 ;prompt code vector .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;reserved .db 0,0,0,0 ;user defined .db 255,255,255,255 ;length and checksum (255=unused) .db "4x20 LCD Test",0 ;max 31 characters, plus the zero .org locat+64 ;executable code begins here
startup:
.equ cout, 0x0030 ; cout: print byte in accumulator to serial port .equ cin, 0x0032 ; cin: get a character from the serial port (blocking) .equ phex, 0x0034 ; phex: print accumulator value as 2-digit hex .equ phex16, 0x0036 ; phex16: print DPTR value as
4-digit hex .equ pstr, 0x0038 ; pstr: print string pointed to by DPTR .equ newline, 0x0048 ; newline: send cr+lf to serial port .equ ghex, 0x003A ; ghex: read ascii, store in acc. as hex.equ lcd_clear_cmd, 0x01 ;clears display .equ lcd_home_cmd, 0x02 ;put cursor at home position .equ lcd_on_cmd, 0x0C ;turn on display (cursor off) .equ lcd_left_move_cmd, 0x10 .equ lcd_right_move_cmd, 0x14 .equ lcd_left_shift_cmd, 0x18 .equ lcd_right_shift_cmd, 0x1C .equ lcd_config_cmd, 0x38 ;configure, 8 bit interface, 2 lines, 5x7 digits
main_loop:
lcd_init: lcall lcd_busy mov dptr, #lcd_command_wr mov a, #lcd_config_cmd movx @dptr, a
lcall lcd_busy mov dptr, #lcd_command_wr mov a, #lcd_clear_cmd movx @dptr, a
lcall lcd_busy mov dptr, #lcd_command_wr mov a, #lcd_on_cmd movx @dptr, a
lcall lcd_busy mov dptr, #lcd_command_wr mov a, #lcd_left_shift_cmd movx @dptr, a
lcall lcd_busy mov dptr, #lcd_command_wr mov a, #0x81 movx @dptr, a
begin: mov dptr, #mesg_start lcall pstr
getaddr: lcall ghex lcall newline jc quit
setaddr: orl a, #0x80 ; msb set for set DD RAM address mov dptr, #lcd_command_wr ; set LCD write port movx @dptr, a ; and output character to LCD sendstr: mov dptr, #mesg1 acall lcd_pstr
quit: ljmp 0
; mesg_start: data sent to serial port at program initialization
mesg_start: .db "Enter screen address to try: ",0
; mesg1 : data sent to LCD during main loop
mesg1: .db "+",0
lcd_pstr: clr a movc a, @a+dptr inc dptr jz lcd_pstr_end push dpl push dph acall lcd_cout pop dph pop dpl sjmp lcd_pstr lcd_pstr_end: ret
lcd_cout: push acc acall lcd_busy mov dptr, #lcd_data_wr pop acc movx @dptr, a ret
lcd_busy: mov dptr, #lcd_status_rd movx a, @dptr jb acc.7, lcd_busy ret