Файл: Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 14.06.2025

Просмотров: 3575

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

408 13 THE PC TIMER

7

6

5

4

3

2

1

0

0

1

0

0

0

0

0

1

0

1

0

0

1

1

1

0

0

1

0

1

0 0

01

10

11

0

1

0

1

Meaning

Binary counting BCD Counting Mode 0 selected Mode 1 selected Mode 2 selected Mode 3 selected Mode 4 selected Mode 5 selected undefined

Read/Load status – MSB only Read/Load status – LSB only Read/Load Status – LSB first, then MSB New initial count loading finished

New initial count loading in progress Timer output signal status – LOW Timer output signal status – HIGH

Figure 13-2 Description of the returned counter status byte.

13.3 Programming the Timer

Programs will be developed in the coming sections that take advantage of the PC timer’s accurate timing. We will start by developing an object class for the PC timer. Note that although the timer hardware is independent of the parallel port hardware, the object classes we created in the preceding chapters can be used with the new timer object class developed in this chapter.

Programs have been developed to accurately measure time periods, measure a persons reflexes, and to generate a time-base for an earlier program that displayed the VCO output on-screen (see Chapter 10). The final program digitises an electrical waveform generated on the interface board, and saves the digitised values for later analysis.

As explained previously, the PC’s three timers are connected to a clock signal having a frequency of 1.1932 MHz. Their counters can be loaded with a maximum value of 65,535 to produce a maximum time of 54.9 ms per countdown cycle. If we are to measure times greater than 54.9 ms, we must monitor and account for the number of down-counts. Each countdown of Timer 0 is referred to as a ‘tick’. A special region of memory known as BIOS is used to store the number of ticks since mid-night. BIOS is the abbreviation for the PC’s Basic Input Output System. It is a segment of software that predominantly interacts with hardware devices to carry


13 THE PC TIMER 409

out low-level tasks. Like many operating systems, the PC’s operating system suffers from poor determinism (determinism is the term used to describe the ability of software to carry out tasks on time), and other latencies (time delays when actioning requests – some generated by hardware). As a result of these latencies, the tick count does not always get updated immediately, and so the BIOS tick count cannot be used reliably. We need to devise a reliable method to monitor and account for the number of tick counts so we can use this value in conjunction with the timer count value to measure time periods greater than one full timer countdown cycle. We will use Timer 0 for our time reference since it operates in a suitable mode.

13.3.1 Reading Timer 0 Count Value and Ticks

To read the number of counts corresponding to a given instant in time, we must read the timer ticks and also the contents of the Timer 0 counter. Section 13.2.4 describes how to latch the count value of Timer 0 (a snap shot taken) by issuing a read-back command. The latched data can be read later by reading the output register of Timer 0.

Before starting to program the timers, it is important to be aware that we will not adhere to the strict practice of structured procedure abstraction (use of functions). This will allow us to produce programs that execute fast and provide satisfactory accuracy when reading the timer. Additional time would be consumed if we called a function within one of the member functions of our PCTimer class.

13.4 The Object Class PCTimer

We will develop a class to provide a means of measuring time and generating time delays. To do this the class needs functions that perform the following tasks:

ξ

Set a ‘zero’ time reference (this does not mean clearing the hardware timer

in the PC).

ξ

Generate a time delay of a specified value.

ξ

Read the current time.

The definition of the PCTimer class that has the above capabilities is shown in Listing 13-1.

Listing 13-1 The PCTimer class - pctimer.h.

#ifndef PctimerH #define PctimerH

class PCTimer

{

410 13 THE PC TIMER

private:

unsigned int InitCount; unsigned long TickCount; unsigned int LastCount;

public:

PCTimer();

void ResetTimer();

void Delay(const double& milliseconds); double ReadTimer();

void UpdateTicks();

};

#endif

Setting ‘Zero’ Time

The basic requirement when making use of time is to have a reference of ‘zero’ time. The data member InitCount is used to store the count value (remaining before the next tick) that corresponds to this ‘zero time’ as shown in Figure 13-4. This value of InitCount is established at the time of instantiating the PCTimer object, and can also be re-established by calling the member function

ResetTimer().

The ResetTimer() function can be used at any time to create a ‘zero time’ reference. It latches and reads Timer 0, then stores the count value into the data members InitCount and LastCount. LastCount is to temporarily store the timer’s last count value so the other member functions can detect the next tick as described in the following text. The number of ticks that have occurred, stored in data member TickCount, is then reset to zero.

Accounting for Timer Ticks

As explained previously, to determine the exact time that corresponds to any given instant, we need to know the number of timer ticks elapsed since the ‘zero’ time reference was created using Timer 0. We must monitor each countdown of Timer 0 to prevent any ticks being missed. The three member functions; Delay(), ReadTimer(), and UpdateTicks(), all need to track and record the number of ticks that take place during their operation. Figure 13-3 shows three different scenarios when monitoring timer ticks, explained as follows.

