Click here to Skip to main content
12,886,892 members (35,455 online)
Click here to Skip to main content
Add your own
alternative version


594 bookmarked
Posted 28 Sep 2003

I/O Ports Uncensored Part 2 - Controlling LCDs (Liquid Crystal Displays) and VFDs (Vacuum Fluorescent Displays) with Parallel Port

, 28 Sep 2003
Rate this:
Please Sign up or sign in to vote.
Controlling LCDs (Liquid Crystal Displays) and VFDs (Vacuum Fluorescent Displays) with Parallel Port

Click for bigger picture

Before You Start

If you want to understand the logic of these I/O ports and want to make a quick start to LCD you have to check out my first article. If you don't need the logic and only need a quick live work, do the circuit in part 2 and download my program to make LCD live.

Part 1 - What is an LCD and what is it for?

Don't be afraid, I won't give a history lesson like every other article out there does but I want to say why we are using all these LCDs from the time when it was first invented. At first we used LEDs and then 7SDs appeared now we are using LCDs because of their capability of showing not only numbers also showing letters and all kind of symbols. I used a character based LCD see it's datasheet here. It has a HD44780(Hitachi) compatible KS0066U controller. Samsung made this controller and if you are interested in the electronic stuff, you can download the controller info from here These controllers are not much complicated like today's graphic LCDs' (Palms, New Generation Digital Cameras, Nokia and other cell phones) controllers but they have been used in commercial and industrial products around the world. Because of their basic interface they can talk to the old Z80, 6502 and/or the PIC microcontrollers which are considered as one of the most popular microcontrollers by the hobbyists. You can find additional info on microcontrollers at

Let me explain what VFDs are: VFDs (Vacuum Fluorescent Displays) are also like LCDs. These are commonly used in microwaves and some pocket calculators. See a sample picture of a VFD here. The key is controllers so there are HD44780 compliant VFDs around. I like VFDs more than LCDs because they are brighter than LCDs but they are also more expensive than LCDs so I used an LCD in my article.

What are the shapes of these LCDs? I used a 2x16 (2 row(line) x 16 column) LCD in my article as you can see in the above picture. There are lots of LCD types such as 1x8, 2x8, 1x16, 1x20, 2x20, 2x20, 2x10, 1x40 and there are also many different vendors. And if there are more than 80 characters, mostly they use 2 controllers on the LCD (Mine has one - This is important). I don't give any lcd structure information due to codeproject's concept if somebody wants to learn about how these LCD structures are check these two urls:
  1. Samsung's LCD structure and type article
  2. Sharp's The Principles of LCD Technology article

Part 2 - LCD Connections, Pinout Descriptions and Circuit

LCD Connections

Mostly an LCD has a 14 pin connection which are D0-D7 (Data Bits), E (Enable), R/W (Read/Write), RS (Register Select), Vee or Vo (Contrast), Vdd or Vcc (+5V supply), Vss (Ground/Earth connection) so there are 8 data, 3 power and 3 control lines for a standard non-backlight LCD. If an LCD has a backlight it has additional two lines for that which are 15th (VB+) and 16th(VB- or Ground) lines. Below there is a table of the pin matches and pictures of my LCD's backsides:

Standard LCD Pin Matches (Character number <80)

Pin Symbol/Alternate SymbolPossibilityFunction
1Vss-Power supply (GND)
2Vdd/Vcc-Power supply (+5V)
3Vee/Vo-Contrast adjust
4RS0/10 = Instruction input / 1 = Data input
5R/W0/10 = Write to LCD module / 1 = Read from LCD module
6E1, 1-->0Enable signal
7DB00/1Data pin 0
8DB10/1Data pin 1
9DB20/1Data pin 2
10DB30/1Data pin 3
11DB40/1Data pin 4
12DB50/1Data pin 5
13DB60/1Data pin 6
14DB70/1Data pin 7

If your LCD has more than 80 characters (like 4x40)

15E21, 1->0Enable signal row 2 & 3
16  Not used mostly

HY1602B (Hyper 1602B) with KS0065 controller (compatible with HD44780) and backlight. Click for a bigger picture
Click for bigger picture
1602-04 with KS0066U controller (compatible with HD44780) and backlight Click for a bigger picture
Click for bigger picture
These are 2 different 2x16 LCDs as in the pictures the 15th and 16th pins are for backlight as I mentioned above.

