Over the winter break of 2020-2021, I did a project where I implemented an interface between 89C51 and the LCD module DMC-20481NY. The C and assembly code were written in MIDE-51. I sent ASCII from 89C51 to the LCD controller and the characters are displayed on the LCD display.
In C language, I created a new putchar() and made the printf() work with the control ASCII \n and \r in the LCD module.
Wire Wrap and Tool
74LS08 and 74LS02
LCD Module
DMC-20481NY
5V Power Supply
89C51 boot51 system (Created in previous project)
POT 10K ohm (VR)
The interface is a logic circuit that converts 89C51 write/read timing of WR, RD, and the address decoder output to the timing that the LCD required. The LCD interface, DMC 20481NY, is depicted above. The map of the LCD register into 89C51 memory location is shown in the table below.
The diagrams below were drawn by yours truly. They helped a lot with the wiring process. The first diagram is the IF diagram while the second one is a zoomed-out system diagram.
org 0000
start: Mov A,#30H
lcall sendCmd
Mov A,#0EH
lcall sendCmd
Mov A,#06H
lcall sendCmd
lcall clrScreen
mov dptr,#h2
lcall puts
sjmp $
delay: mov r7,#10h ; speed of LCD display
dll: mov r6,#0
djnz r6,$
djnz r7,dll
ret
sendCmd:
mov dptr,#cmdWr
movx @dptr,A
lcall delay
ret
putchar: mov dptr,#datWr ;LCD data register address is loaded to dptr
movx @dptr, a ;send the letter to LCD data register
lcall delay ;wait for busy =0,
ret
puts:
loop3: movx a,@dptr
jz return1
inc dptr
mov r1,dpl
mov r2, dph
lcall putchar
mov dpl,r1
mov dph, r2
sjmp loop3
return1: ret
clrScreen: mov a,#01h ;clear screen
lcall sendCmd
ret
org 1000h
buf: db "LCD test Code" ; what LCD will display.
count: db 13 ; number of letters from buf "LCD test Code"
hl: db 17
h2: db "LCD_test ASM V1.0",00h
cmdWr equ 8000h
datWr equ 8002H
end
// Compile this code with SDCC 4.0
#include <8052.h>
#include <stdio.h>
static __xdata unsigned char *cmdWr;
static __xdata unsigned char *datWr;
void delay(void)
{ int i;
for (i=0;i<500;i++)
{}
}
void InitSerialPort(void)
{
SCON = 0x50; /* SCON: mode 1, 8-bit UART, enable rcvr */
TMOD |= 0x20; /* TMOD: timer 1, mode 2, 8-bit reload */
TH1 = 0xf3; /*TH1=0xf3; reload value for 2400 baud @ 12MHz*/
PCON=0x80; /* Smod1=1 related to 4800, 12MMHz*/
TR1 = 1; /* TR1: timer 1 start to run */
TI = 1; /* TI: set TI to send first char of UART */
}
int getchar()
{ while (!RI); /* assumes UART is initialized */
RI = 0;
return SBUF;
}
int putchar (int c)
{
*datWr=(char)c;
delay();
while (!TI); /* assumes UART is initialized */
TI = 0;
SBUF = c;
return c;
}
void gets(char *str)
{ while(1)
{ *str=(char)getchar();
if ((*str=='\n')||(*str=='\r')) break;
putchar(*str);
str++;
}
}
void LCDinit(void)
{ cmdWr= (__xdata unsigned char *)0x8000;
datWr= (__xdata unsigned char *)0x8002;
*cmdWr=0x01; //clear screen
delay();
*cmdWr=0x30;
delay();
*cmdWr=0x0e;
delay();
*cmdWr=0x06;
delay();
}
void main(void)
{
InitSerialPort();
LCDinit();
printf_tiny("LCD_test with C V1.0");
while (1)
{
}
}
In summation, I wrote and tested an LCD code in both ASM and C language. I used DMC20481NY LCD for the project. I tested these two codes multiple times and troubleshooted (trouble-shot?) all the errors. The entire project took me like 23 hours to complete, which is like a full day of nonstop work.