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

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

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

418 13 THE PC TIMER

#include "pport.h" #include "pctimer.h"

main()

{

double ReflexTime; ParallelPort PPort; PCTimer T;

//Turn off LEDs at start. PPort.WritePort0(0);

//A long beep.

cout << "\a\a\a\a\a" ;

//Time delay of 1.5-5.0 sec. T.Delay(1500+rand()%3500);

//Light up all 8 LEDs. PPort.WritePort0(255);

//Reset Timer. T.ResetTimer();

//Wait for button press. while((PPort.ReadPort1() & 0x80) == 0)

T.UpdateTicks();

//Read PC Timer.

ReflexTime = T.ReadTimer();

//Turn off LEDs. PPort.WritePort0(0);

cout << "Your reflex time is ";

cout << setprecision(3) << ReflexTime; cout << " ms." << endl;

getch();

return 0;

}

13 THE PC TIMER 419

Executable File Generation

 

Required Files

Listing No.

Project File Contents

 

 

pport.cpp

 

 

 

 

Listing 10-8

pport.cpp

 

 

pport.h

Listing 10-7

pctimer.cpp

 

 

pctimer.cpp

Listing 13-3

 

 

pctimer.h

Listing 13-1

 

 

reflex.cpp

Listing 13-5

reflex.cpp

 

When this program first executes, it turns off all LEDs and issues a long beep. It then generates a random time delay between 1.5 and 5.0 seconds, followed by lighting all eight LEDs and initialising the timer to ‘zero time’. The user then reacts to the LEDs lighting up by pressing the button switch on the interface board. The program detects the button press and calls the ReadTimer() function to read the timer and return the time that has elapsed since ‘zero time’. The LEDs are turned off and the reflex time is displayed on-screen.

Connect the interface board’s BASE address outputs to the inputs of the LED Driver IC according to Table 13-4. The button switch connects to the BASE+1 input as shown in Table 13-5.

Table 13-4 LED connections.

BASE Address

ULN2803A Pin No.

(Buffer IC, U13)

(Driver IC, U3)

D0

1

D1

2

D2

3

D3

4

D4

5

D5

6

D6

7

D7

8

 

 

Table 13-5 Switch connection.

Button Switch

BASE+1 Address

(Buffer IC, U6)

OUT

D3

 

 

13.7 Generating a Time-Base

In Chapter 10 we developed a program (Listing 10-11) to monitor and display the pulse-train from the the interface board’s VCO (voltage-controlled oscillator). The horizontal axis of the plot (time) was generated by using software loops and not from real-time techniques. In the original program, at every instant the VCO’s pulse-train was read, the trace was plotted and the value of i incremented.

420 13 THE PC TIMER

Therefore, each change in i could be considered as a ‘new reading’. Our real-time capabilities can be now used to incorporate an accurate time-base with the graphics plot. Listing 13-6 shows a modified version of the original program (changes shown in bold typeface) that uses a proper time-base for its horizontal axis.

In this program the variable i is still used for positioning the trace along the x axis. However, its meaning is different, now becoming a time unit of 10 ms. For this new arrangement, the main loop in the program plots continuously but only increments the value of i every 10 ms. Therefore, plotting along the horizontal axis moves by one pixel every 10 ms. This also means that the resolution of the plot is 10 ms. That is, if the signal changes in less than a 10 ms period, its change cannot be properly represented and may show as a series of vertical lines. This can be rectified by re-coding the program to use a smaller value for the delay between timer reads to suit the frequency of the incoming signal.

Listing 13-6 Graphical display of pulse-train with a real time-base - timebase.cpp.