The counter is first read and its count value stored in the member variable LastCount. A short time later during execution of the program, the counter is read again to test if a tick has passed, and this count value is stored in the variable Count. Case (a) shows the two reads of the counter occurring within a countdown cycle – no tick has occurred. In this case the variable Count is not greater than the variable LastCount. Case (b) shows a new countdown cycle underway when the counter is read for the second time. In this case a tick has occurred; Count is greater than LastCount. Case (c) shares the same result as case (a) in that


13 THE PC TIMER 411

Count is not greater than the variable LastCount. When using the same criteria to test for a tick as used for case (a), we will make an incorrect evaluation that a tick has not occurred because the two reads of the counter in case (c) are made more than a full countdown period apart (and Count < LastCount ).

65,535

65,535

Count

LastCount

Count

LastCount

0

0

0

Time

0

Time

(a) Tick has not occurred

(b) Tick has occurred

Count is not ! LastCount

Count ! LastCount

65,535 LastCount

Count

0

0

Time

(c)

Tick is missed

Read period ! 1 countdown (54.9 ms)

Figure 13-3 Accounting for timer ticks.

Evaluating Elapsed Time

At the start of the timing process, the counter is latched, read, and its value is stored in the data member InitCount. This value represents ‘zero’ time, and is the number of counts remaining before the next tick as shown in Figure 13-4.

Tick occurred

Tick occurred

Tick occurred

Tick occurred

(0

65,535)

(0

65,535)

(0

65,535)

(0

65,535)

65,535

65,535

Count

InitCount, LastCount

0

‘zero time’

0

Current Time

0

0

Time

Elapsed Time

Figure 13-4 Evaluation of the elapsed time.

At the end of the ‘Elapsed Time’ the timer is read again and its value stored in the variable Count. The number of timer counts since the last tick can be evaluated by subtracting Count from 65,535 (i.e. 65,535 – Count). The number of tick counts within the elapsed time is stored in TickCount. Therefore, the total counts corresponding to the elapsed time is:

TotalCounts = InitCount + (TickCount-1)*65535 + 65535–Count;

Which can be written as:


412 13 THE PC TIMER

TotalCounts = InitCount + TickCount*65535 – Count;

This is then easily converted into a value of time by knowing the frequency of the PC’s clock that drives the counter.

The purpose and operation of the member functions of this class are explained as follows.

The PCTimer() function shown in Listing 13-2 is the constructor for the PCTimer object class. The constructor allocates space for all data members of the class and then takes an initial reading of the timer for the ‘zero time’ reference. Obtaining the ‘zero time’ reference is performed within the body of the constructor by using the function ResetTimer().

Listing 13-2 The constructor of the PCTimer class.

PCTimer::PCTimer()

{

ResetTimer();

}

The ReadTimer() function determines the total number of counts since zero time until the instant ReadTimer() is called. The total number of counts is calculated as described above. Finally, the total count value is converted into a value of time in milliseconds and a value of type double is returned. The ReadTimer() function does not call another member function to avoid added delays. Instead, all the code it needs is placed within its body.

The Delay() function is used to generate a specified delay that is passed to it as a parameter in milliseconds. When called, it reads the timer once to determine the start of the delay period, being the current number of counts since zero time. Then it adds the number of counts since zero time to the number of counts corresponding to the specified delay. The timer is then read repeatedly until the number of counts since zero time is equal to the total number of counts evaluated above. At this point in time the delay will expire.

The UpdateTicks() function simply performs the task of quickly monitoring the tick status during down-counting (faster than the ReadTimer() function). It does this using the same method as employed in the other member functions of the PCTimer class. For the proper functioning of the PCTimer class, the Update() function must be called at least once within a countdown, preferably every 40 ms. This completes the development of our PCTimer object class. The function file pctimer.cpp that contains these functions is given in Listing 13-3.

Listing 13-3 Member functions of the PCTimer class - pctimer.cpp.

#include <dos.h>

13 THE PC TIMER 413

#include "pctimer.h"

PCTimer::PCTimer()

{

ResetTimer();

}

void PCTimer::ResetTimer()

{

//Latch Timer 0 outportb(0x43, 0xD2);

//Read latched Count

LastCount = InitCount = inportb(0x40)+inportb(0x40)*256; TickCount = 0; // Initialise to zero.

}

double PCTimer::ReadTimer()

{

double Time;

unsigned long TotalCounts; unsigned int Count;

//Latch Timer 0. outportb(0x43, 0xD2);

//Read latched Count

Count = inportb(0x40) + inportb(0x40)*256;

if(Count > LastCount) TickCount++;

LastCount = Count;

TotalCounts = ((long)InitCount + TickCount*65535L -(long)Count);

Time = (TotalCounts/1.1932)/1000.0; return Time; // In milliseconds.

// return TotalCounts;

}

void PCTimer::Delay(const double& milliseconds)

{

unsigned int Count;

long StartCount, DelayCount, EndCount, TotalCount;