41413 THE PC TIMER
//Latch Timer 0. outportb(0x43, 0xD2);
//Read latched CountOne.
Count = inportb(0x40) + inportb(0x40)*256;
if(Count > LastCount) TickCount++;
LastCount = Count;
StartCount = ((long)InitCount + TickCount*65535L
-(long) Count);
DelayCount = (long) (milliseconds*1.1932*1000);
EndCount = StartCount + DelayCount;
//Repeat a loop for the duration of the period. do
{
//Latch Timer 0. outportb(0x43, 0xD2);
//Read latched CountOne.
Count = inportb(0x40) + inportb(0x40)*256;
if(Count > LastCount) TickCount++;
LastCount = Count;
TotalCount = ((long)InitCount + TickCount*65535L -(long)Count);
}
while (TotalCount < EndCount);
}
void PCTimer::UpdateTicks()
{
unsigned int Count;
//Latch Timer 0. outportb(0x43, 0xD2);
//Read latched Count.
Count = inportb(0x40) + inportb(0x40)*256;
if(Count > LastCount) TickCount++;
LastCount = Count;
}
As mentioned previously, it is essential that when using any of the member functions of the class that they are called within a countdown cycle. The class will function best if the PC’s interrupts are disabled, however, we have chosen to leave all interrupts active to avoid unnecessary complexity in our programs. The effect of these interrupts may cause small and unforeseen time delays.
For example; An attempt is made to read the timer at a particular instant using the ReadTimer() function. If the timer interrupt also occurs at this time, it will force the function ReadTimer() to wait until the timer interrupt has been serviced. This delay will cause ReadTimer() to return a count value that is greater than the instantaneous value when the call to the ReadTimer() function was initiated. The effect of interrupts is demonstrated in one of the programs that uses a member function of the PCTimer object.
NOTE
Although updating the tick count is handled automatically by the Delay() function while it is active, the ReadTimer() and UpdateTicks() functions will only perform this task at the instant they are called. Therefore, if time
periods need to be measured, ensure that functions ReadTimer() and
UpdateTicks() are called repetitively within a full timer countdown period
(54.9 ms) to correctly monitor and update the tick count value.
13.5 Measurement of Time
The PCTimer object class will be used to demonstrate the measurement of realtime. As explained earlier, measurement of time periods can be affected by the execution of interrupt routines. The following program will allow us to observe the delays that can be generated by the various interrupt service routines executing in the PC. The disable() function can be called to stop all interrupts (disabling most of the PC’s peripherals, including the keyboard). Therefore, make sure that the interrupts are disabled for a minimum length of time! Calling the enable() function re-enables the interrupts and allows the PC’s peripherals to resume operation. The program that measures time is shown in Listing 13-4.
Listing 13-4 Measurement of time – time.cpp.
#include <iomanip.h> #include <math.h> #include <iostream.h> #include <conio.h> #include <dos.h>
#include "pctimer.h"
main()
{
PCTimer T;
double TimeValue[1000]; int i;
//disable();
for(i = 0; i < 1000; i++)
{
for(int j = 0; j < 50; j++) sin(j);
TimeValue[i] = T.ReadTimer();
}
enable();
for(i = 1; i < 1000; i++)
{
cout << i << '\t';
cout << setprecision(3) << TimeValue[i] << '\t';
cout << setprecision(3) << (TimeValue[i] - TimeValue[i-1])<< '\t';
cout << endl;
if( i % 20 == 0)
{
cout << "Press a key for more ... "; getch();
cout << endl;
}
}
return 0;
}
Executable File Generation
|
Required Files |
|
Listing No. |
|
Project File Contents |
|
|
pctimer.cpp |
|
Listing 13-3 |
|
pctimer.cpp |
|
|
|
|
|
|
pctimer.h |
|
Listing 13-1 |
|
time.cpp |
|
|
time.cpp |
|
Listing 13-4 |
|
|
|
The program measures the time consumed by each iteration of a for loop that executes 1000 times. Within this for loop is another for loop that repeatedly executes the sin() function 50 times for no real purpose except to waste time. You can alter the number of times the sin() function executes to change the time spent by each iteration of the external for loop. The ReadTimer() function is called within each iteration to read the time and store the time values in an array. Note that the UpdateTicks() function does not need to be called since the ReadTimer() function monitors and accounts for timer ticks, and importantly, the for loop will execute in less than a full countdown period.
The time value and also the time difference between two consecutive readings of the timer are displayed on-screen 20 lines at a time. Interrupts will have the effect of adding time delays of varying value to the time taken to perform the calculations. Therefore, if interrupts are active (not disabled), calculations will take different periods of time, and it is these differences that the program is displaying. If the interrupts are disabled, calculation times will be uniform. Therefore, any irregularities in the times displayed in the third column will be caused by interrupts. You can run the program twice, once with the interrupts disabled and then with the interrupts enabled to observe these effects. These results should provide some insight into the effect of interrupts when measuring time.
13.6 Reflex Measurement
In this section we will use the interface board to measure a person’s hand reflexes. A program has been provided that will light up a set of LEDs on the interface board after a random time delay. The person under test will react and press the button switch on the board in response to the LEDs lighting up. The delay in time from the LEDs lighting up and the press of the button switch is a measure of a person’s reflexes. Listing 13-5 shows the program that performs the reflex measurement.
Listing 13-5 Reflex measurement – reflex.cpp.
#include <iomanip.h> #include <conio.h> #include <iostream.h> #include <stdlib.h>
#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;
}
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.