Другие языки программирования и технологии

Как реализовать таймер в TPascal'e

Олег Вернав
Олег Вернав
1 117
Доброго времени суток.

Не все так просто, DeNVeR. Этот таймер будет периодически на секунду "подвешивать" комп. Во время выполнениея процедуры delay(1000); ничего другое выполняться не будет.

А вообще, не надо реализовывать таймер в паскале. Он уже есть и называется системный таймер. Надо просто уметь им пользоваться. Идея состоит в перехвате прерывания по таймеру, которое возникает примерно 18,2 раза в секунду (период 55 миллисекунд) . Сначала объявляются переменные

var
TimerOn : Boolean; {флаг включения таймера}
OldTimer : procedure; {переменная для хранения адреса процедуры обработки прерывания по таймеру}
Period : Integer; {период нашего таймера}
TicCount : Integer; {счетчик "тиков" системного таймера}

Затем объявляется процедура обработки прерывания по таймеру.

{$F+}
procedure MyTimerInt; interrupt;
begin
if TimerOn then begin
if TicCount = Period then какое-то действие, например присвоение значения перемнной
{или так}
if TicCount = 1 then какое-то действие, например присвоение значения перемнной
Dec(TicCount);
if TicCount = 0 then TicCount := Period;
end
else TicCount := Period;
Inline($9C);
OldTimer; {вызов старого обработчика чтобы, в частности, правильно часы шли}
end;
{$F-}

И еще парочка для удобства

{процедура установки нового обработчика прерывания по таймеру}
procedure NewTimerInt;
begin
GetIntVec($8, @OldTimer);
SetIntVec($8, @MyTimerInt);
end;

{процедура восстановления старого обработчика}
procedure RestoreTimerInt;
begin
SetIntVec($8, @OldTimer);
end;

А затем где-то в программе выполняется вызов, который заменяет старый обработчик на ваш, который будет выыполнять нужные вам действия.

NewTimerInt;

И когда надо запустить таймер устанавливается значение периода

Period := Round(18.2 * число секунд) ;

и переменной TimerOn присваивается значение True, в результате чего будет выполняться определенное в обработчике действие. Если это присвоение значения переменной, то в основной программе анализируется эта переменная и при ее определенном значении делается вывод, что время для чего-то наступило. Затем переменная сбрасывается и все повторяется сначала. Чтобы выключить таймер делают TimerOn := False;

Перед выходом из программы восстанавливается старое прерывание по таймеру

RestoreTimerInt;

Вроде все.

Удачи!
Gallor
Gallor
59 612
Лучший ответ
Добавлю к посту Gennady - в процедуре обработки прерывания нужно стараться выполнять минимум действий, скажем только лишь взвести флажок "было прерывание". Основную работу нужно делать вне этой процедуры, например в цикле проверяя значение флажка, и как только он взвелся, делать нужную работу, предварительно сбросив флажок.
Program tim;

uses crt;
var timm:integer;

Procedure DecTimer(inp:integer);
begin
dec(inp,1);
delay(1000);
writeln(inp);
end;

begin
timm:=100;
repeat
dectimer(timm);
{тут можно размещать дополнительный код программы}
until timm<0;
end.
Олег Вернав Сорри. Может не втыкаю? Но мне нужна такая фишка. Я ставлю точку начала отсчёта, а потом смотрю сколько времени прошло с начала запуска. Как вариант можно получать системное время в начале выполнения и во время проверки. Меня интересовал вопрос о существовании готовой модульной функции.
Спасибо за ответ