/***************************************************** The frequency of the pulse-train being output by the voltage-controlled oscillator will change as we change the analog input voltage to the VCO circuit. The Potentiometer (POT1) on the interface board generates the input voltage to the VCO and the program reads the pulse-train being output by the VCO. This pulse-train is graphically displayed on-screen.

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

#include <graphics.h> #include <stdlib.h> #include <iostream.h> #include <conio.h> #include <dos.h>

#include "vco.h" #include "pctimer.h"

void main()

{

VCO Vco;

PCTimer T;

int i=0; // controls plotting in the x range int SignalLevel;

int Driver = DETECT, GraphicsMode, ErrorCode; int X, Y;

// set to graphics mode

13 THE PC TIMER 421

initgraph(&Driver, &GraphicsMode, "");

//check for error codes ErrorCode = graphresult(); if (ErrorCode != grOk)

{

cout << "Graphics error: "

<<grapherrormsg(ErrorCode) << endl; cout << "Press any key to halt:" << endl; getch();

exit(1);

}

X = getmaxx(); Y = getmaxy();

rectangle(X/4-1, Y/2-76,X*3/4+1,Y/2+76); // border setviewport(X/4, Y/2-75,X/4*3,Y/2+75,1);

T.ResetTimer();

while(!kbhit())

{

SignalLevel = Vco.SignalLevel();

if(SignalLevel == 0) // low level lineto(i,100);

else // high level lineto(i,50);

if(T.ReadTimer() > 10)

{

T.ResetTimer();

i++;

}

if(i > X/2) // half screen = Viewport width

{

i = 0;

while(Vco.SignalLevel()); // wait for low level while(!Vco.SignalLevel());// wait for high level clearviewport();

moveto(0,50);

T.ResetTimer();

}

}

}

422 13 THE PC TIMER

Executable File Generation

 

Required Files

 

Listing No.

 

Project File Contents

 

 

pport.cpp

 

Listing 10-8

 

pport.cpp

 

 

 

 

 

 

pport.h

 

Listing 10-7

 

 

 

 

vco.cpp

Listing 10-4

vco.cpp

 

vco.h

Listing 10-1

 

 

 

pctimer.cpp

Listing 13-3

pctimer.cpp

 

 

pctimer.h

Listing 13-1

 

 

 

 

timebase.cpp

Listing 13-6

timebase.cpp

 

The ‘zero time’ reference is set before starting to plot by calling the function ResetTimer(). This function is also used in the following if statement to periodically reset the timer every 10 ms:

if(T.ReadTimer() > 10)

{

T.ResetTimer();

i++;

}

If a 10 ms period has elapsed, the timer is reset to allow the next 10 ms period to be measured, and the index i is incremented to allow the next pixel to be plotted. Otherwise, i will remain as is and plotting will repeat at the same time position.

When the trace has reached the edge of the Viewport’s plot region (X/2; half the screen width) the program enters an if statement used to setup the screen ready for a new trace. Inside this if statement the program resets the value of i to zero, and then waits for the incoming VCO signal to switch to a high level by waiting for the VCO output to change state from logic-low to logic-high using the following combination of statements:

while(Vco.SignalLevel()); // wait for low level while(!Vco.SignalLevel());// wait for high level

This ensures the plot always starts with the same edge transition on-screen. Once the VCO signal has made the required low-to-high level transition, the screen is cleared, the cursor repositioned to the left edge, and the timer is reset to a fresh ‘zero time’ reference. Note: if interrupts are enabled, some of the pulses displayed may have wider widths due to time consumed by interrupt service routines.

Just as we used a real-time program to plot a waveform on the screen, we can timestamp data in real-time as it is acquired. We will generate a waveform using the VCO and Charge/Discharge circuitry on the interface board, digitise its analogue output using the ADC, timestamp these values, and store this data in a file.

13 THE PC TIMER 423

13.8 Data Acquisition with Timestamp

The Charge/Discharge circuit on the interface board can be driven by a digital logic signal to generate an analog waveform that can be sampled to demonstrate the data acquisition process. Each data sample can be accurately time-stamped as it is acquired by using the PCTimer object in the data acquisition program.

In this section, one program will perform data acquisition, time-stamp the data as it is acquired, and store the data into a disk file for later analysis. A second program will retrieve the stored data from the disk file and process the data to determine the period of the waveform generated by the Charge/Discharge circuit.

13.8.1 The Charge/Discharge Circuit

The Charge/Discharge circuit can be driven from any digital logic signal, including one that may be generated by software using an output bit of one of the ports. However, this application uses the simple arrangement whereby the VCO drives the input of the Charge/Discharge circuit with a periodic signal as shown in Figure 13-5. The Charge/Discharge circuit has a capacitor that is charged when the VCO output becomes low and discharged when the VCO output becomes high. The analog signal output from the Charge/Discharge circuit (shown in Figure 13-6) is digitised by connecting it to the analog-to-digital converter. The program will acquire the digitised signal for more than one period and time-stamp each digitised sample. This data is then stored by writing it to a file.

+5V

 

 

 

 

Input

Output

Input

 

Output

voltage

pulse-train

Charge/Discharge

waveform

POT

VCO

 

 

 

Circuit

(To ADC)

 

 

 

 

 

 

 

 

Interconnect Lead

 

 

 

Figure 13-5 Connections for the VCO to drive the Charge/Discharge circuit.

Voltage

 

 

 

(V)

 

 

Period (T)

 

 

 

5V

A

B

C

Threshold

 

 

 

0

O

 

 

 

 

Time

 

0

 

 

 

 

Figure 13-6 Voltage waveform generated by the Charge/Discharge circuit.

42413 THE PC TIMER

13.8.2Programming Data Acquisition & Timestamp

In this section we will develop two programs. The first program (named TimeStmp.cpp) will sample the signal using the analog-to-digital converter, and read the time of sampling. These paired results will then be written to a disk file. This program will need to use the ADC class and the PCTimer class. Note: the VCO object is not used since the VCO circuit is only used as a signal generator to drive the input of the Charge/Discharge circuit.

The second program (named Period.cpp) will retrieve the stored data from the disk file and scan through the data to determine the period (T) of the waveform. It does not need to use any of the objects developed previously.

Program 1 – TimeStmp.cpp

The steps involved in this program that digitises the signal are:

1.Reset the timer.

2.While looping until sufficient time has elapsed (5 seconds suggested):

-read time and store in an array.

-read ADC and store in an array.

-wait for sampling period (10 ms. is suggested)

3.Write the data to a file.

The program for timed acquisition of data is given in Listing 13-7.

Listing 13-7 Program to acquire data with time-stamps – timestmp.cpp.

#include <iomanip.h> #include <iostream.h> #include <fstream.h> #include <stdlib.h> #include <conio.h>

#include "adc.h" #include "pctimer.h"

void main()

{

ADC Adc; PCTimer T;

double Time[500]; unsigned char Data[500]; double TempTime;

double Duration = 5000; // Acquisition period - 5000 ms. int i = 0;

const int SamplingInterval = 10; // Milliseconds

13 THE PC TIMER 425

T.ResetTimer(); do

{

TempTime = T.ReadTimer(); if(TempTime > i*SamplingInterval)

{

Data[i] = Adc.ADConvert(); Time[i++] = TempTime;

}

}

while(T.ReadTimer() < Duration);

//Create, open then write data to disk file. ofstream os("timestmp.dat");

for(int j = 0; j < i; j++)

{

os << setprecision(3) << Time[j] << '\t';

os << setprecision(3) << (double) Data[j] << endl;

}

os.close(); // Close file.

}

Executable File Generation

 

Required Files

Listing No.

 

 

 

 

pport.cpp

 

 

 

 

 

Listing 10-8

 

pport.cpp

 

 

pport.h

Listing 10-7

 

 

 

 

adc.cpp

Listing 10-4

adc.cpp

 

 

adc.h

Listing 10-1

 

 

 

pctimer.cpp

Listing 13-3

pctimer.cpp

 

 

pctimer.h

Listing 13-1

 

 

 

 

timestmp.cpp

Listing 13-7

timestmp.cpp

 

 

 

 

 

 

 

This program uses the ADC class and the PCTimer class. The ADC class is used to acquire the data by controlling and reading the analog-to-digital converter. The PCTimer class is used to accurately measure the time when the signal was sampled by the ADC. The two objects Adc of type ADC and T of type PCTimer have been instantiated from these two classes.

We have decided to perform data acquisition for a 5 second duration using a sampling interval of 10 ms, generating a total of 500 samples. Two arrays named Time and Data have been created to store the respective data, each having 500 elements, with the variable i used as the array subscript. The variable named

426 13 THE PC TIMER

Duration is used to store the overall sampling duration, and is set to 5000 milliseconds (5 seconds). The variable named SamplingInterval is used to define the sampling interval and is set to 10 ms. Since the sampling interval is constant during this data acquisition process, SamplingInterval is declared as const. The identifier TempTime is used to temporarily store the time read by reading the PC timer.

Just prior to entering the do-while loop, the program resets the PCTimer object T, thereby establishing ‘zero time’. The loop will execute continuously with data read at 10 ms intervals. The if statement compares the current time with the time when the next sample must be taken. When the current time becomes greater than the time for the next sample, the ADC will be read, its value stored in the array Data[], and the time stored in array Time[]. The while loop terminates when the time exceeds the value of Duration.

All the data stored in the two arrays is then written to a data file named timestmp.dat. The ofstream constructor is called to create the file by instantiating the object os of type ostream. The file name timestmp.dat is passed as a parameter to the ofstream constructor. The for loop initialises the integer identifier j to zero and continues to write the values until the value of the subscript j reaches the number of data elements recorded in the do-while loop. The file os is then closed by calling the member function close() of the ofstream class. When the program has completed its execution, all data will be stored as two columns separated by a tab character in the text file timestmp.dat. The first column contains time values and the second column contains integer values representing the analog voltage output from the Charge/Discharge circuit.

Program 2 – Period.cpp

The second program retrieves the data from the disk file and stores this data in memory. It then processes the data to determine the period of the waveform that was sampled.

The steps involved in the second program are now given:

1.Read the data file and store the data values in memory.

2.Loop to find two data points one period apart:

-search until a data value in the second column is less than the threshold (Point O).

-continue searching until a data value is greater than the threshold; store its corresponding time value (Point A).

-continue searching until a number less than the threshold is found (Point B).

-continue searching until a number greater than threshold is found; store its corresponding time value (Point C). Then quit the loop.

3.Calculate the period of the waveform, being the difference between the two times (Point C – Point A).

13 THE PC TIMER 427

The program that performs the above data retrieval and data processing steps is shown in Listing 13-8 and does not need to use any of the object classes that have developed previously.

Listing 13-8 Program to determine the period of the output waveform - period.cpp

#include <iostream.h> #include <fstream.h>

void main()

 

 

 

{

 

// Pointer

to Time data

double *TimePtr;

double *DataPtr;

// Pointer

to ADC data

double MaxData = 0;

// Maximum

value of ADC data

int NumData=0;

 

// Number of data pairs in file

int i =0;

 

// Case in

initialised to 1

int Case = 1;

 

int Quit = 0;

 

// Quit = 0 means do not quit

unsigned char

Threshold;

 

double TimeA,

TimeC;

 

 

//Instantiate ifstream object (is). ifstream is("tmddata.dat");

//Read through the file to find the number of

//data pairs and the max value of ADC data. while(is)

{

is >> *TimePtr >> *DataPtr; if(!is.fail())

{

if(*DataPtr > MaxData) MaxData = *DataPtr;

NumData++;

}

}

//close input stream

is.close();

//Set Threshold based on MaxData Threshold = MaxData - 5;

//Alocate memory for Time and ADC data