Vývody D0..D7 LCD displeje jsou propojeny s datovou sběrnicí D0..D7 mikroprocesoru. K adrese A0 je připojen RS a k adrese A1 R/W displeje. "Enable" pulz
je generován přídavnou logikou, která v tomto případě úplně
dekóduje adresy 0xFF00..0xFF03 a umožňuje čtení i zápis. Registry LCD displeje jsou potom přístupné na následujících adresách:
0xFF00 for - zápis do controlního registru
0xFF01 for - zápis do datového registru
0xFF02 for - čtení kontrolního registru
0xFF03 for - čtení datového registru
Program je odladěn v C51-Keil. Je třeba si uvědomit, že v některých případech délka pulzu "E" nemusí vyhovovat použitému LCD displeji - je úměrná hodinové frekvenci mikroprocesoru.
//////////////////////////////////////////////////////////////////////
// LCD INTERFACE TO EXTERNAL MEMORY
/////////////////////////////////////////////////////////////////////
#define BLINK_OFF_CURSOR_OFF 0x0C
#define BLINK_ON_CURSOR_OFF 0x0D
#define BLINK_OFF_CURSOR_ON 0x0E
#define BLINK_ON_CURSOR_ON 0x0F
#define CLEAR 0x01
#define HOME 0x02
#define LINE_1 0x80
#define LINE_2 0xC0
#define LINE_3 0x94
#define LINE_4 0xD4
#define LCD_OFF 0x08
xdata char wrctl_lcd _at_ 0xFF00; // RS_LCD = 0, RW_LCD = 0
xdata char wrdata_lcd _at_ 0xFF01; // RS_LCD = 1, RW_LCD = 0
xdata char rdctl_lcd _at_ 0xFF02; // RS_LCD = 0, RW_LCD = 1
xdata char rddata_lcd _at_ 0xFF03; // RS_LCD = 1, RW_LCD = 1
void delay(unsigned int dly){
int d;
for(d=0;d!=dly;d++);
}
char busy_lcd(){ // busy flag is D7, must be masked with 0x80
return(rdctl_lcd & 0x80);
}
void init_lcd(){
wrctl_lcd = 0x30; // write control for the firt time on power up
delay(5000); // execute delay 4.1 ms or more,
// because busy flag can not read
wrctl_lcd = 0x30; // same before, the second
delay(5000);
wrctl_lcd = 0x30; // one more time, without delay
delay(5000);
wrctl_lcd = 0x38; // function set to 8bit length interface
while(busy_lcd()); // now, busy flag can read for cek busy lcd
// set blink on and cursor off, please change if you don't like it
wrctl_lcd = BLINK_ON_CURSOR_OFF;
while(busy_lcd()); // now, busy flag can read for check busy lcd
wrctl_lcd = CLEAR; // clear lcd
while(busy_lcd()); // now, busy flag can read for check busy lcd
}
void locate_lcd(char row, char col){
char d;
// locate cursor to row,col for write read char in lcd
// row and char start at 0, for example locate_lcd(0,0) is row 1 and col 1
switch(row){
case 0: d = LINE_1; // set to DD_RAM start address for line_1
break;
case 1: d = LINE_2; // set to DD_RAM start address for line_2
break;
case 2: d = LINE_3; // set to DD_RAM start address for line_3
break;
case 3: d = LINE_4; // set to DD_RAM start address for line_4
break;
}
wrctl_lcd=(d += col);
while(busy_lcd());
}
void wrstr_lcd(char *ptrbuff){
char d;
// this routine send string in idata, data, pdata, cdata or cdata ending by NULL
// the address is generic pointer *ptrbuff
// this pointer aotumatically contain pointer for memory type that you pass to
// this routine
while((d=*ptrbuff++) != 0){
wrdata_lcd = d; while(busy_lcd());
}
}
char code msgcode_lcd[] = "This STRING-CODE";
char xdata msgxdata_lcd[] = "This STRING-XDATA";
char idata msgidata_lcd[] = "This STRING-IDATA";
void test_lcd(){
locate_lcd(0,0); // testing to write string-code to lcd (0,0)
wrstr_lcd(&msgcode_lcd[0]);
locate_lcd(1,0); // testing to write string-code to lcd (1,0)
wrstr_lcd(&msgcode_lcd[0]);
delay(50000); // delay
wrctl_lcd = CLEAR; // now clear display
while(busy_lcd());
locate_lcd(0,0); // testing to write string-code to lcd (0,0)
wrstr_lcd(&msgidata_lcd[0]);
locate_lcd(1,0); // testing to write string-code to lcd (1,0)
wrstr_lcd(&msgidata_lcd[0]);
delay(50000); // delay
wrctl_lcd = CLEAR; // now clear display
while(busy_lcd());
locate_lcd(0,0); // testing to write string-code to lcd (0,0)
wrstr_lcd(&msgxdata_lcd[0]);
locate_lcd(1,0); // testing to write string-code to lcd (1,0)
wrstr_lcd(&msgxdata_lcd[0]);
delay(50000); // delay
}
main(){
init_lcd();
while(1) {test_lcd()};
}