Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006)

.pdf
Скачиваний:
192
Добавлен:
12.08.2013
Размер:
3.18 Mб
Скачать

5 OBJECT-ORIENTED PROGRAMMING 93

void WritePort0(unsigned char data);

// New public member function added.

void ChangeAddress(unsigned int newaddress);

};

ParallelPort::ParallelPort()

{

BaseAddress = 0x378;

}

ParallelPort::ParallelPort(int baseaddress)

{

BaseAddress = baseaddress;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

// New public member function defined.

void ParallelPort::ChangeAddress(unsigned int newaddress)

{

BaseAddress = newaddress;

}

void main()

{

ParallelPort OurPort;

// The correct way to manipulate a private data member OurPort.ChangeAddress(0x3BC);

OurPort.WritePort0(255);

}

The program statement shown below from the previous listing will legally change the value of the private data member BaseAddress to 0x3BC:

OurPort.ChangeAddress(0x3BC);

In this illustrative example we have shown how a private data member can be changed using a public member function. The public member function ChangeAddress() has complete access to the private data member BaseAddress since it is a member function of that same object class. We will not use the ChangeAddress() function in our proper ParallelPort class.

94 5 OBJECT-ORIENTED PROGRAMMING

Instead, the user can pass the desired value for the base address to the constructor so the BaseAddress can be set to a different value than its default value of 0x378 (set by the default constructor).

5.6 Parallel Port Class – Stage II

In the first stage we created an object class named ParallelPort which provided the required functionality to use the port associated with address BASE. We now need this object to also use the port at address BASE+1. Note that the port at address BASE is used as an output port and the port at address BASE+1 is an input port. The new object’s intended functionality is:

ξ

Ability to specify the base address of the parallel port.

ξ

Send data through port at address BASE.

ξ

Receive data through port at address BASE+1.

Adding further functionality to an existing object is an ideal situation for using class derivation. However, there is no justification to develop a hierarchy of classes for each part of the parallel port, since there is no great use of parts of the parallel port. It is most appropriate to develop the entire parallel port as one object. Therefore, in this second stage we will add the extra functionality to the ParallelPort class so it can also use the port at address BASE+1.

The class definition for the new ParallelPort class is given in Listing 5-10, with additions shown in bold text. It contains the declarations for the member data and the member functions. All data members of the class ParallelPort are declared as private. All the member functions are declared as public. As before, BaseAddress is one of the data members and the function WritePort0()is included so that data can be sent out to port at address BASE.

Listing 5-10 New class definition for the object ParallelPort.

class ParallelPort

{

private:

unsigned int BaseAddress; unsigned char InDataPort1;

public:

ParallelPort(); // default constructor ParallelPort(int baseaddress); // constructor void WritePort0(unsigned char data);

unsigned char ReadPort1();

};

5 OBJECT-ORIENTED PROGRAMMING 95

The port at address BASE+1 is an input port (data into the PC). The function ReadPort1() has been introduced to the ParallelPort class to read data through this port. The private data member InDataPort1 is declared to store the data read from this port. The number assignments used for all the members of the class represent the offsets from the base address. For example, WritePort0() function will be writing to an address with offset 0 with respect to the base address

– in this case BASE+0, being the BASE address. Similarly, the ReadPort1() function will read from an address with offset 1. Therefore, it will read the port at address BASE+1.

The definitions of all the functions belonging to this expanded class are contained in Listing 5-11.

Listing 5-11 Function definitions of the ParallelPort object.

ParallelPort::ParallelPort() // default constructor

{

BaseAddress = 0x378;

InDataPort1 = 0;

}

ParallelPort::ParallelPort(int baseaddress) // constructor

{

BaseAddress = baseaddress;

InDataPort1 = 0;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

unsigned char ParallelPort::ReadPort1()

{

InDataPort1 = inportb(BaseAddress+1);

//Invert most significant bit to compensate for

//internal inversion by printer port hardware. InDataPort1 ^= 0x80;

//Filter to clear unused data bits D0, D1 and D2 to zero. InDataPort1 &= 0xF8;

return InDataPort1;

}

The only change to the constructors is the extra statement that initialises the data member of the BASE+1 address, InDataPort1 to 0. If InDataPort1 is not

96 5 OBJECT-ORIENTED PROGRAMMING

initialised it will store some unknown value. However, initialising this variable to 0 is not essential. It may be initialised to any other value or left un-initialised provided precautions are taken to prevent its use until InDataPort1 holds an actual value read from the port.

The function ReadPort1(), reads the port at address BASE+1 and returns a value of type unsigned char. This requires the body of this function to have a return statement, which is return InDataPort1. Therefore, while this function stores the results of input operations in the data member InDataPort1, at the same time it provides an interface to other functions outside of the class to receive the value of this data member. This will enhance the flexibility of the object. In the coming chapters the ParallelPort object will be used when writing many programs. It is advantageous to have full flexibility in the ParallelPort object so that it can be used to write good and efficient programs.

The function inportb() is called within ReadPort1() and carries out the task of reading the data from the port at the specified address, in this case BASE+1. Note that only bits 3 to 7 are free to be read through this port. Also, bit 7 is internally inverted by the parallel port hardware. The ReadPort1() function is coded to compensate for the inversion (explained in Section 3.6) and also clear the unused bits D0-D2 to zero by using the logical AND operator (&). The hexadecimal number F8 represents a bit pattern of 1111 1000 and will clear bits D0-D2 of any number it is ANDed with. The value produced from this correcting operation will be stored in the data member InDataPort1. The last line of the ReadPort1() function contains the return statement which returns the value of InDataPort1.

The complete program is shown in Listing 5-12. Check operation of the program by connecting your interface board to the PC according to Table 3-1 and Table 3-2.

Listing 5-12 Write data to port at BASE and read data from port at BASE+1.

/***************************************************** The fundamental object class ParallelPort is expanded to include the input port at address BASE+1. The combined object is still named ParallelPort and is used to write

to the port at address BASE and to read data from the port at address BASE+1.

*****************************************************/

#include <stdio.h> #include <dos.h>

class ParallelPort

{

private:

5 OBJECT-ORIENTED PROGRAMMING 97

unsigned int BaseAddress; unsigned char InDataPort1;

public:

ParallelPort(); ParallelPort(int baseaddress);

void WritePort0(unsigned char data); unsigned char ReadPort1();

};

ParallelPort::ParallelPort()

{

BaseAddress = 0x378; InDataPort1 = 0;

}

ParallelPort::ParallelPort(int baseaddress)

{

BaseAddress = baseaddress; InDataPort1 = 0;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

unsigned char ParallelPort::ReadPort1()

{

InDataPort1 = inportb(BaseAddress+1);

//Invert most significant bit to compensate

//for internal inversion by printer port hardware. InDataPort1 ^= 0x80;

//Filter to clear unused data bits D0, D1 and D2 to zero. InDataPort1 &= 0xF8;

return InDataPort1;

}

void main()

{

unsigned char BASE1Data; ParallelPort OurPort;

OurPort.WritePort0(255);

BASE1Data = OurPort.ReadPort1();

98 5 OBJECT-ORIENTED PROGRAMMING

printf("\nData Read from Port at BASE+1 %2X\n",BASE1Data);

}

Listing 5-10 and Listing 5-11 (explained earlier) are incorporated unchanged in Listing 5-12 which has a main() function added.

The first line in the main() function is:

unsigned char BASE1Data;

This line declares a variable named BASE1Data to store data of type unsigned char. In strict C++ terms, this line has instantiated an object of type unsigned char and given it the name BASE1Data. As such, BASE1Data will now reside in memory. The purpose of BASE1Data is to store the value read from the port at address BASE+1. How this is done will become clear as we work through the rest of the statements of the main() function.

The next line in the main() function is:

ParallelPort OurPort;

This line instantiates the OurPort object, which is of type ParallelPort. Therefore, Ourport will have two data members, namely BaseAddress and InDataPort1. When the above line is executed, the default constructor will be called (no argument used for the base address). As a result the variable BaseAddress will be set to 0x378 and the variable InDataPort1 will be set to 0.

The two member functions are called in the next two lines:

OurPort.WritePort0(255);

BASE1Data = OurPort.ReadPort1();

The first line writes a byte of data (255 in this case) to the port at address BASE. This will cause all eight LEDs to light. The second line will read the port at address BASE+1 and compensate for inverted bit D7. ReadPort1() stores this result for later retrieval in the data member InDataPort1 and returns the value of InDataPort1 to the main() function. This value received by the main() function is stored into its variable BASE1Data.

The last line of the main() function displays the value of BASE1Data on the screen in hexadecimal format with a field width of 2. A carriage return and line feed is inserted before the value is displayed by using the new line character combination \n. In this example main() function, its variable BASE1Data was assigned the value returned from the ReadPort1() function. Our future programs will not always be programmed to do operate this way. For these cases where the main() function

Also note we need to have the data member InDataPort1 so the value read from the port can be stored in our object. Without having such a storage variable,

5 OBJECT-ORIENTED PROGRAMMING 99

the program must rely on the main() function’s variable BASE1Data to be assigned the value returned from the ReadPort1() function. It will not always be desirable for our future programs to be programmed to use a main() function variable in this way. In these cases, if the ParallelPort object did not have the data member InDataPort1 to store the value returned from ReadPort1(), then this value would be lost once ReadPort1() completes its execution.

5.7 Parallel Port Class – Stage III

In this final stage we will further develop the object class ParallelPort to encompass all input/output functionality of the parallel port of the PC - with one exception. This being the absence of input through BASE+2 as it can be unreliable on some computers. This class will output data through the port at address BASE, input data through the port at address BASE+1, and output data through the port at address BASE+2. It will also compensate for internal inversions that occur within the parallel port hardware.

5.7.1 Full function Object Class ParallelPort

The functionality required for the final object class ParallelPort is:

ξ

Ability to specify the BASE address of the parallel port.

ξ

Output data through the port at address BASE.

ξ

Input data through the port at address BASE+1.

ξ

Output data to the port at address BASE+2.

The definition for the final ParallelPort class is shown in Listing 5-13.

Listing 5-13 The definition for the ParallelPort class.

class ParallelPort

{

private:

unsigned int BaseAddress; unsigned char InDataPort1;

public:

ParallelPort(); ParallelPort(int baseaddress);

void WritePort0(unsigned char data); void WritePort2(unsigned char data); unsigned char ReadPort1();

};

100 5 OBJECT-ORIENTED PROGRAMMING

In the class definition, a function is included for each of the requirements in the list. The definitions of the member functions are given in Listing 5-14. Additions made to the earlier ParallelPort object class are shown in bold font in Listing 5-13 and Listing 5-14.

Listing 5-14 Definitions of member functions of the class ParallelPort.

ParallelPort::ParallelPort()

{

BaseAddress = 0x378; InDataPort1 = 0;

}

ParallelPort::ParallelPort(int baseaddress)

{

BaseAddress = baseaddress; InDataPort1 = 0;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

void ParallelPort::WritePort2(unsigned char data)

{

//Invert bits 0, 1 and 3 to compensate for

//internal inversions by printer port hardware. outportb(BaseAddress+2, data ^ 0x0B);

}

unsigned char ParallelPort::ReadPort1()

{

InDataPort1 = inportb(BaseAddress+1);

//Invert most significant bit to compensate for

//internal inversion by printer port hardware. InDataPort1 ^= 0x80;

//Filter to clear unused data bits D0, D1 and D2 to zero. InDataPort1 &= 0xF8;

return InDataPort1;

}

5 OBJECT-ORIENTED PROGRAMMING 101

The ParallelPort object class is used in the program shown in Listing 5-15 to carry out data transfer operations using all three ports of the parallel port of your PC. The operation of the program can be checked with the interface board. The connections to be made on the interface board are those given in Table 3-1 and Table 3-2. Note that before stepping through the program to test the operation of the port at address BASE+2, remove connections from the BASE address outputs to the LED Driver IC and reconnect the LED Driver IC to the BASE+2 address outputs as per Table 3-3.

Listing 5-15 Input and Output operations using ParallelPort class.

/***************************************************** The object class created to use ports at addresses BASE and BASE+1 has been expanded to include output

through the port at address BASE+2. The combined object class is still named ParallelPort.

*****************************************************/

#include <dos.h> #include <conio.h> #include <stdio.h>

class ParallelPort

{

private:

unsigned int BaseAddress; unsigned char InDataPort1;

public:

ParallelPort(); ParallelPort(int baseaddress);

void WritePort0(unsigned char data); void WritePort2(unsigned char data); unsigned char ReadPort1();

};

ParallelPort::ParallelPort()

{

BaseAddress = 0x378; InDataPort1 = 0;

}

ParallelPort::ParallelPort(int baseaddress)

{

BaseAddress = baseaddress;

102 5 OBJECT-ORIENTED PROGRAMMING

InDataPort1 = 0;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

void ParallelPort::WritePort2(unsigned char data)

{

outportb(BaseAddress+2,data ^ 0x0B);

}

unsigned char ParallelPort::ReadPort1()

{

InDataPort1 = inportb(BaseAddress+1);

//Inverting Most significant bit to compensate

//for internal inversion by printer port hardware. InDataPort1 ^= 0x80;

//Filter to clear unused data bits D0, D1 and D2 to zero.

InDataPort1 &= 0xF8; return InDataPort1;

}

void main()

{

unsigned char BASE1Data; ParallelPort OurPort;

OurPort.WritePort0(0x55);

printf("\n\nData sent to Port at BASE\n"); getch();

BASE1Data = OurPort.ReadPort1();

printf("\nData read from Port at BASE+1: %2X\n", BASE1Data);

getch();

OurPort.WritePort2(0x00);

printf("\nData sent to Port at BASE+2\n"); getch();

}

The first line of the main() function’s body instantiates one object of type unsigned char named BASE1Data used to store data read from the port at