Parallel Port Interfacing Tutorial
Parallel Port Interfacing Tutorial
Introduction
Parallel port is a simple and inexpensive tool for building computer
controlled devices and projects. The simplicity and ease of programming makes
parallel port popular in electronics hobbyist world. The parallel port is often used
in Computer controlled robots, Atmel/PIC programmers, home automation, ...etc...
Here a simple tutorial on parallel port interfacing and programming with some
examples.
Everybody knows what is parallel port, where it can be found, and for what
it is being used. the primary use of parallel port is to connect printers to computer
and is specifically designed for this purpose. Thus it is often called as printer Port
or Centronics port (this name came from a popular printer manufacturing
company 'Centronics' who devised some standards for parallel port). You can see
the parallel port connector in the rear panel of your PC. It is a 25 pin female
(DB25) connector (to which printer is connected). On almost all the PCs only one
parallel port is present, but you can add more by buying and inserting ISA/PCI
parallel port cards.
Parallel port modes
The IEEE 1284 Standard which has been published in 1994 defines five
modes of data transfer for parallel port. They are,
1) Compatibility Mode
2) Nibble Mode
3) Byte Mode
4) EPP
5) ECP
The programs, circuits and other information found in this tutorial are
compatible to almost all types of parallel ports and can be used without any
problems (Not tested, just because of confidence ! ). More information on parallel
port operating modes can be found here.
Hardware
The pin outs of DB25 connector is shown in the picture below
The lines in DB25 connector are divided in to three groups, they are
Direction
Register
Inverted
- bit
nStrobe
Out
Control-0
Data0
In/Out
Data-0
Yes
No
Data1
In/Out
Data-1
No
Data2
In/Out
Data-2
No
Data3
In/Out
Data-3
No
Data4
In/Out
Data-4
No
Data5
In/Out
Data-5
No
Data6
In/Out
Data-6
No
Data7
In/Out
Data-7
No
10
nAck
In
Status-6
No
11
Busy
In
Status-7
Yes
12
PaperOut
In
Status-5
No
13
Select
In
Status-4
No
14
Linefeed
Out
Control-1
Yes
15
nError
In
Status-3
No
16
nInitialize
Out
Control-2
No
17
nSelectPrinter
Out
Control-3
Yes
18-25
Ground
from these registers(with some restrictions). For example , if we write '1' to Data
register , the line Data0 will be driven to +5v. Just like this ,we can
programmatically turn on and off any of the data lines and Control lines.
Where these registers are ?
In an IBM PC, these registers are IO mapped and will have unique
address. We have to find these addresses to to work with parallel port. For a
typical PC , the base address of LPT1 is 0x378 and of LPT2 is 0x278. The data
register resides at this base address , status register at baseaddress + 1 and the
control register is at baseaddress + 2. So once we have the base address , we
can calculate the address of each registers in this manner. The table below shows
the register addresses of LPT1 and LPT2
Register
LPT1 LPT2
data registar(baseaddress + 0)
0x378 0x278
0x379 0x279
Programming Concepts
Almost all programming languages allow programmers to access parallel
port using some library functions. For example , Borland C is providing "Inportb"
and "Outportb" functions to read or write IO mapped peripherals. But the
examples provided here in this tutorial is written VC++ and can be easily ported to
other compilers like Borland C and Turbo C. Visual Basic does not have any
functions or support to access parallel port directly, but it is possible to add such
capabilities to your VB application by writing a dll in VC++ and calling its exported
functions from VB. VC++ provides two functions to access IO mapped
peripherals, '_inp' for reading and '_outp' for writing. These functions are declared
in "conio.h".
Hardware for testing sample programs
The schematic diagram of the test circuit is shown below. It is
recommended to build this circuit before testing the sample programs
Start VC++ IDE , Select 'New' from File menu.Then select ?Win32
Console Application? from ?Projects? tab(picture-3). enter project name as ?
partest1? , then click OK button.
Picture-3
Now you can see a dialog box with caption ?Win32 Console Application - step 1
of 1? (picture-4).
Picture-4
Select ?a simple Application? and click Finish. Now open exaple1.cpp from ?
fileview? and replace the existing code with the code given below.
#include"stdafx.h"
#include"conio.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
intmain(intargc,char*argv[])
{
shortdata;
if(argc<2)
{
printf("Usage\n\n");
printf("partest1.exe,,\n\n\n");
return0;
}
if(!strcmp(argv[1],"read"))
{
data=_inp(atoi(argv[2]));
printf("Datareadfromparallelport
is");
printf("%d\n\n\n\n",data);
}
if(!strcmp(argv[1],"write"))
{
_outp(atoi(argv[2]),atoi(argv[3]));
printf("Datawrittentoparallelport
is");
printf("%s\n\n\n\n\n",argv[3]);
}
return0;
}
The Problem
Writing programs to talk with parallel port was pretty easy in old DOS days and in
Win95/98 too. We can use Inporb and outportb or _inp() or _Outp functions in our program without
any problem if we are running the program on Dos or WIN95/98. But entering to the new era of
NT clone operating systems like WIN NT4, WIN2000, WINXP, all this simplicity goes away. Being
interested in Parallel port interfacing and programming you might have experienced the problems
in writing a program that can talk to parallel port successfully in NT based operating systems.
When we are trying to run a program which is written using the the conventional software
functions like Inporb, outportb, _inp() or _Outp on a WINNT or WIN2000 system, it will show an
error message that "The exception privileged instruction occurred in the application at
location ....". The picture of such a messagebox is given below.
Staring to this messagebox, you might have been thinking that "did i make a mistake in
my program ?" it is working fine on WIN98 ... Who is guilty here. 'Nobody' that is the answer. Then
why it is happening like this ..? The answer is in the next paragraph
Being a very secure operating system, Windows NT assigns some privileges and
restrictions to different types of programs running on it.It classifies all the programs in to two
categories , User mode and Kernel mode ie; running in ring3 and ring0 modes. user mode
programs are running in ring3 mode and Kernel mode programs are running in ring0 mode. The
programs you generally write falls in the user mode category. The user mode programs are
restricted to use certain instructions like IN, OUT etc.. Whenever the operating system find that a
user mode program is trying to execute such instructions , the operating system stops execution
of those programs and will display an error message. Eventually our interfacing programs stops
where they are executing IN or OUT instructions to read or write data to parallel port. But in the
same time Kernel mode programs are in no way restricted in executing such instructions. Device
drivers are capable of running in kernel mode. So the workaround for the above stated problem is
to write a kernel mode driver capable of reading and writing data to parallel port and let the user
mode program to communicate with it. Writing a driver is not an easy job for even experienced
programmers. But writing a simple driver for communicating with parallel port is a simple task
when drivers like USB, sound card etc.. are concerned. Even though you get a working driver
from somewhere else, installing and configuring it can be very cumbersome task.
The Solution
Introducing Inpout32.dll for WIN 98/NT/2000/XP. This dll have the following features
1) Works seamless with all versions of windows (WIN 98, NT, 200 and XP)
2) Using a kernel mode driver embedded in the dll
3) No special software or driver installation required
4) Driver will be automatically installed and configured automatically when the dll is loaded
5) No special APIs required only two functions Inp32 and Out32
6) Can be easily used with VC++ and VB
7) Functions are compatible with Jan Axelsons Inpout32.dll (available at www.lvr.com). So this dll
can be used with the sample programs available with the book Parallel Port Complete, without
any modification.
1) 'DriverEntry' , Called when driver is loaded. Creates device object and symbolic links.
2) 'hwinterfaceUnload', Called when driver is unloaded, performs clean up
3) 'hwinterfaceDeviceControl', handles calls made through DeviceIOControl API. Performs reading
writing to the parallel port according to the control code passed.
The DLL Inpout32
The functions in the DLL are implemented in two source files, "inpout32drv.cpp" and
"osversion.cpp". osversion.cpp checks the version of operating system. "inpout32drv.cpp" does
installing the kernel mode driver, loading it , writing/ reading parallel port etc... The two functions
exported from inpout32.dll are
1) 'Inp32', reads data from a specified parallel port register.
2) 'Out32', writes data to specified parallel port register.
the other functions implemented in Inpout32.dll are
1) 'DllMain', called when dll is loaded or unloaded. When the dll is loaded , it checks the OS
version and loads hwinterface.sys if needed.
2) 'Closedriver', close the opened driver handle. called before unloading the driver.
3) 'Opendriver', open a handle to hwinterface driver.
4) 'inst' , Extract 'hwinterface.sys' from binary resource to 'systemroot\drivers' directory and
creates a service. This function is called when 'Opendriver' function fails to open a valid handle to
'hwinterface' service.
5) 'start' , starts the hwinterface service using Service Control Manager APIs.
6) 'SystemVersion' Checks the OS version and returns appropriate code.
What is hwinterface.ocx ActiveX control
It is an activex control with same features of Inpout32.dll. It can be used either with VC++ or VB.
But it gives great convenience when used with VB. Data can be written to parallel port using
Outport method and can be read using Inport method.
The libraries can be linked to the executable in two ways . one is static linking and the other
is dynamic linking. Static linking is the methode used to combine the library routines with the
application. When bulding the program , the linker will search all the libraries for the unresolved
functions called in the program and if found, it will copy the corresponding object code from the
library and append it to the executable. The linker will keep searching until there are no more
unresolved function references. This is the most common methode for linking libraries.This
methode boasts of ease of implementation and speed but will generate bulky executables. In
dynamic linking , the required functions are compliled and stored in a library with
extension ?.DLL?. Unlike static linking, no object code is copied in to the executable from the
libraries.Insted of that, the executable will keep the name of the DLL in which the required function
resides. and when the executable is running , it will load the DLL and call the required functions
from it. This methode yealds an executable with small footprint , but have to compromise on
speed a little.
Example 1
Objetive
Create a Dynamically linkable library which can calculate and return the sum of two numbers
passed to it.
Tools required
visual C++ 6 , Visual basic 6
Writing The DLL
Start VC++ IDE , select ?New? from File menu. Then select ?Win32 Dynamic - link library? from ?
Projects? tab(picture-1). enter project name as ?example1? , then click OK button. Now you can
see a dialog box with caption ?Win32 Dynamic - Link library - step 1 of 1? (picture-2).
Picture 1
Picture 2
Select ?a simple DLL project? and click Finish. Now open exaple1.cpp from ?fileview? (picture-3)
Picture 3
add these lines in to example1.cpp
int _stdcall sum(int x , int y)
{
return x+y;
}
It is a simple function which returns the sum of numbers passed to it.
Now our function is ready. The next step is to create a ?.def? file which informs the linker to export
our function.Select ?New? from ?File? menu and then select ?text File? from ?Files? tab.Give it a
name ?example1.def?. Now you can see an empty file . Add these lines in to ?example1.def?
LIBRARY EXAMPLE1
EXPORTS
sum @1
Select ?Build example1.dll? from ?build? menu. The build process should complete without any
errors. If any error occures , correct it and rebuild again. Oce the build process is completed
successfuly , you can see ?example1.dll? in ?debug? directory.
Now we have successfuly built the Dll and it is the time to test it. For testing the DLL we have to
write a small program in VB. Open a new project in Visual Basic. Place three text box and a
command button like in picture 4.
Picture 4
Copy the code given bellow , to the code window
Private Declare Function sum Lib "example1.dll" (ByVal x As Long, ByVal y As Long) As Long
Private Sub Command1_Click()
Text3.Text = Str(sum(CInt(Text1.Text), CInt(Text2.Text)))
End Sub
copy example 1.dll to ?windows? or ?system? directory . Then run VB ,enter some values to text1
and text2 and click ?Calculate? button. If you can see the sum in text3, you have completed
example1 successfuly ! cangratulations !.
Download the source code and project files for example1
Example 2
Objetive
Create a Dynamically linkable library which can calculate and return the sum of two numbers
passed to it.
Tools required
visual C++ 6 , Visual basic 6
Writing The DLL
Create a new win32 DLL project in VC++ just like in the previous example. insert the statement
given below before main
#include ?string.h?
Insert the following code after main
char* _stdcall to_upper(char *lowerstring)
{
_strupr(lowerstring);
return lowerstring;
}
Create a def file and insert the following code
LIBRARY example2
EXPORTS
to_upper
@1
Now save the project, build it and copy example2.dll to ?windows? or ?system? directory.
Create a new project in VB, place a text box and command button the form paste the following
code to code window.
Private Declare Function to_upper Lib "example2.dll" (ByVal text As String) As String
Private Sub Command1_Click()
If (Text1.text) = "" Then
Exit Sub
End If
MsgBox to_upper(Text1.text)
End Sub
Run the program and enter some lower case characters in textbox.It should display a
messagebox with same characters with case changed.
Download the source code and project files for example2
Example 3
Objetive
Create a DLL which can read/write data to parallel port
This DLL is a very useful for interfacing parallel/serial ports. Since Visual Basic does not have any
facility to communicate with parallel port directly , programmers will have to write code for
accessing parallel port in a DLL and should be called from VB. In this DLL , in this dll , accessing
the device registers is done using functions _Inp() and _Outp(), which is declared in ?conio.h? .
More details about these functions can be found at MSDN online .
We will export two functions from the DLL.One is for reading from a device register and the other
is for writing to the device register. Let these functions be InPort() and OutPort(). InPort() will take
one parameter ie; the address of the register to be read. and Outport will take two ie; the address
of the register to which the data to be written and the data itself.
Note: to do this project , You need to have some knowledge in Parallel port interfacing.
Tools required
visual C++ 6 , Visual basic 6
@1
@2
Picture 5
Add the following code to code window
Private Declare Function InPort Lib "example3.dll" (ByVal portaddress As Integer) As Integer
Private Declare Function OutPort Lib "example3.dll" (ByVal portaddress As Integer, ByVal data As
Integer) As Integer
Private Sub Command1_Click()
OutPort 888, 10 'Val("&h" + Text2.Text), Val(Text1.Text)
End Sub
and to select a particular device for use by the host. When a DC device is selected the 'downstream' devices and the legacy
device do not see any activity on the parallel port. To these devices the parallel port is idle.
One advantage of standardizing on the switching protocol is to enable the use of a common software driver on the host PC. The
host driver, possibly provided by the Operating System, can then provide the switching services for the host application. The
1284.3 Service Provider Interface defines the types of services that are required by client applications. These services will be
provided by the host.
This 1284.3 SPI is responsible for determining how many devices are attached to the parallel port and discovering what they are.
This information is obtained by the 1284 device ID method for LPT plug and play. To the client application it appears that the DC
device is the only device attached to the parallel port. The 1284.3 SPI driver manages the switching and selection of the
peripheral.
Once you have a software layer to provide the basic port enumeration services it is a natural extension to include the data transfer
functions. The 1284.3 Data Link interface defines these services. With a full software interface to the parallel port we are able to
achieve independence from the actual hardware interface. This makes it easier to migrate to newer and faster hardware without
effecting the client applications.
The 1284.3 Data Link defines a packet protocol that enables the delivery of packets of data to other side of the interface. This
creates a connection-less, peer to peer relationship between the host and the peripheral. The header provides information on the
data length and the transport protocol being used. This ensures that the data is only delivered to the appropriate client. The data
length is used to enable DMA for the reception of data.
At this point the 1284/1284.3 protocol stack provides a software interface that is independent of the actual hardware
implementation. With the appropriate implementation of the data link the parallel port could be used with many different transport
protocols. Although this is true, there was no transport layer that could take advantage of the features of the 1284 interface. In
particular the channel capabilities of the EPP and ECP modes.
The IEEE 1284.1 committee had defined a printer management standard that could operate over networks or direct attached
interfaces. They requested that the IEEE develop a transport protocol that would take advantage of the 1284 standard parallel
port capabilities but also be suitable for other physical interfaces. One of the main requirements was that the transport layer be
able to maintain multiple conversations, or sessions, between the PC and the peripheral. In addition to this the protocol should
ensure that one conversation cannot block another. An example of blocking is what you see in older Centronics interfaces. If the
paper should run out of the printer or you open the tray to add more paper you can no longer communicate with the printer. With
1284.4 these functions should be independent and not effect one another.
The IEEE 1284.4 committee was established to develop and define this transport protocol. After analysis of various existing
protocols, such as PPP and the MFP IS16550, it was determined that the Multiple Logical Channels (MLC) protocol developed by
Hewlett-Packard and Genoa Technology met the general requirements for this standard. QualityLogic (formerly Genoa
Technology) and HP offered this protocol as the basis for the 1284.4 standard. While MLC was the basis for 1284.4, the final
standard is not backward compatible with MLC.
The 1284.4 protocol allows a device to carry on multiple, concurrent exchanges of data and/or control information with another
device across a single point-to-point link. Blocking of one data exchange has no effect on the others. While the protocol was
required to operate over the 1284 interface it may also operate over other interfaces such as USB and IEEE 1394.
1284.4 defines a packet protocol that enables this communication. Within the packet is the identity of the source and destination
endpoints, client data, as well as control and credit information. Credit is the flow control method that is used to ensure that
channel blocking does not occur.
With credit the target of a data transfer gives the source of the data an indication of how much data it is guaranteed to accept. In
this way the source can never send more data than the target can accept. Upon initialization both sides negotiate for how much
data needs to be transferred and in what packet sizes.
The source and target identities define a connection between the sides. A source may communicate with multiple target
endpoints. In this way one client can communicate with multiple services on the target. A scanner is one example of how this may
operate. The scanner application on the host may need to communicate with two functions on the scanner peripheral. The first
function may be the scanner control and status monitor. The application will then establish a conversation between itself and this
function on the scanner. At some point a page to be scanned may be inserted. Now the scanner can request the establishment of
a connection between the scan engine and the host application. Now we have two independent conversations established
between the PC and the peripheral.
This model can be extended to many different conversations. Conversations may occur between devices on different physical
interfaces. The advantage of 1284.4 is that it can port to other PC related interfaces by the implementation of the appropriate
software interface. This means that a client application on the PC can communicate with devices on multiple physical interfaces
without any changes.
In conclusion, the parallel port is being enhanced by new hardware and software support. With backward compatibility and a huge
installed base this interface will provide a convenient and powerful port for future peripherals. This presentation will provide an
introduction to the protocol stack and issues involved in developing parallel port peripherals.