Pinout Descriptions

Pin 1,2,3

According to the table, I call Pin 1(Vss),2(Vdd/Vcc),3(Vee/Vo) power pins because they are the gates to power. Pin 1 is for ground so you have to connect to ground/earth and Pin 2 is for the +5V power supply. 6V or 4,5V is mostly acceptable in few amperes and also 3V is acceptable on some of the LCD modules (You can also power these modules with a battery in a very economical way). In my application I get the voltage from the molex cable of the pc which is inside the case. And pin 3 is for the LCD's contrast adjustment. I did not but you could use a potentiometer(10K pot will be ok) for changing the contrast of your LCD. See the schematics below

Pin 4,5,6

I call Pin4(RS),5(R/W),6(E) the control buddies because these pins are the arms of your controller inside your LCD module. Pin 4(RS) is registration select if this pin is low the data perceived by the data pins taken as commands by the LCD and if this pin is high the LCD can receive/send 8 or 4 bit character data. I call Pin 5(R/W) clerk because when this pin is low you can write character to the LCD, if the pin is high you can read character data or the status information from the LCD. I didn't make any read operations in my app so I solder this pin to the ground (with soldering this to the ground I made this pin low - "0" see the below circuits). Pin 6(E) which I call the guardian, is used to initiate the actual transfer of commands or character data between the LCD module and the data pins.

Pin 7,8,9,10,11,12,13,14

The eight pins which are DB0-DB7 are the data pins which I call them the workers. The data can be transferred or fetched from the LCD by 8 or 4 bits. Which one is better? This is up to you, by the way if you are using a microcontroller and you have few pins you can use your module in 4 bit mode(by using DB4-DB7). I used 8 bit mode in my LCD because I used the parallel port which already have 8 bit data lines (remember my first article, part 1 D0-D7)

Pin 15,16

These two pins are for the backlight of the LCD module. 15th pin goes to the power supply(VB+) and 16th pin goes to the ground(VB-). Backlight is very useful in dim environments but some LCD modules don't have backlights. There are multicolored LCDs around as well.


What we need to supply for our circuit? Below is a list of that:


2x16 Paralell LCD must be HD44780 compatiable

2. Normal parallel printer cable
3.Normal twin power cable
4.10 way housing and the PCB header
5.6 way housing and the PCB header
6.Hard drive type power connector (Molex)
7.16 PCB terminals
8.A digital multimeter(must measure few ampers!), a solder pen with some soldering iron
9.Some patience, and my program :)
*10 K potentiometer (Not required - needed when you want to adjust the contrast of your LCD - see circuit with potentiometer)

Make the circuit as its shown in the pictures below.

The circuit with potentiometer


The circuit without potentiometer

If your soldering goes well you get a typical test screen of a character based LCD as its shown below:

Part 3 - Before Coding

Before coding you have to know some of the basic instructions of a HD44780 controller. Below is a table from the Hitachi's old web site which explains the instructions for HD44780 compatible LCD. Note: I add some extra info for easy understanding.

InstructionCodeDescriptionExecution time**
Clear display0000000001Clears display and returns cursor to the home position (address 0).1.64mS
Cursor home000000001*Returns cursor to home position (address 0). Also returns display being shifted to the original position. DDRAM contents remains unchanged.1.64mS
Entry mode set00000001I/DSSets cursor move direction (I/D), specifies to shift the display (S). These operations are performed during data read/write. I/D = 0 --> cursor is in decrement position. I/D = 1 --> cursor is in increment position. S = 0 --> Shift is invisible. S = 1 --> Shift is visible40uS
Display On/Off control0000001DCBSets On/Off of all display (D), cursor On/Off (C) and blink of cursor position character (B). D = 0 --> Display off. D = 1 --> Displan on. C = 0 --> Cursor off. C = 1 --> Cursor on. B = 0 --> Cursor blink off. B = 1 --> Cursor blink on. 40uS
Cursor/display shift000001S/CR/L**Sets cursor-move or display-shift (S/C), shift direction (R/L). DDRAM contents remains unchanged. S/C = 0 --> Move cursor. S/C = 1 --> Shift display. R/L = 0 --> Shift left. R/L = 1 --> Shift right40uS
Function set00001DLNF**Sets interface data length (DL), number of display line (N) and character font(F). DL = 0 --> 4 bit interface. DL = 1 --> 8 bit interface. N = 0 --> 1/8 or 1/11 Duty (1 line). N = 1 --> 1/16 Duty (2 lines). F = 0 --> 5x7 dots. F = 1 --> 5x10 dots. 40uS
Set CGRAM address0001CGRAM addressSets the CGRAM address. CGRAM data is sent and received after this setting.40uS
Set DDRAM address001DDRAM addressSets the DDRAM address. DDRAM data is sent and received after this setting.40uS
Read busy-flag and address counter01BFCGRAM / DDRAM addressReads Busy-flag (BF) indicating internal operation is being performed and reads CGRAM or DDRAM address counter contents (depending on previous instruction). I used some delay functions in my code which are ThreadSleep if you don't want to use these you can check the Busy Flag and make your LCD speedy. BF = 0 --> Can accept instruction. BF = 1 --> Internal operation in progress no additional operation can be accepted. 0uS
Write to CGRAM or DDRAM10write dataWrites data to CGRAM or DDRAM.40uS
Read from CGRAM or DDRAM11read dataReads data from CGRAM or DDRAM.40uS
* = Not important, Can be "1" or "0"
** = Execution Time is a time needed which the LCD needs for the operation.

