The serial port enables to the electronic designer to communicate a PC with devices that supports the RS-232 standard. On the other hand, the parallel port outputs eight data bits and five input signals. It outputs only one interrupt signal (IRQ7).

On the contrary the ISA BUS outputs a 20 bit address bus and a 8 bit data BUS. Allows to manage most of the PC interrupt signals and even, drive DMA (direct memory access) transfers.

Description of the BUS.

In the figure you can see the pinouts of the ISA BUS. The BUS is divided into two sides. The first side pins are named A1 to A31 and it is the components side. It consist of the address and data buses. The second side pins are named B1 to B31 and it is the solder side. This side contents the power pins and the signals related to interrupts and DMA transfers.

We list the most used pins and its description below. For the "A" side:

A0-A19 (pins A31 to A12): This twenty lines are the address BUS. They can address 1MB (2^20 bytes).
D0-D7 (pins A9 to A2): The data BUS consist of this eight data lines.
AEN (pin B11): It is used for the DMA controller to take over the data and address buses in a DMA transfer.

For the "B" side:

GND (pins B1, B10, B31): Connected to the ground of the computer
+5V (pins B3, B29): 5V DC output of the power source.
-5V (pin B5): -5V DC output.
-12V (pin B7): -12V DC output.
+12V (pin B9): +12V DC output.
MEMW (pin B11): The uP asserts this signal when doing a write to the memory.
MEMR (pin B12): The uP asserts this signal when doing a read from the memory.
IOW (pin B13): The uP asserts this signal when doing a write to a port.
IOR (pin B14): The uP asserts this signal when doing a read from a port.
DACK0-DACK3 (pins B15, B17, B19 and B26): The DMA controller sets this signals to let a device know that the DMA has the control of the buses.
DRQ1-DRQ3 (pins B6, B16 and B18): Allow the peripheral boards to request the use of the buses.
+T/C (pin B27): The DMA controller sets this signal to let the peripheral know that the programmed number of bytes has been sent.
IRQ2-IRQ7 (pins B4, B21, B22, B23, B24 and B25): Interrupt signals. The peripheral devices sets this signals to request for the attention of the uP.
ALE (pin 28): This signal is used for the uP to lock the 16 lower address BUS in a latch during a memory (or port) input/output operation.
CLOCK (pin 20): Is the system clock.
OSC (pin 30): Is a high frequency clock which can be used for the I/O boards.

Let's start describing the operation of the ISA bus with a simple read cycle from an Input/Output port. The first thing the microprocessor does is to send out a high on the ALE signal, then sends out the A0-A19 lines. After, the ALE signal goes low. From now on the address of the target port to be read will be latched. Then the BUS takes the -IOR signal to a low level. So that the addressed device will take a data byte to the D0-D7 data bus. The microprocessor will read then the data bus and take the -IOR signal to a high again.

A write cycle to a port works this way: The microprocessor asserts the ALE high, then outputs A0-A19. ALE goes low again. The microprocessor send out the data byte to be write. It then asserts the -IOW signal. After the device have time to read the data byte, the uP raises the -IOW signal high again.

The only difference between a memory read/write cycle and a port read/write cycle is that in a memory cycle the -MEMR and -MEMW signals will be asserted, working the same way as -IOR and -IOW do.

Driving Interrupts.

In the PC memory map we can find two kinds of interrupts, the software interrupts and the hardware interrupts. In this tutorial only the hardware interrupts will be explained. In a PC, the external interrupts are driven by the 8259A priority interrupt controller. When an 8259A receives an interrupt signal through the IRQ2 to IRQ7 signals, it sends an interrupt request signal to the INTR input of the uP. Then the 8086 outputs an INTA (interrupt-acknowledge) signal to the 8259. So that the uP can get interrupt type of the external device. The 8086 then uses the type read from the external device to get the address for the interrupt-service procedure from the interrupt pointer table in memory. Note that INTR and INTA are not present in the ISA bus, this signals are only used for the uP and the 8259A.

Programming Interrupts.

The basic target of an interrupt is to execute a function that response to the request of a hardware device. An interrupt vector contents the address of this function. In an 8086 system the first Kbyte of memory (from 00000H to 003FFH) is used for the interrupt vectors. To point to any address of the whole memory map four bytes are needed. 16 bits for the base address and 16 bits to identify the segment. So, a 1Kbyte of memory allows to store 256 interrupt vectors. Some of the 256 interrupt vectors are used for the system, others are free to be used for the user programs. To install a user interrupt service procedure you can use a program like the one of the example.

The program install an interrupt routine in the IRQ1 interrupt channel, which is the system timer. This timer generates an interrupt 18.2 times per second. In the interrupt service routine, we increment a global variable. When this variable equals to 18 is printed on the screen. So that, we will get on the screen a second counter.

