Parallel Port Programming (PART 1) : With C
Parallel Port Programming (PART 1) : With C
Parallel Port Programming (PART 1) : With C
By Hars
Parallel port is a very commonly known port, widely used to connect the printer to the PC. If you
backside of your computer, there will be a port having 25 pins with a small symbol like this: . Th
is known as LPT port or printer port. We can program this port for device control and data transfer.
article, we will learn basics of parallel port and programming the parallel port.
Parallel port basics:
In computers, ports are used mainly for two reasons: Device control and communication. We c
program PC's Parallel ports for both. Parallel ports are mainly meant for connecting the printer to th
But we can program this port for many more applications beyond that.
Parallel ports are easy to program and faster compared to the serial ports. But main disadvant
it needs more number of transmission lines. Because of this reason parallel ports are not used in lo
distance communications. Let us know the basic difference between working of parallel port and se
port. In serial ports, there will be two data lines: One transmission and one receive line. To send a d
serial port, it has to be sent one bit after another with some extra bits like start bit, stop bit and parit
detect errors. But in parallel port, all the 8 bits of a byte will be sent to the port at a time and a indic
will be sent in another line. There will be some data lines, some control and some handshaking line
parallel port. If three bytes of data 01000101 10011100 10110011 is to be sent to the port, followin
figures will explain how they are sent to the serial and parallel ports respectively. We can understan
parallel port communication is faster compared to that of serial.
In computers, ports are used mainly for two reasons: Device control and communication. We c
program PC's Parallel ports for both. Parallel ports are mainly meant for connecting the printer to th
But we can program this port for many more applications beyond that.
Parallel ports are easy to program and faster compared to the serial ports. But main disadvant
it needs more number of transmission lines. Because of this reason parallel ports are not used in lo
distance communications. Let us know the basic difference between working of parallel port and se
port. In serial ports, there will be two data lines: One transmission and one receive line. To send a d
serial port, it has to be sent one bit after another with some extra bits like start bit, stop bit and parit
detect errors. But in parallel port, all the 8 bits of a byte will be sent to the port at a time and a indic
will be sent in another line. There will be some data lines, some control and some handshaking line
parallel port. If three bytes of data 01000101 10011100 10110011 is to be sent to the port, followin
figures will explain how they are sent to the serial and parallel ports respectively. We can understan
parallel port communication is faster compared to that of serial.
electroSofts.com will soon
you an article on serial port program
in Windows.
figure 1.0 © electroSofts.com
figure 1.1 © electroSofts.com
In the PC there will be D-25 type of female connector having 25 pins and in the printer, there will be
pin Centronics connector. Connecting cable will combine these connecter using following conventio
structure of D-25 and Centronics connecters are explained bellow.
Now let us know how communication between PC and printer takes place. Computer places t
data in the data pins, then it makes the strobe low. When strobe goes low, printer understands that
is a valid data in data pins. Other pins are used to send controls to the printer and get status of the
printer, you can understand them by the names assigned to the pins.
To use the printer port for applications other than printing, We need to know how ports are
organized. There are three registers associated with LPT port: Data register, Control register and S
register. Data register will hold the data of the data pins of the port. That means, if we store a byte
to the data register, that data will be sent to the data pins of the port. Similarly control and status
registers. The following table explains how these registers are associated with ports.
Direction
Pin No (D-Type 25) SPP Signal Register.bit
In/out
1* nStrobe In/Out Control.0
2 Data 0 In/Out Data.0
3 Data 1 In/Out Data.1
4 Data 2 In/Out Data.2
5 Data 3 In/Out Data.3
6 Data 4 In/Out Data.4
7 Data 5 In/Out Data.5
8 Data 6 In/Out Data.6
9 Data 7 In/Out Data.7
10 nAck In Status.6
11* Busy In Status.7
12 Paper-Out / Paper-End In Status.5
13 Select In Status.4
14* nAuto-Linefeed In/Out Control.1
15 nError / nFault In Status.3
16 nInitialize In/Out Control.2
17* nSelect-Printer/ nSelect- In/Out Control.3
In
18 - 25 Ground Gnd
Table 1.1: Pin directions and associated registers.
* Pins with * symbol in this table are hardware inverted. Than means, If a pin has a 'low' ie. 0V
Corresponding bit in the register will have value 1.
Signals with prefix 'n' are active low. That means, Normally these pins will have low value. Wh
needs to send some indication, it will become high. For example, Normally nStrobe will be high, wh
data is placed in the port, computer makes that pin low.
Normally, data, control and status registers will have following addresses. We need these add
in programming later.
By default, data port is output port. To enable the bidirectional property of the port, we need to
the bit 5 of control register.
To know the details of parallel ports available in your computer, follow this procedure:
To start programming, you will need a D-25 type Male connector. Its pin structures can be foun
the connector as follows:
When we want to find out whether particular pin of the port is high or low, we need to input the
of corresponding register as a byte. In that, we have to find out whether the corresponding bit is hig
low using bitwise operators. We can't access the pins individually. So, you need to know basic bitw
operations.
Main bitwise operators that we need are bitwise AND '&' and bitwise OR '|'. To make a particul
in a byte high without affecting other bits, write a byte with corresponding bit 1 and all other bits 0; O
with original byte. Similarly, to make particular bit low, write a byte with corresponding bit 0 and all o
bits 1; AND it with original byte.
In Turbo C, there are following functions used for accessing the port:
outport() function sends a word to port, inport() reads a word from the port. outportb() sends a
port and inportb() reads a byte from the port. If you include DOS.H header, these functions will be
considured as macro, otherwise as functions. Function inport() will return a word having lower byte
data at PORTID and higher byte as data at PORTID+2. So, we can use this function to read status
control registers together. inportb() function returns byte at PORTID. outport() writes the lower byte
PORTID and higher byte to PORTID+1. So this can be used to write data and control together. out
function write the data to PORTID. outport() and outportb() returns nothing.
Let us start with inputting first. Here is an example program, copy it and run in Turbo C or Borl
without anything connected to parallel port. Then you should see data available in status register a
numbers 10, 11, 12, 13 and 15 of the parallel port. Pin 11 (active low) is 0 and all other pins are 1 m
it is OK.
#include"stdio.h"
#include"conio.h"
#include"dos.h"
Now, take a D-25 male with cables connected to each pins. Short all the pins from 18 to 25, ca
ground. Now you can run above program and see the change by shorting pins 10, 11, 12, 13 and 1
ground. I prefer using switches between each input pins and ground. Be careful, do not try to groun
output pins.
To find out the availability of ports in a computer programmatically, we will use the memory loc
where the address of port is stored.
/*PortAdd.c
To find availability and addresses of the lpt ports in the computer.
*/
#include <stdio.h>
#include <dos.h>
void main()
{
unsigned int far *ptraddr; /* Pointer to location of Port Addresses
*/
unsigned int address; /* Address of Port */
int a;
ptraddr=(unsigned int far *)0x00000408;
clrscr();
#include"conio.h"
#include"dos.h"
void main()
{
while(!kbhit())
{
outportb(PORT, ~inportb(PORT) );
delay(1000);
}
}
We can easily program the parallel port in DOS. But as we know, DOS
programs have their own limitations. So, if you want to move from DOS to
Windows, go through this article. This is an introduction to program the
parallel port in VC++. You need not have much knowledge about VC++.
This article is designed for one who know basics of parallel port and
beginners of VC++. If you don't know anything about parallel port, read my
first article "Parallel port programming with C (Part 1)". There you get basic
information about parallel port and programming the port in Turbo C or
Borland C.
Now, you are knowing the pins and registers of parallel port. You
know how to access them in DOS. If you want to run your program in
Windows 95 or 98, you are having access to the port in the similar way.
You need to know how to use dialog boxes and windows materials with it.
But your program should also run in Windows XP, NT or higher versions,
then there is another issue. Higher versions of Windows do not allow to
access the hardware directly for security reasons. But still, there are ways, I
will explain later. First we will start programming which will work only in
lover versions of Windows.
Direct Access:
If you want to program the port in VB, there is no direct access to the
port. Still you can access the port using DLL files created with VC++. You
can use the next method Access using inpout32.
If you are familiar with Visual C++, then create a dialog based
application named ParallelPort and skip this section, go to adding controls.
Adding controls:
Now, you should see a tool bar as shown here, it is called Control toolbar. If not, select
it from view menu->toolbars. Icon marked here with red color is the Check Box. If you click
the check box icon and draw in the window, You will have the check box placed in the
window. You need to place 17 such check boxes in the window. You can use copy-past to
make your work easy. After that, Group then using 3 group boxes. Group box icon is there
above the check box in the figure. After doing this much, your design should look like
figure(2.3). So, re arrange your dialog components to look like that. Again run the
application and make sure that there is no error.
figure(2
Figure(2.3)
Next, right click on the Group Box labeled Static and go to properties.
Change the captions to Data, Status and Control respectively. Right click
on the first Check box Check 1, Change the caption to "Pin 2" and ID to
IDC_Pin2. Similarly change the captions of check boxes in data group to
Pin 2 to Pin 9; status port Pin 10, Pin 11, Pin 12, Pin 13 and Pin 15; Control
Port Pin 1, Pin 14, Pin 16 and Pin 17. Change the ID's
correspondingly(IDC_Pin2, IDC_Pin3...).
Window designing is over. Next part is coding. We have placed some
controls in the dialog box. To get the values of these controls, we need to
have variables associated with then. To do that, right click and select
"ClassWizard" from drop down menu. Select tab "Member Variables". You
will get a list of Control IDs. Select each IDs separately and click Add
Variable. Type variable name as m_pin1. m_pin10, m_pin11... and retain
Category Value and Variable type BOOL. Refer following figure.
Figure(2.4)
void CParallelPortDlg::UpdatePins()
{
int reg;
reg=_inp(STATUS);
UpdateData(FALSE);
}
Now scroll to the top of the page and add these lines before class
declarations.
#define DATA 0x378
#define STATUS 0x379
#define CONTROL 0x37a
To make run this code when the dialog is initialized, we need to call it.
So, go to function OnInitdialog() in the file CParallelPortDlg. (In the class
view tab of the workspace, under ParallelPort Classes, expand
CParallelPortDlg, you will get the function name, double click it.) Add the
following code to it. This code will call the function UpdatePins() and set a
timer to scan the port pins. You can change the second parameter to
change the frequency at which ports are needed to be scanned. I have
used 200 milli seconds. _outp(CONTROL, 0xDF) will reset the control
register bit 5 low so that data pins will act as output._outp(PORT, DATA)
sends the byte DATA to the address PORT.
BOOL CParallelPortDlg::OnInitDialog()
{
//App.Wiz generated code
// TODO: Add extra initialization here
SetTimer(1,200,NULL);
_outp(CONTROL, _inp(CONTROL) & 0xDF);
UpdatePins();
return TRUE; // return TRUE unless you set the focus to a control
}
Next part is Updating the pin contents for each timer tics. For that,
we need to handle the windows message WM_TIMER. Now since we have
set the timer for 200 ms, for every 200 ms, Windows returns WM_TIMER
message. To write a handler, write click on the CParallelPortDlg in the
class view tab, select "Add Windows Message Handler...". In "New
Windows messages/events", select WM_TIMER and click Add and Edit. It
will take you to the newly created function CParallelPortDlg::OnTimer(UINT
nIDEvent). Add the following code to it.
void CParallelPortDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
int status_reg;
status_reg=_inp(STATUS);
if((status_reg & 0x40)==0) m_pin10=0; else m_pin10=2;
if((status_reg & 0x80)==0) m_pin11=0; else m_pin11=1;
if((status_reg & 0x20)==0) m_pin12=0; else m_pin12=1;
if((status_reg & 0x10)==0) m_pin13=0; else m_pin13=1;
if((status_reg & 0x08)==0) m_pin15=0; else m_pin15=1;
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
Here, we have refreshed only input pins. Output pins have to be
changed when user clicks on the check boxes. To find any change of value
in check boxes, we can use BN_CLICKED message handler. But for all the
check boxes we have to repeat the process. It is easy to use
ON_COMMAND_RANGE. For that, scroll up to the position in the file
ParallelPortDlg.cpp where you find
BEGIN_MESSAGE_MAP(CParallelPortDlg, CDialog). (Do not confuse
between CParallelPortDlg and CAboutDlg.) Add the following code to it.
BEGIN_MESSAGE_MAP(CParallelPortDlg, CDialog)
//{{AFX_MSG_MAP(CParallelPortDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
//}}AFX_MSG_MAP
//Code added by me from here.
ON_COMMAND_RANGE(IDC_Pin2, IDC_Pin9, ChangePin)
ON_COMMAND(IDC_Pin14, ChangeControl)
ON_COMMAND(IDC_Pin16, ChangeControl)
ON_COMMAND(IDC_Pin17, ChangeControl)
ON_COMMAND(IDC_Pin1, ChangeControl)
//Code added by me till here
END_MESSAGE_MAP()
Above code will call the function ChangePin() when buttons in the
range IDC_Pin2 to IDC_Pin9 are changed and ChangeControl() when
chack buttons with ID IDC_Pin14, IDC_Pin16, IDC_Pin17 or IDC_Pin1 are
changed. Now we need those two functions. Add two new functions to
CParllelPortDlg: void 'ChangePin()' and 'void ChangeControl()' using the
method explained earlier. Write codes to them as follows:
void CParallelPortDlg::ChangePin(int pin)
{
int data_register, new_register;
UpdateData(TRUE);
data_register=_inp( DATA );
new_register=0;
if( m_pin2==TRUE ) new_register |= 0x01;
if( m_pin3==TRUE ) new_register |= 0x02;
if( m_pin4==TRUE ) new_register |= 0x04;
if( m_pin5==TRUE ) new_register |= 0x08;
if( m_pin6==TRUE ) new_register |= 0x10;
if( m_pin7==TRUE ) new_register |= 0x20;
if( m_pin8==TRUE ) new_register |= 0x40;
if( m_pin9==TRUE ) new_register |= 0x80;
_outp(DATA, new_register);
void CParallelPortDlg::ChangeControl()
{
int control_register, new_register;
UpdateData(TRUE);
_outp(CONTROL, new_register);
If everything is OK, you should get the following window when you run
the program. To test the program, run this program without connecting
anything to the port. Change some of the pins and close the window. If you
run the program again you should get the values which was there before
closing the window in the output pins.
You can always use this program to test the parallel port. Now, make
a circuit connecting all the input pins to switches, all the output pins to
LEDs with 2.2K or 10K resisters. If you press switch, corresponding pin
value should change in the screen, If you change state of any output pin,
corresponding LED should glow.
Every thing is ok. But as you know, this program will run only in win9x.
If your program is needed to run in windows xp and higher versions, you
need to write a kernel mode device driver. Do not worry if you are not up to
that level. There are DLL files available freely for such drivers. You can use
those files and call them from your program.
If you do not want to use driver and test the above program in Windows XP
as it is, use my post in the ElectroSofts Forum
InpOut32 is a DLL file which can send a data to parallel port and
which can return the data in the parallel port. You can download this file
with source code for free from http://logix4u.net. You can use this file in
any windows programming language like Visual basic, C#, C++ etc. If you
know how to use DLL files, download the file from http://logix4u.net and use
Inp32() and Out32() functions instead of _inp() and _outp().
To know how to use DLL file in VC++, let us now convert our previous
project to XP enabled program.
Add these two lines in the file ParallelPortDlg.cpp after pre processor
directives.
Where ever _inp() comes, change them to Inp32() and where ever
outp() comes, change them to Out32().
Copy DLL file inpout32.dll and lib file inpout32.lib got by compiling the
source code available at logix4u.net to the project folder.
From project menu, select settings, go to tab link, in object/ library
modules write inpout32.lib
Now your program should run without any errors.