394 12 DATA ACQUISITION WITH OPERATOR OVERLOADING
cout. This overloading process will enable us to output the converted value to cout. The header file adc.h must be modified to include the new operator overloading function. It is possible to write this function without it needing to access any private data of the ADC class. We have chosen to write a non-member function, and so it does not need to be declared as a friend function. The new header file is given in Listing 12-18.
Listing 12-18 File adc.h overloads the << operator.
#ifndef AdcH #define AdcH
#include <iostream.h> #include "pport.h"
class ADC : public ParallelPort
{
private:
unsigned char ADCValue;
public:
ADC(int baseaddress=0x378); unsigned char ADConvert(); unsigned char GetADCValue();
friend void operator>>(ADC adc, unsigned char& value);
};
// declaration of the non-member functions ostream& operator<<(ostream& os, ADC adc);
#endif
Observe the similarity of the following function with the Add_A_Bead() function described earlier in Section 12.2.9:
ostream& operator<<(ostream& os, ADC adc);
The operator overloading function operates in a very similar manner, except the operator << is now used to call the function. The function file is given in Listing 12-19.
Listing 12-19 Function file adc.cpp for the header file in Listing 12-18.
#include <iostream.h> #include "adc.h"
ADC::ADC(int baseaddress) : ParallelPort(baseaddress)
{
ADCValue = 0;
12 DATA ACQUISITION WITH OPERATOR OVERLOADING 395
}
unsigned char ADC::ADConvert()
{
WritePort2(0x01);
WritePort2(0x00);
WritePort2(0x01);
WritePort2(0x03);
ADCValue = ReadPort1() & 0xF0;
WritePort2(0x01);
ADCValue += (ReadPort1() >> 4) & 0x0F;
return ADCValue;
}
unsigned char ADC::GetADCValue()
{
return ADCValue;
}
void operator>>(ADC adc, unsigned char& value)
{
adc.ADConvert(); value = adc.ADCValue;
}
ostream& operator<<(ostream& os, ADC adc)
{
os << “ “ << (int)adc.ADConvert();
return os;
}
The following programming statement demonstrates the elegance of operator overloading.
cout << Adc << Adc << Adc;
Each use of the overloaded operator << with an Adc object will perform an analog-to-digital conversion and then send the resulting output value to the standard output device. As such we will be able to use the above statement to produce three output values to the screen.
The above statement has the precedence of evaluation as shown by the parentheses in the statement below:
396 12 DATA ACQUISITION WITH OPERATOR OVERLOADING
(((cout << Adc) << Adc) << Adc;)
The program dataacq.cpp shown in Listing 12-20 contains a main() function you can experiment with. This program will carry out three analog-to-digital conversions and send the values to the screen every second. Several analog-to- digital conversion samples can be acquired as a group and averaged to overcome the effects of noise on a signal. Note that a significant period of time is consumed to print each set of results to the screen, slowing the effective speed of acquisition.
Listing 12-20 main() function datacq.cpp checks operation of operator <<.
#include <conio.h> #include <bios.h> #include <dos.h>
#include "adc.h"
void main()
{
ADC Adc;
int Quit = 0;
clrscr();
while(!Quit)
{
cout << endl << Adc << Adc << Adc;
if(bioskey(1)!=0)
if(bioskey(0) == 0x2d00) Quit = 1; /*Alt-X*/ delay(1000);
}
}
Executable File Generation
|
Required Files |
|
Listing No. |
|
|
Project File Contents |
|
|
pport.cpp |
|
Listing 10-8 |
|
|
|
|
|
pport.h |
|
Listing 10-7 |
|
|
|
|
|
|
|
|
|
|
|
adc.cpp |
|
Listing 12-19 |
|
|
|
|
|
|
|
|
|
|
adc.h |
|
Listing 12-18 |
|
|
|
|
|
dataacq.cpp |
|
Listing 12-20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Operator overloading can be used for a variety of other tasks. For example, we can overload the ++ operator in the DCMotor class described in Chapter 8 to enable us to increment the Speed by 1 unit of resolution. Similarly, the -- operator can be
12 DATA ACQUISITION WITH OPERATOR OVERLOADING 397
overloaded in the DCMotor class to decrement the Speed by 1 unit of resolution. A segment of sample code that uses such overloaded operators could be:
DCMotor Motor1;
Motor1++; // increase speed by 1
Another example would be to overload the << operator in the DAC class so it can output the integer value N to the Digital-to-Analog Converter:
DAC Dac;
Dac << N;
12.4 Summary
There are several methods that can be used to pass parameters into functions and return the result from the function. Most functions receive their parameters as a copy of the argument given in the calling environment. An alternate means of passing parameters is pass by reference. When passing parameters by reference the function has access to the actual argument used in the calling environment. This saves memory space and also provides an improvement in speed. For reasons such as these, pass by reference is generally preferred when passing class objects to functions.
Similarly, most functions are written to return values as a copy of the value generated within the function. If values are returned by reference, the real object within the function is returned rather than a copy of it. This facility can be used efficiently in operator overloading, in particular with the chained use of an operator.
Friend functions are a special category of functions that have unrestricted access to all members of the class they are declared in. Although they are not member functions, they have all the privileges of a member function. Friend functions have a further advantage over member functions in that they do not need to be tagged to an object when being called (using ‘.’ or ‘->’ membership operators).
12.5 Bibliography
Winston, P.H., On to C++, Addison Wesley, 1994.
Johnsonbaugh, R and Martin Kalin, Object-Oriented Programming in C++, Prentice Hall, 1995.
Staugaard A. C. (Jr), Structured and Object Oriented Techniques, Prentice Hall, 1997.
Lafore, R. Object Oriented Programming in MICROSOFT C++, Waite Group Press, 1992.
Wang, P.S., C++ with Object Oriented Programming, PWS Publishing, 1994.
13.1 Introduction
So far we have not used real-time for tasks that have involved timing. Recall the generation of PWM signals from Chapter 8. In these programs we generated time delays by executing software loops whose duration was unknown and dependent on the computer’s speed. A hardware timer is typically used when time needs to be measured accurately. Your PC is equipped with such a timer that can be programmed to carry out various timing-related tasks. It operates independently of the PC’s processor to ensure uninterrupted and accurate operation, and has spare resources for us to use in our own programs.
In general, the timer subsystem of your PC has three independent timers. More modern systems will have five independent timers. We will keep our discussion to the most general case, i.e. three timers. There are two principal functions associated with timers; timing of an event and counting events. The basic requirement for any timer is a clock signal; being a continuous train of pulses with a known and highly stable frequency. Having access to a steady clock allows us to write programs that can take advantage of real-time operations.
13.2 PC Timer System
Central to the timing system of all but the most recent PC’s is the 8254 Programmable Interval Timer containing three timers, named Timer 0, Timer 1 and Timer 2 as shown in Figure 13-1. The timers can be operated in several different modes controlled by gate signal level and the use of a control register (explained in section 13.2.2). These modes include single timeout, square wave generator and rate generator, discussed in section 13.2.3. They share a common clock signal driving their clock inputs, but only Timer 2 has a gate input that is free to be controlled through software.
Each of the timers contains a 16-bit counter. A counter can be considered as a special memory location in hardware, the value of which is incremented or decremented by each incoming clock pulse. In your PC, each clock pulse drives the counters down a count value. Typically, the counter’s output signal will change state when it reaches zero.
Because all three timers share the same fixed clock signal, they cannot be used for event counting. Event counting takes place when a counter/timer is used to count external pulses applied to its clock input - often arriving at irregular intervals. Regardless of the speed of a PC, its clock frequency will be 1.1932 MHz. This enables every PC to maintain a fixed standard for timing.
Clock |
|
|
|
Clock |
Timer 0 |
|
|
|
|
|
|
|
|
(1.1932 MHz) |
|
|
|
|
Timer Interrupts |
|
|
Gate |
(16-bit π counter) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Clock |
Timer 1 |
|
|
|
Periodic Pulses to |
|
|
|
|
|
|
|
|
|
|
|
|
Gate |
(16-bit π counter) |
|
|
|
Refresh Dynamic |
|
|
|
|
|
|
|
RAM |
|
|
|
|
Clock |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Programmable |
|
|
|
Timer 2 |
|
|
|
|
|
|
|
Gate |
|
|
|
|
|
|
|
(16-bit π counter) |
|
|
|
|
Signal 1 |
|
|
|
|
|
|
|
|
|
To Speaker |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Drive Circuitry |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Programmable |
|
|
|
|
AND |
|
|
|
|
|
|
|
|
Gate |
|
|
|
|
|
Signal 2 |
|
|
|
|
|
|
|
|
|
|
|
|
Figure 13-1 PC Timing System - 3 timers (clock input, gate, and output).
The three timers in your PC have special tasks assigned to them, explained as follows.
TIMER 0
Timer 0 is used to generate the so-called timer interrupt. The timer interrupt will regularly trigger the CPU to execute a special routine that updates the system time. This action takes place every 54.9 milliseconds. The gate signal of Timer 0 is held permanently at logic-HIGH, and therefore is not programmable. Since the clock and the gate are not programmable, the only timer variables that can be altered are the count value written to the counter and the mode of operation. Timer 0 has an output latch register that allows software to read the count value. Furthermore, the state of its output signal can be determined (i.e. high or low) by reading Timer 0’s status register.
NOTE
An interrupt is a signal generated by hardware or software that is sent to the CPU
to request its attention. Depending upon the priority of an interrupt, it will be
attended to immediately or flagged for later attention. The interrupt generated by
timer 0 has the highest priority and will be attended to immediately by the CPU.