#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <bios.h>
#define IMR 0x21
int _key=1;
int global=0;
void interrupt (*_old_int_function)();
char _old_mask;
char _interrupt_mask(int IRQn)
char p=1;
return ~p;
void _install_int_function(int IRQn, void interrupt (*_new_int_function)())
int inter = IRQn + 8;
_disable(); //disable interrupts
_old_int_function=_dos_getvect(inter); //save the old interrupt vector
_dos_setvect(inter,_new_int_function); //install the new interrupt vector
_old_mask=inportb(IMR); //save the state of the 8259A IMR register
outportb(IMR,_old_mask&_interrupt_mask(IRQn)); //Set new value for IMR register
_enable(); //enable interrupts
void _end_interrupt(void)
void _Unistall_new_int_function(int IRQn)
int inter = IRQn + 8;
_disable(); //disable interrupts
_dos_setvect(inter,_old_int_function); //restore the old interrupt service function
outportb(IMR,_old_mask); //restore the IMR
_enable(); //enable interrupts again
void interrupt _new_int_function()
_disable(); //disable interrupts
global++; //global count the number of interrupts
//that the system has requested
_end_interrupt(); //to tell the system the interrupt service function has finished
_enable(); //enable interrupts again
/*Read the keyboard. If "ESC" is pressed the program ends*/
void _keyboard(void)
union u_type{int a;char b[3];}keystroke;char inkey=0;
if(bioskey(1)==0) return;
switch (inkey)
case 1: _key=0;
case 11: _key=39;
return; /*_key 0*/
default: _key=15;
void main(void)
int second=0;
cprintf("Press 'ESC' to exit \n \n");
_keyboard(); //read the keyboard
if (global >=18)
second++; //incremented each second
cprintf("Time: %d",second);
while(_key !=0);

DMA transfers.

Some input/output devices send data faster than the microprocessor can get it. The DMA (Direct Memory Access) is a dedicated IC that sends and receives data faster than the microprocessor. So magnetic and optical disks use this IC to access the memory of the system.

The DMA (Direct Memory Access) controller borrows the address bus, the data bus and the control bus from the system and transfers a programmed series of bytes from a fast I/O device to the memory. The 8237 DMA controller is the device used for the PC to do this job.

When a device has a data block ready to be send to the memory, sends a DMA request asserting a DRQn signal to the DMA controller. If the requested channel is unmasked, the DMA will send a HRQ (hold request) signal to the microprocessor. The microprocessor will respond floating its buses and sending a HLDA (hold acknowledge) signal to the DMA. Then the DMA gets the control of the buses asserting the AEN signal high and sending out the address of memory to be written. Next the DMA outputs the DACKn (DMA acknowledge) to the device. Finally the DMA controller asserts the MEMW and IOR signals on the control bus. When the data transfer is completed unasserts the HRQ signal and the processor gets the control of the buses again.

If a device needs some data from the memory, the process is similar. The only difference is that the DMA controller outputs the MEMR and IOW on the control bus.

  • Using the power source.
  • Description of the port.
  • Addressing the port.
  • Programming the port.
  • Description of the port.
  • Addressing the port.
  • Programming the port.
  • Introduction to serial communications.
  • Description of the port.
  • Addressing the port.
  • Programming the port.


  • Introduction.
  • Description of the BUS.
  • Driving Interrupts.
  • Programming Interrupts.
  • DMA transfers.


This is the Tutorial Section. In it we will describe the hardware of some parts of a modern PC. If we take a look at the standard Input/Output PC connectors we can find: the parallel port, to which the printer is connected, two COM ports (the RS_232 ports), and the joystick port. We will start by describing the parallel and the joystick ports. But first, we will show you how can we use the power source of the PC to connect other devices.


When the box of your computer is open you can see the different parts of the PC: the motherboard, the disk units, the video board and the power source. The power source consists of an aluminum box with wires of different colors getting out of it.

Using the power source.

Colors of wires
black / ground
red / 5V
yellow / 12V

The parallel, the joystick and the serial ports have no pin connected to the PC source. So, all the devices you connect to this port must use an extern source. However, you have got another option: the power source of the PC could be used to give power to other devices

The source of the computer has got five outputs. These outputs consist of ,many wires connected to GND, 5V, -5 V, 12V and -12 V. These are the voltages that the computer works with. If you take these wires out of the computer box you can use them to power up some devices.

The most used voltages are 5V, 12V and GND. To identify these outputs most dealers of PC power sources use the colors shown in the table 1.1.


Description of the port.

The Parallel port is a standard designed to connect a printer to a computer. It is used for the CPU to send data to a printer. This interface drives some input and output signals. The purpose of these signals is to let the computer know the state of the printer and control it. Eight data bits carry all the information sent with each clock pulse.

The hardware of this port consists of 8 output data bits, 5 input control bits and 5 output control bits. The control signals are listed below:


STROBE/: Tells the printer when the eight data bits are ready to be read. Turns to a low logic level when the data are ready.

INIT/: Reset the printer.

SLCT IN/: Selects the printer when it turns to a low logic level.

AUTO FD/: Tells the printer to print an empty line followed by a carriage return.

D0-D7: Data bits.


ACK/: Tells the CPU that the data has been correctly received.

BUSY: The printer sets this line when its buffer is full. The computer will stop sending more data.

SLCT: Tells the computer that a printer is present.

ERROR/: An error has occurred. The CPU stop sending more data.

PE: The printer is out of paper.

