Testing the Parallel Port
3.5 Basic Input Using the Parallel Port
In this section we will learn how to write a program to read the port associated with the BASE+1 address (0x379). This is the only port address of the three port addresses comprising the parallel port that is dedicated to input operations. We will be reading this port and displaying the number on-screen that corresponds to the input data received.
Table 3-2 Connections for basic input.
BASE+1 Address*
(Buffer ID, U6)
Power Supply +5V and GND pins D3 +5V D4 GND D5 GND D6 +5V /D7 +5V * The signal preceded by a slash ( / ) is internally inverted by the parallel port hardware.
Once again, program operation can be verified by connecting the PC to the interface board using the interface cable. The remaining connections to be made
are on the interface board and shown in Table 3-2. The incoming data can easily be changed by swapping the wiring for the second column of Table 3-2 between +5V and GND.
Use the interconnect leads to make the connections shown in Table 3-2. When the connections are complete, the signals on the interface board are connected to the port at address BASE+1 (0x379). Note that this port has only five signal lines out of eight that can be used. Three of the signal lines, namely the ones corresponding to Data Bits 0 to 2 are unavailable, as they are not dedicated to the port at BASE+1 in the PC parallel port.
The essential steps required in this program are: 1. Read the port.
2. Display the result on the screen.
Both these actions require very simple statements and do not justify coding extra functions. Therefore, just a main function will suffice. To read a port carrying 8 bits of data, we can use the library function inportb(). To display the result on the screen, we can use the library function printf(). It may be convenient to stop the program immediately after displaying the result so we can read the screen. This is especially useful when an Integrated Development Environment (IDE) is used to develop the program. When IDEs are used, the screen will automatically revert to the IDE’s editor once program execution terminates. This will prevent the user from observing what happened on the screen at the time the program ran. However, we will be able to see the onscreen results if we make the program wait for a key press just before it ends. We can do this using the library function getch(). Therefore, the program must use the function sequence inportb(), printf() and getch() in that order. In order for us to be able to use these functions we must provide their prototypes, contained in the header files dos.h, stdio.h, andconio.h, respectively. This program is shown in Listing 3-2.
Listing 3-2 Reading the port at address BASE+1. /***************************************************** READING THE PORT AT ADDRESS BASE+1
This program will read the port at address BASE+1 and print the number read on the screen. The number is formed by combining the five signal lines read in
through the port. Bits 0, 1 and 2 have no valid data as they are not dedicated to BASE+1 internally in the PC. Bits 3, 4, 5 and 6 will be read as normal. Bit 7 is permanently inverted by the parallel port hardware. *****************************************************/ #include <dos.h>
#include <stdio.h> #define BASE 0x378 void main()
{
unsigned char InputData; // Declare data type for // various InputData. InputData = inportb(BASE+1); // Read port at BASE+1. printf("%2X\n",InputData); // Print result to screen // as a hexadecimal number. getch(); // Wait for key press. }
NOTE
Detailed descriptions of the library functions can be found in the documentation that comes with the C++ development software. More recently, the descriptions are available on-line in help files. The documentation will also provide the names of the header files associated with each library function. This will enable you to determine the name of the header file that must be included in order to be able to use a particular function.
This program has compiler directives; three are include statements and the one is a define statement. The three include statements will include the header filesdos.h, stdio.h and conio.h. The define statement will allow us to use the identifier BASE whenever we need to refer to the actual address 0x378. The main() function begins with the line void main() whose meaning has been explained previously. The main() function like all functions can take in parameters. In this case it does not take any parameters, and so an empty pair of parenthesis are used to follow the word main. This signifies to the compiler that it does not take any parameters and ensures it is recognised as a function.
An example of a function that does take in parameters is the outportb() function used in Listing 3-1. It takes in two parameters - the address the data is to be written to and the data itself. Therefore, its parentheses are not empty.
The next statement (after the brace) in the program is:
As mentioned earlier, this is an identifier declaration. It simply informs the compiler the identifier’s name (in this case, InputData) and the type of data the identifier is allowed to represent (in this case, unsigned char).
This variable is declared so it can be used to store the value returned by the inportb() function. This is an ideal place to understand the concept of return value of a function. The prototype of the inportb() function, as provided by the header file dos.h states that its return value is of type unsigned char. Therefore, the variable InputData must also be declared as unsigned char in order to receive the value returned by inportb().
The next statement in the program is:
InputData = inportb(BASE+1);
This statement makes a call to the function inportb() and takes in one parameter, which is an address. The placeholder BASE is defined as 0x378. Therefore,BASE+1 will evaluate to be 0x379. This value specifies the location of the port to be read. Therefore, this statement will read the second port associated with the parallel port of your PC. The value read by the inportb() function is then placed into the variable InputData.
The statement used to display the result on the screen is:
printf(“%2X\n”,InputData);
Theprintf() function is a C function – not C++. However, since C is a subset of C++ it can be used in C++ programs. When it comes to printing data on the screen,printf() offers good flexibility and ease of use. In our programs we use the good features of C with C++ to develop better applications. The function printf() is a relatively unusual and very useful function in that you can pass a
variable number of parameters to it. Most of the functions you will be writing will have a fixed number of parameters. In the current example, the number of parameters passed to the printf() function is two. The first argument is the string of characters “%2X\n” and the second argument is the value of the variable InputData. These two arguments are separated by a comma.
C Examples of frequently used format specifiers
%10.3f Floating point format with a field width of 10 and 3 decimal places.
%5d Integer format with a field width of 5.
%c Character format.
%s String format (used for a sequence of characters such as a sentence).
%X or %x Hexadecimal format. X will print upper case hexadecimal letters and x
The first argument “%2X\n” is a format specifier that is used when printing the value of InputData on your screen. The characters %2X specify that a hexadecimal format of field width 2 is to be used. A carriage return and a line feed are specified by the two characters \n, the character ‘n’ known as the new line character.
To represent a byte of incoming data, two hexadecimal digits are needed since each hexadecimal digit represents 4 bits. Therefore, a field width of 2 is appropriate. After printing the number, the cursor on your screen will be positioned at the start of the next line.
The line:
getch();
is used to make the program wait for a key press and give us time to read what has been printed on the screen. The getch() function waits to receive a character from the keyboard and so the program will not proceed until a key is pressed. When this happens the program will terminate since there are no more statements to execute.
The operation of the program can be verified by interpreting the bit pattern of the hexadecimal value printed on-screen and then checking that this bit pattern corresponds to the actual signals generated on the interface board. You can change the connections on the interface board by changing the connections shown in the right-most column of Table 3-2. That is, you can re-arrange the connection of signals to ground and to +5V. If you run the program again, you should see a different result on the screen.