CGRAM is character generator RAM, this ram can hold user defined graphic characters. This capability gains these modules popularity because of this you can make bargraphs and your own language's special characters(Maybe Chinese, Korean, Turkish, Greek, etc.).

DDRAM is the Display Data RAM for these modules which represents the hexadecimal Display data adresses. See below:


Line 1

Line 2

















































If you decide to develop your own program after this article, this instruction table will come in handy. If it comes a bit complicated see Part 4 then you can understand the logic behind the instructions with coding.

Part 4 - Coding Time

Now we know a lot of things about LCDs so we can write some codes to make our LCD live. There are three important functions in my app which are Prepare_LCD | move_to_specific | button_Write_to_screen_Click

The below code(Prepare_LCD) Prepares the LCD after you saw the test screen. I made the comments as clear as possible so you can examine with the guiding of the instruction codes above.

private void Prepare_LCD(int cursor_status)
 /* Look at the instruction table to make these comments make sense */

 /* Thread.Sleep() function is not needed for some type of LCD instructions 
  * and also this is changeable from an LCD
  * to another so tryout the best for your module */

  /* Sends 12(d) = 1100 binary to open the entire display and 
   * makes a delay that LCD needs for execution */

  if(cursor_status == 0)
    PortAccess.Output(data, 12); //Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Sends 14(d) = 1110 binary to open the entire display 
   * and makes the cursor active and also
   *  makes a delay that LCD needs for execution */

  if(cursor_status == 1)
    PortAccess.Output(data, 14); //Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Sends 15(d) = 1111 binary to open the entire display, makes 
   * the cursor active and blink and also
   *  makes a delay that LCD needs for execution */

  if(cursor_status == 2)
    PortAccess.Output(data, 15); //Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Makes the enable pin high and register pin low */
  PortAccess.Output(control, 8); Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Makes the enable pin low for LCD to read its 
   * data pins and also register pin low */
  PortAccess.Output(control, 9); Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article
  /* Clears entire display and sets DDRAM address
   *  0 in address counter */
  PortAccess.Output(data, 1); //Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Makes the enable pin high and register pin low */
  PortAccess.Output(control, 8); Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Makes the enable pin low for LCD to read its 
   * data pins and also register pin low */
  PortAccess.Output(control, 9); Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* We are setting the interface data length to 8 bits 
   * with selecting 2-line display and 5 x 7-dot character font. 
   * Lets turn the display on so we have to send */
  PortAccess.Output(data, 56); //Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Makes the enable pin high and register pin low */
  PortAccess.Output(control, 8); Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

  /* Makes the enable pin low for LCD to read its
   * data pins and also register pin low */
  PortAccess.Output(control, 9); Thread.Sleep(1); 
//The delays can be smaller, Check Busy Flag info in the article

move_to_specific moves the cursor anywhere on the LCD (anywhere from the 32 option in a 2x16 LCD). See the code below:

private void move_to_specific(int line, int column)
  /* Makes the RS pin low */
  PortAccess.Output(control, 8); //Thread.Sleep(1);

  if(line == 1)
    /* Sets RAM address so that the cursor is positioned 
     * at a specific column of the 1st line. */
    PortAccess.Output(data, 127+column); //Thread.Sleep(1);
  if(line == 2)
    /* Sets RAM address so that the cursor 
     * is positioned at a specific column of the 2nd line. */
    PortAccess.Output(data, 191+column); //Thread.Sleep(1);

