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

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

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

134 6 DIGITAL-TO-ANALOG CONVERSION

BASE CLASS

Private

Protected

Public

Private

Protected

Public

Private

Protected

Public

 

 

DERIVED CLASS

Privateaccess

specifier

No access

Private

 

 

 

 

Private

Protected

specifieraccess

No access

 

 

 

 

Protected

accessPublic

 

Protected

specifier

No access

 

 

 

 

Protected

 

 

Public

Figure 6-16 Access specifiers determine access attributes of derived class members.

6.5.2 Polymorph Functions

The attempt to redefine the member function WritePort0() in Listing 6-9 is quite legitimate. However, WritePort0() is a function the DAC class inherited from the base class ParallelPort. To allow derived classes to redefine

inherited functions, the inherited functions must derived class definition as done in Listing 6-9 (and there are two WritePort0() functions: one

be explicitly included in the Listing 6-7). In this example, of them belonging to the

ParallelPort class; and the other belonging to the DAC class. The existence of functions of the same name throughout a class hierarchy is termed polymorphism. These functions not only have the same name, but also the same number of parameters, same types of parameters, and the same sequence of parameters.

The declaration of the DAC class is given in Listing 6-8. Despite the DAC class inheriting the function WritePort0() from the base class ParallelPort, it is explicitly coded again in the DAC class. This allows us to redefine the body of the WritePort0() function to suit the needs of the DAC class.

6 DIGITAL-TO-ANALOG CONVERSION 135

NOTE

There is a clear difference between the term polymorphism and overloading.

Overloaded functions also have the same function name. They differ in the number or type of parameters passed to the functions. In addition, overloaded functions do not need to be member functions.

The complete program, including the class hierarchy that can be compiled without errors is given in Listing 6-9.

Listing 6-9 Digital-to-analog conversion with the expanded DAC object.

