Introduction.
This describes how an Optrex LCD Display may be interfaced with a PC printer port using the 4-bit transfer mode. Typical displays include:
Optrex DMC 20261, 2 line by 20 character Optrex DMC 40218, 2 line by 40 character
Both are readily available from BG Micro, PO Box 280298, Dallas, TX, 75228, e-mail bgmicro@ix.netcom.com for less than $10.00. Although a data sheet is provided, it leaves a great deal to be desired.
The above LCD displays use an on-board HD44780 micro-controller and although this discussion deals specifically with the above two Optrex displays, it is probably applicable to all such LCD panels.
The question may arise, why, with a full monitor on a PC, would anyone want to interface an LCD panel having only the capability of displaying 40 or 80 characters.
A PC may well be used in an embedded application where the environment is such that a monitor is unnecessary and just too large. A small LCD panel may be adequate. However, in most cases, such an LCD panel would be interfaced with such processors as the BASIC Stamp or 68HC11. The PC parallel port provides a very simple environment for testing and debugging. Once, all of the anomalies of the LCD panel are understood, it then becomes a simple matter to modify the code so as to interface with another pro cessor.
The interface between the parallel port and the LCD is shown in Figure #1. Note that six output bits on the Data Port are used. The lower four bits are used for data. Output Data_6 is used to control the register select input to the LCD and Data_7 is used to clock the data transfer. In our application LCD input R/W is tied to ground as we only wrote to the LCD panel. The "read" feature was not used.
Printer Optrex LCD Port Data 7, Term 9 <------------- EN, Term 6 Data 6, Term 8 <------------- RS, Term 4 Data 5, Term 7 <-- No Connect Data 4, Term 6 <-- No Connect GRD ---- R/W, Term 5 Data 3, Term 5 <------------- DB7, Term 14 Data 2, Term 4 <------------- DB6, Term 13 Data 1, Term 3 <------------- DB5, Term 12 Data 0, Term 2 <------------- DB4, Term 11 GND Term 18 <------------ GND, Term 1 +5--- Vcc, Term 2 See Note 2 ---------- Vee, Term 3 Note 1. LCD inputs DB0 - DB3 are not connected. Note 2. A 10K pot is connected between +5 and GND. The wiper is connected to Vee (term 3 on the LCD). Note that the terminal assignments on the LCD panel are somewhat non standard: 2 4 6 8 10 12 14 * * * * * * * * * * * * * * 1 3 5 7 9 11 13 Figure #1. Interface Between Printer Port and LCD Panel
General Overview.
Transfers to the LCD panel consist of instructions (RS input at logic zero) and data (RS input at logic one). Typical instructions are setting the cursor position, setting the cursor display mode and clearing the display. A data transfer is the actual d ata to be displayed on the panel.
On outputting any instruction or data to the LCD, the RS input and the four data leads are first set up with the Enable lead at logic zero. The transfer occurs on bringing the Enable lead high.
On power-up, a specific initialization procedure must be followed. LCD input RS is set to logic zero to indicate the "instruction mode". The instruction 0x3 is set on the four data bits and this instruction is sent three times. The instruction 0x2 is t hen sent to place the LCD module in the 4-bit mode.
After that time, all instructions and all data consists of eight bits. However, this is a two step process. The high nybble is first transferred, and then the low nybble.
Instructions.
Instructions are summarized below;
#1. Clear Display 0000 0 0 0 1 This clears to display memory by setting the content at all locations to 0x00 and sets the cursor address to zero (beginning of the first line). #2. Cursor Home 0000 0 0 1 * * is don't care. This is similar to command #1 except the display memory is not changed. The cursor is set to address 0x00. #3. Entry Mode 0000 0 1 I/D S I/D set cursor to either increment (1) or decrement (0). S specifies whether to shift the display (1) or not (0). Once set, the entry mode may not be changed without first resetting the LCD. #4. Display 0000 1 D C B ON/OFF Control D - display on (1), off (0). C - cursor on (1), off (0). B - blink on (1), off (0). #5. Cursor/ 0001 S/C R/L * * Display Shift S/C Display shift (1), Cursor shift (0). R/L Right (1), Left (0). * is don't care. #6. Function Set 001 DL N F * * DL Data Length. 8-bit (1), 4-bit (0). N Number of Lines 2-lines (1), 1 line (0). F Font. 5X11 dots (1), 5X8 dots (0). #7. Display Data Address Set. 1 A6 A5 A4 A3 A2 A1 A0 Note that the display memory consists of 128 address locations in the range of 0x00 - 0x7f. Only 2 X 20 = 40 or 2 X 40 = 80, depending on the model may be displayed at any one time. Normally, either command #1 or command #2 is used to set the address to zero, and as each character is transferred to the LCD, the address counter is incremented. However, by using command #7, the address counter may be set to any value in the range of 0x00 to 0x7f. This is particularly useful in selecting between the two lines. The first character on the first line is at address 0x00 and the first character on the second line is at 0x40. Thus, to select the beginning of the first line, the instruction is 0x80 (100 0 0000), and to select the beginning of the second line 0xc0 (1100 0000).
Program LCD_1.C
In program LCD_1.C the LCD is initialized by sending the sequence 0x3, 0x3, 0x3 and finally 0x2 to set the display in the 4-bit mode. After that time, all instructions consist of eight bits.
The entry mode is set to 4-bit data length, 2 lines, 5X11 font. The routine shows how to turn the display off, to clear the display and bring the cursor to the home position. The cursor control is set to increment (go to the right) with each character an d the display is not to shift. Finally, the display is turned on, the cursor is turned on and placed in a blinking mode.
/* ** LCD_1.C ** ** Illustrates how to initialize LCD ** ** Christine M. Samuels, Morgan State University, July 2, '96 */ #include <stdio.h> #include <dos.h> #define DATA 0x03bc #define STATUS DATA+1 #define CONTROL DATA+2 void clock(int x); void out(int x); void init(void); void main() { init(); } void clock(int x) {/* brings EN lead high and then low */ delay(25); outportb(DATA,x|0x80); delay(25); outportb(DATA,x); } void out(int x) { x = x & 0x4f; /* only RS and the 4 data bits */ clock(x); } void init(void) { int y; /*after power on*/ for(y=0; y<3; y++) { out(0x03); /* send 0x3 three times */ delay(20); } out(0x02); /* 4 bit operation */ /***********/ out(0x02); /* high nybble */ out(0x0c); /* then low nibble */ /* Sets the font and number lines to be displayed ** See instruction #6 above. ** Instruction 0x2c 0010 1 1 0 0 ** ^ 4-bit ^ 2 lines ^ font 5X11 */ /***********/ /***********/ out(0x00); out(0x08); /* Display off, cursor off, blink off. ** See instruction #4 above. ** Instruction 0x08 0000 1 0 0 0 ** ^ display ^ cursor ^ blink ** off off off */ /***********/ /***********/ out(0x00); out(0x01); /* Clear screen. Cursor to home position. ** See instruction #1 above. */ /***********/ /***********/ out(0x00); out(0x06); /* Increment cursor to right when writing. ** See instruction #2 above. ** Instruction 0x06 0000 01 1 0 ** ^ increment ^ don't shift ** cursor display */ /***********/ /***********/ out(0x00); out(0x0f); /* Display on, cursor on and blinking. ** See instruction #4 above. ** Instruction 0x0f 0000 1 1 1 1 ** ^ display ^ cursor ^ blink ** on on on */ /***********/ }Data Transfers.
Program LCD_2.C illustrates a number of features associated with the LCD panel.
Recall that in transferring instructions, that the register select (RS) input to the LCD panel is at logic zero. Data transfers are identified with setting the RS input to logic one. Aside from this, the process is the same; the high nybble is first tr ansferred and then the low nybble. This is performed in function "out_char(char c)".
Note. A variant of this program was tested and worked as described. However, over the past several months we have revised the code many times and did not test this final version as the fixture was no longer available. Please call any errors to my attention.
/* Program LCD_2.C ** ** Illustrates how to output a character and string to LCD panel. ** Demonstrates various features including scrolling and blinking. ** Illustrates how to display variables. ** ** Christine Samuels, Peter H. Anderson, MSU, Sept 22, '96 */ #include <stdio.h> #include <dos.h> #include <string.h> #include <conio.h> #include <math.h> #define DATA 0x03bc #define STATUS DATA+1 #define CONTROL DATA+2 #define RS 0x40 #define PI 3.14159 void out_string(char str[]); void out_char(char c); void out(int x); void initialization(void); void clock(int x); void main(void) { int h; char c; char s_1[] = {"Initialization Completed!"}; char s_2[] = {"My name is Optrex. I am a LCD."}; char s_3[] = {"Please input a character:"}; char s_4[] = {"That's all folks!"}; char s_5[] = {"Bye from Morgan State University!"}; char str[80]; float x, y, z; initialization(); out_string(s_1); delay(2000); out(0x00); /* clear display */ out(0x01); /*asks user to input a character and output it on the LCD*/ out_string(s_3); /* prompt the user on the LCD */ while (!kbhit()) /*loop until a key is hit*/ out(0x00); /* clear the display */ out(0x01); c = getch(); /* get the character and display on LCD */ out_char(c); sleep(5); /* pause to admire */ /*output a string on the LCD*/ out(0x00); /* clear display */ out(0x01); out(0x00); /* display on and blinking */ out(0x0f); out_string(s_2); /*scroll screen to the right and left*/ for(h=0; h<80; h++) { out(0x01); out(0x0c); } delay(1000); /* now the other way */ for(h=0; h<80; h++) { out(0x01); out(0x08); } sleep(5); /*show features such as cursor on/off, blink on/off, show special characters*/ out(0x00); /* clear display */ out(0x01); out(0x00); /* show blink ON and OFF */ out(0x0f); sleep(5); out(0x00); out(0x0e); sleep(5); out(0x00); out(0x0f); sleep(5); /*show cursor on/off feature*/ out(0x00); out(0x0c); sleep(5); out(0x00); out(0x0e); sleep(5); /* show how to display variables */ x = 30.0; /* 30 degrees */ y = cos(x*PI/180.0); /* cos and sin of the angle */ z = sin(x*PI/180.0); /* make the string and output to LCD */ sprintf(str, "Angle = %.3f, cos = %.3f, sin = %.3f.", x, y, z); out_string(str); sleep(5); out(0x00); /* clear display */ out(0x01); /*goodbye*/ out_string(s_4); out(0x0c); /* set cursor to beginning of the second line */ out(0x00); out_string(s_5); } void out_string(char str[]) { int s,t; t = strlen(str); for(s=0; s<t; s++) { out_char(str[s]); } } void out_char(char c) { out(((c>>4) & 0x0f) | RS); /* hi nybble */ out((c & 0x0f) | RS); /* low nibble */ } void out(int x) { x = x & 0x4f; clock(x); } void initialization(void) { int y; /*power on*/ for(y=0; y<3; y++) { out(0x03); delay(20); } /*4-bit operation */ out(0x02); out(0x02); out(0x0c); /*display off, cursor off, blink off*/ out(0x00); out(0x08); /*clear screen*/ out(0x00); out(0x01); /*increment cursor to right when writing*/ out(0x00); out(0x06); /*cursor on and blinking*/ out(0x00); out(0x0f); } void clock(int x) { delay(25); outportb(DATA,x|0x80); delay(25); outportb(DATA,x); }