See the below table for the ascii code binary equivalent for understanding the button_Write_to_screen_Click function:

Now you can look at the button_Write_to_screen_Click function in the code, I am not putting it here because I don't want to make the article hard to read but I commented on it in the app so you can check it out.

Note: You can enable Thread.Sleep functions in the code if your LCD's execution time is very quick

Part 5 - Before Final Note

Some people say "what will I benefit from an extra LCD?" For those, I made a tiny thing which grabs codeproject or the msdn rss headlines from the net and displays them on the LCD screen. Now you can check out the news while you are playing or watching full screen TV on your computer.

As you can see in the video the first line is fixed and the second line scrolls with the news after a period of time the second news scrols and the third, fourth and goes on. If you have online site which has some member systems or forums on it, you could send information using a php or an asp file to a xml or txt file and then fetch the info from there and send to the screen of your LCD or maybe even your area's forecast. You can make some periodic e-mail checks and display them on your LCD screen. You can also interface with your winamp for some spectrum visualization like a plugin but this will be outer world plugin to your winamp :) so see the motion1 and motion2 buttons for info how to develop these type of solutions:

You can make lots of things with an extra LCD on your desktop and these type of things are bounded by your imagination so I can say here "Enjoy your imagination" :)

Final Note

Finally I come to the end of my second article in codeproject. I hope I was able to put a smile on the faces of those waiting for my second article. After my first article I get 35-40 e-mails from various people who are interested in these type of things. People send their works also their circuits about various projects, for ex: some people sent their year(s) lasting problems on similar projects. So I want to thank you all for e-mails and also the threads in codeproject. I will be expecting your new suggestions and comments on this article. Don't abstain to mail at if you have problems.

What will be the third?

I don't want to talk about my next article so I didn't put a picture of it like I did in the end of my first article because it is after all a mystery.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Levent Saltuklaroglu
Web Developer
Turkey Turkey
No Biography provided

You may also be interested in...


Comments and Discussions

GeneralSame Thru USB Pin
Juba19-Sep-07 18:13
memberJuba19-Sep-07 18:13 
GeneralRe: Same Thru USB Pin
sick14-Sep-08 4:54
membersick14-Sep-08 4:54 
Generalaccessing parallel port Pin
aksmati886-Sep-07 5:01
memberaksmati886-Sep-07 5:01 
GeneralRe: accessing parallel port Pin
cyberpunk_np15-Oct-07 0:13
membercyberpunk_np15-Oct-07 0:13 
GeneralLCD DOn't show anything Pin
Iosifidis Efthimios24-Jul-07 3:47
memberIosifidis Efthimios24-Jul-07 3:47 
QuestionVista64 and LPT Pin
gxprogs10-Jul-07 20:08
membergxprogs10-Jul-07 20:08 
AnswerRe: Vista64 and LPT Pin
BuggingMe25-Mar-10 8:53
memberBuggingMe25-Mar-10 8:53 
GeneralI think you missed something [modified] Pin
Stephan Poirier7-May-07 18:53
memberStephan Poirier7-May-07 18:53 
Hi Levent,

Maybe I'm wrong but I did a lot of testing to confirm that your code is unusable if you wire the R/W pin to the parallel port. It took a while for me to see that you had hard wired the R/W pin to the ground so it stays always in WRITE mode.OMG | :OMG:
I don't know why I didn't checked there before anything else, my error.Sigh | :sigh:

For my personnal use, I had to wire the R/W pin of the LCD to the parallel port because I wanted the R/W operation to be controlled by my application.

I have a Matrix Orbital LCD model MOP-AL202C that is HD44780 compatible.
This is the mapping of the control bits for my LCD. (Same as you)

Parallel Port                         LCD
Pin 1  --> C0                 Pin 6 --> E (Enable)
Pin 14 --> C1                 Pin 5 --> R/W (Read/Write)
Pin 16 --> C2                 Pin 4 --> RS (Data/Instruction)

In your code, when you put
<code>PortAccess.Output(control, 8);</code>
<code>PortAccess.Output(control, 9);</code>
<code>PortAccess.Output(control, 4);</code>
<code>PortAccess.Output(control, 5);</code>