/***************************************************** In this program, the compilation error has been eliminated by changing the access attribute of BaseAddress in the base class (ParallelPort) from private to protected. Now the functions of the publicly derived class can access the inherited BaseAddress.

This accessibility is only available to the derived classes of the base class and to the base class

itself. The function WritePort0(), which is re-declared in the derived class, can now be modified without any compilation errors.

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

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

class ParallelPort

{

protected:

unsigned int BaseAddress;

private:

unsigned char InDataPort1;

public:

ParallelPort(); ParallelPort(int baseaddress);

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

136 6 DIGITAL-TO-ANALOG CONVERSION

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);

}

void ParallelPort::WritePort2(unsigned char data)

{

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;

}

class DAC : public ParallelPort

{

private:

unsigned char LastOutput;

public:

DAC();

DAC(int baseaddress);

void WritePort0(unsigned char data);

6 DIGITAL-TO-ANALOG CONVERSION 137

unsigned char GetLastOutput();

};

DAC::DAC()

{

LastOutput = 0;

}

DAC::DAC(int baseaddress) : ParallelPort(baseaddress)

{

LastOutput = 0;

}

void DAC::WritePort0(unsigned char data)

{

outportb(BaseAddress,data); LastOutput = data;

}

unsigned char DAC::GetLastOutput()

{

return LastOutput;

}

void main()

{

DAC D_to_A;

 

 

 

D_to_A.WritePort0(0);

",

D_to_A.LastOutput); // Does

// printf("\nDAC byte:%3d

printf("\nDAC byte:%3d

",

// not work, why?

D_to_A.GetLastOutput());

cout << "

Measure voltage

and press a key" << endl;

getch();

 

 

 

D_to_A.WritePort0(32);

",

D_to_A.GetLastOutput());

printf("\nDAC byte:%3d

cout << "

Measure voltage

& then press a key" << endl;

getch();

 

 

 

D_to_A.WritePort0(64);

",

D_to_A.GetLastOutput());

printf("\nDAC byte:%3d

cout << "

Measure voltage

and press a key" << endl;

getch();

 

 

 

138 6 DIGITAL-TO-ANALOG CONVERSION

D_to_A.WritePort0(128);

printf("\nDAC byte:%3d ", D_to_A.GetLastOutput()); cout << " Measure voltage and press a key" << endl; getch();

D_to_A.WritePort0(255);

printf("\nDAC byte:%3d ", D_to_A.GetLastOutput()); cout << " Measure voltage and press a key" << endl; getch();

}

In the above program, the constructor DAC() is called at the time of instantiating the DAC class object D_to_A. Referring to the function definition of the default DAC() constructor; it makes a call to the default constructor of the class ParallelPort before entering the body of the DAC() constructor. The default constructor of the ParallelPort class will initialise BaseAddress to 0x378 (and set InDataPort1 to 0). Then execution of the body of the constructor DAC() begins. It will initialise the value of the DAC class’s private data member

LastOutput to 0.

Note that the member function GetLastOutput() is called when the value of LastOutput needs to be printed onscreen. This needs to be done because the printf() function does not have direct access to the private data member

LastOutput.

The definition of the WritePort0() function can be modified slightly to revert the access attribute of BaseAddress back to private for the following reasons. Consider the function WritePort0() from Listing 6-9 reproduced in Listing 6-10.

Listing 6-10 WritePort0() function of the DAC class.

void DAC::WritePort0(unsigned char data)

{

outportb(BaseAddress,data); LastOutput = data;

}

The only time BaseAddress is accessed is when the data is sent out the port. The polymorphic function WritePort0() of the ParallelPort class can do this. It has no problem in accessing BaseAddress since the function and the data are in the same class. It is possible to call the polymorphic function WritePort0() of the ParallelPort class from inside the polymorphic function WritePort0() of the DAC class by using the scope resolution operator;

6 DIGITAL-TO-ANALOG CONVERSION 139

the double colon (::). This process is shown in Figure 6-17 and is implemented by modifying the fragment of code from Listing 6-10 to become that given in Listing 6-11.

Derived Class

Derived Class

Inherited Base Class Members

Inherited Base Class’s Members

Parallel Port

Parallel Port

private

private

BaseAddress

BaseAddress

InDataPort1

InDataPort1

public

public

ParallelPort ( )

ParallelPort ( )

WritePort0 (data)

WritePort0 ( )

.

.

.

.

.

.

Derived Class Members

Derived Class Members

DAC

DAC

private

private

LastOutput

LastOutput

public

public

DAC ( )

DAC ( )

DAC (baseaddress)

DAC (baseaddress)

WritePort0 ( )

WritePort0 ( )

GetLastOutput ()

GetLastOutput ( )

Case (a)

Case (b)

Figure 6-17 Use of inherited polymorphic functions (BaseAddress private again).

Listing 6-11 Calling a polymorphic function of a base class.

void DAC::WritePort0(unsigned char data)

{

ParallelPort::WritePort0(data);

LastOutput = data;

}

In the ParallelPort class definition, the access attribute of the data member BaseAddress can now be set back to private as shown in Figure 6-17. The new and preferred program is given in Listing 6-12.

140 6 DIGITAL-TO-ANALOG CONVERSION

Listing 6-12 Use of polymorphic functions.

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

In this program, the access attribute of the data member BaseAddress has been changed back to private.

BaseAddress is accessed via the polymorphic WritePort0() function of the base class, which can access BaseAddress.

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

#include <iostream.h> #include <stdio.h> #include <conio.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; InDataPort1 = 0;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

void ParallelPort::WritePort2(unsigned char data)

{

6 DIGITAL-TO-ANALOG CONVERSION 141

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;

}

class DAC : public ParallelPort

{

private:

unsigned char LastOutput;

public:

DAC();

DAC(int baseaddress);

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

};

DAC::DAC()

{

LastOutput = 0;

}

DAC::DAC(int baseaddress) : ParallelPort(baseaddress)

{

LastOutput = 0;

}

void DAC::WritePort0(unsigned char data)

{

ParallelPort::WritePort0(data);

LastOutput = data;

}

unsigned char DAC::GetLastOutput()

{

return LastOutput;

142 6 DIGITAL-TO-ANALOG CONVERSION

}

void main()

{

DAC D_to_A;

D_to_A.WritePort0(0);

printf("\nDAC byte:%3d ", D_to_A.GetLastOutput()); cout << " Measure voltage and press a key" << endl; getch();

D_to_A.WritePort0(32);

printf("\nDAC byte:%3d ", D_to_A.GetLastOutput()); cout << " Measure voltage and press a key" << endl; getch();

D_to_A.WritePort0(64);

printf("\nDAC byte:%3d ", D_to_A.GetLastOutput()); cout << " Measure voltage and press a key" << endl; getch();

D_to_A.WritePort0(128);

printf("\nDAC byte:%3d ", D_to_A.GetLastOutput()); cout << " Measure voltage and press a key" << endl; getch();

D_to_A.WritePort0(255);

printf("\nDAC byte:%3d ", D_to_A.GetLastOutput()); cout << " Measure voltage and press a key" << endl; getch();

}

Having learnt this elegant means of manipulating private data of a base class from inside a derived class, we can complete our improvements to the DAC class by changing the name of the WritePort0() function of the DAC class to something more appropriate. Let us choose the name SendData() as a replacement name for the function WritePort0() of the DAC class.

The class definition and the complete program to carry out the exact same tasks as the program in Listing 6-12, is given in Listing 6-13. We will be using this final version of the DAC class when we need to use the DAC system on the interface board in future chapters.

6 DIGITAL-TO-ANALOG CONVERSION 143

Listing 6-13 Replacing WritePort0() of DAC class by SendData().

/***************************************************** In this program, the Function WritePort0() of the DAC class is given the new name SendData() which is more appropriate for the DAC class.

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

#include <iostream.h> #include <stdio.h> #include <conio.h> #include <dos.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; InDataPort1 = 0;

}

void ParallelPort::WritePort0(unsigned char data)

{

outportb(BaseAddress,data);

}

void ParallelPort::WritePort2(unsigned char data)

{