All these signals are connected to a 25 PIN connector. All the bits have TTL logic levels.

Addressing the port.

Table 2.1

Data Bits Table
D0 / data 0 / 2
D1 / data 1 / 3
D2 / data 2 / 4
D3 / data 3 / 5
D4 / data 4 / 6
D5 / data 5 / 7
D6 / data 6 / 8
D7 / data 7 / 9

In the MS-DOS operative system three parallel ports, called LPT1, LPT2 and LPT3, are supported. So we can find three addresses dedicated to these ports in the memory map of the PC. Let's study the addresses dedicated to LPT1 first. Each parallel port uses three addresses of the I/O map. For LPT1 these addresses are 378H, 379H and 37AH.

378H PORT: In this address the CPU writes the data to be sent to the printer. It is an OUTPUT port. The eight data bits (D0-D7) are latched to appear in the output connector. In the table 2.1 we can see which pins of the connector are used.

379H PORT: This is an INPUT port. These signals are used by the CPU to know the state of the printer. The location of the bits is listed in table 2.2.

37AH PORT: In this port the computer writes the signals that control the printer. Therefore, it is an OUTPUT port, see table 2.3.

Table 2.2

Status Bits Table
D0 / not used
D1 / not used
D2 / not used
D3 / ERROR/ / 15
D4 / SLCT/ / 17
D5 / PE / 12
D6 / ACK/ / 10
D7 / BUSY/ / 11

Table 2.3

Control Bits Table
D0 / STROBE / 1
D1 / AUTO FD / 14
D2 / INIT/ / 16
D3 / SLCT IN/ / 17
D4 / Habilitation IRQ7
D5 / not used
D6 / not used
D7 / not used

The computer has three LPTn ports. The addresses of the control and data signals for each LPTn port are listed below. Each port works in the same way that LPT1 does.

Table 2.4

Adresses of LPTn
LPT1 / 378H / 379H / 37AH
LPT2 / 278H / 279H / 27AH
LPT3 / 3BCH / 2BDH / 3BEH

As you can see, the parallel port is able to control the IRQ7 interruption channel. This is a very powerful capability of this port. In a further tutorial we will show you how to use this signal.

Programming the port.

The programs below are examples about the way you can program the parallel port. They are all compiled with the Borland C++ 3.1 compiler.

#include <stdio.h>
#include <dos.h>
#include <conio.h>
/*This program set the parallel port outputs*/
void main (void)

The first program shows you how to send a byte to the parallel port output addresses. It's as easy as you can see. The outportb(); function sends a byte to a specified I/O port. The first function parameter is the address of the port to write a byte. The second parameter is the value of the byte to send. Both parameters can be defined as variables. In this case the first parameter must be an unsigned int, and the second an unsigned char.

#include <stdio.h>
#include <dos.h>
#include <conio.h>
/*This function read parallel port inputs*/
int Read_Input()
{int Byte;
return Byte;}
void main (void)
{int PP_Input;
PP_Input = Read_Input;

The second example shows you how to read a byte from the parallel port input address. The main function is only used to show the value of the byte in the screen. The inportb(); function read a byte from the specified I/O address of the computer. The parameter must be an unsigned int.

[ Home page ] [ Tutorial ] [ Links ] [ Versión en español ]

Questions, comments, suggestions ?

Please e-mail us at:


Description of the port.

The joystick port is designed as an interface with two analog joysticks. Each joystick has two buttons.

Usually, the joystick port is not integrated like a component of the motherboard. The joystick port is implemented in multi-I/O or sound boards. The connector of the port enables the control of two joysticks at the same time. It is very easy to know if the Joystick port is present in your PC. It is the only 15 pin connector that you can find in your PC rear panel.

The stick is attached to two 100K-ohm potentiometers. One of the resistors changes its value with a change in the position of the stick along the X axis. The other potentiometer does the same with the Y axis. A change in the value of the resistors changes the frequency of a digital pulse. In the conversion of the resistance to a variable frequency pulse, a NE558 is used. This component is very similar to the popular NE555, but the NE558 has four timers integrated in the same IC. Two of these ICs are used for each joystick. One pulse shows the X coordinate of the joystick and the second pulse shows the Y coordinate.

The frequency of the pulses can be calculated by the formula shown below:

T = 10 x R + 24.2

Where R is the value of the resistance in K-omh and T is the time of a pulse, in micro s.

The value of the resistors is 100K-omh, so the maximum time of the pulse is 1.024micro s and the minimum time of each pulse is 24.2 micro s.

Addressing the port.

The joystick port is located in the 201H address of the I/O port.

By writing any value in the address of the Joystick port, the timers start generating pulses. Reading this port, we get a byte. The low nibble gives the state of the four digital pulses. The state of the shoot buttons is given in the high nibble. The meaning of each bit of this port is shown in the table.

Table 3.1

button 2 / button 1 / button 2 / button 1 / coordinate y / coordinate x / coordinate y / coordinate x
BIT 7 / BIT 6 / BIT 5 / BIT 4 / BIT 3 / BIT 2 / BIT 1 / BIT 0

To read the position of the joystick you can use the 84H function of the 15H interruption of the BIOS