it control correctly Enable pin and RS pin, but the R/W pin stay in READ mode. So anything you want to write to the LCD won't happen.

So, I corrected the value accordingly to let the R/W pin always stay in WRITE mode.
It gives
<code>PortAccess.Output(control, 2);   //Was 8 before</code>
<code>PortAccess.Output(control, 3);   //Was 9 before</code>
<code>PortAccess.Output(control, 6);   //Was 4 before</code>
<code>PortAccess.Output(control, 7);   //Was 5 before</code>

I'd tested each line of code properly and it works very well. I'd verified each pin with my voltmeter for every code I sent and they change properly and fortunately the R/W pin remains always in WRITE mode.;)

All we have to remember is that C0 (Enable) and C1 (R/W) pin voltage are in reversed logic (high when 0, low when 1) at the output of the parallel port, so you have to consider that when programming. Note that C2 (Register) is in the right logic at the ouput of the parallel port.

On a final note, I just added a truth table
C3 pin from the parralel port is not used on a LCD. You may use it to power the backlight if it doesn't draw to much current. Therefore, you'll be able to turn on and off the backlight programmatically.
                       LCD control truth table
Pin          C3(Select)   C2(Register)   C1(R/W)      C0(Enable)
Bit value        8              4           2             1
                 0              1           1             0         ---->   Gives 6
                 0              1           1             1         ---->   Gives 7
                 0              0           1             0         ---->   Gives 2
                 0              0           1             1         ---->   Gives 3

I hope it will solve a lot of problem to everyone.


-- modified at 1:18 Tuesday 8th May, 2007

Progamming looks like taking drugs...
I think I did an overdose. Poke tongue | ;-P

GeneralRe: I think you missed something Pin
Johannes@Austria19-May-07 6:58
memberJohannes@Austria19-May-07 6:58 
Generalwiring ok but nothing on display Pin
miskecz5-Mar-07 11:46
membermiskecz5-Mar-07 11:46 
Questionwiring ok but nothing on display Pin
Member #38871735-Mar-07 11:36
memberMember #38871735-Mar-07 11:36 
AnswerRe: wiring ok but nothing on display Pin
Iosifidis Efthimios24-Jul-07 9:34
memberIosifidis Efthimios24-Jul-07 9:34 
GeneralRe: wiring ok but nothing on display Pin
miskecz28-Jul-07 21:44
membermiskecz28-Jul-07 21:44 
Generalthe application failed to initialize properly!! Pin
dolbydigital20-Jan-07 2:39
memberdolbydigital20-Jan-07 2:39 
GeneralRe: the application failed to initialize properly!! Pin
AZ_HillBilly9-May-07 11:01
memberAZ_HillBilly9-May-07 11:01 
GeneralNothing is sent to the LCD Pin
Gene Arnold31-Dec-06 7:05
memberGene Arnold31-Dec-06 7:05 
GeneralRe: Nothing is sent to the LCD Pin
Gene Arnold1-Jan-07 15:49
memberGene Arnold1-Jan-07 15:49 
GeneralGood articles - more on reading input Pin
thorkia27-Nov-06 8:38
memberthorkia27-Nov-06 8:38 
GeneralRe: Good articles - more on reading input Pin
Lambry12-Dec-06 9:30
memberLambry12-Dec-06 9:30 
GeneralRe: Good articles - more on reading input Pin
Jerry Jeremiah12-Feb-07 9:51
memberJerry Jeremiah12-Feb-07 9:51 
Questionmore output, extended ports?? Pin
¤ Muammar ¤11-Nov-06 20:54
member¤ Muammar ¤11-Nov-06 20:54 
AnswerRe: more output, extended ports?? Pin
earnshae21-Nov-06 11:15
memberearnshae21-Nov-06 11:15 
GeneralRe: more output, extended ports?? Pin
¤ Muammar ¤2-Dec-06 19:26
member¤ Muammar ¤2-Dec-06 19:26 
AnswerRe: more output, extended ports?? Pin
earnshae4-Dec-06 5:59
memberearnshae4-Dec-06 5:59 
GeneralRe: more output, extended ports?? Pin
Jerry Jeremiah12-Feb-07 9:58
memberJerry Jeremiah12-Feb-07 9:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170424.1 | Last Updated 29 Sep 2003
Article Copyright 2003 by Levent Saltuklaroglu
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid