Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Object Pascal: кроссплатформенные технологии > Объясните про системный таймер $0040$006C;


Автор: ausar 25.8.2008, 14:53

Привет!
Помогите разобраться с системным таймером.Никак не могу заставить работать счетчик секунд
на основе системного таймера. Вот чего я достиг.
Итак доступ непосредственно к счетчику можно получить через

Код

var i:longint absolute $0040$006C;

begin
repeat;
write(i);
inc(t)
until t=1000;
End;



Везде написано что системный таймер производит 18.2 импульсов в сек. Скажем мне необходимо чтоб таймер отсчитывал секнды. Я понимаю что можно взять начальное показание таймера затем с каждым импульсом сравнивать его не достигло ли оно разницы в 18.2 и тогда увеличивать какой нибудь счетчик.
Но никак не могу это сделать. Все время тянет на что нибудь эдакое

Код

...
begin
z:=i {захватили начальное показание счетчика i}
repeat;{поставили цикл чтобы сравнивать текущее показание с ранее захваченным}
if i:=z+182 then inc (t); {на каждом витке сравниваем не достигла ли разница 182 т.е- 10 сек. Непонятно как заставить считать по 18.2)
until t=100
End.


Ну и вполне логично что как надо не получилось. 

Автор: Snowy 25.8.2008, 15:47
А не надо считать по 18.2
Это округлённая цифра.
Считай по 55.
Счётчик увеличивается на 1 каждые 55 милисекунд.
Соответственно пройденное время будет = (i-z) * 55 миллисекунд.

Автор: ausar 27.8.2008, 07:53
Да нет мне нужно точно

Автор: ausar 3.9.2008, 10:21
Вот дошло дело и до завершения. Бьюсь вот над какой проблемой. Мне необходимо сделать часы которые при запуске перехватывают показания системных часов а потом при помощи таймера и прерываний отсчитывают время самостоятельно. В принципе проблема оказалась разрешимой. Количество импульсов - целое число т.е реально их в 1 сек полностью 18. Если так то часы будут отставать и спустя некоторое  время погрешность станет ощутимой. Но насколько я понял погрешность можно ликвидировать на каждой 5й секунде когда округленные .2 от 18.2  превратятся в 1 лишний импульс. Или яне прав? т.е если после каждой 5 сек прибавлять 1 импульс то часы должны идти отностительно ровно.

Я написал вот такое
Код

 {$M $1000,0,0}
Program q3;
Uses Crt,Dos;
Var OldVect:Procedure;
    i:longint absolute $0040:$006C;
    h,m,s,ms: word;
    cmp,ctime:longint;
    addimp:integer;


{Procedure PrintTime;
begin
write(#13,h,':',m,':',s,'[',ms,'] ');
End;}

{F+}
Procedure MyTimer; interrupt; {процедура перехвата прерывания}
begin
addimp:=0; {переменная добавляющая лишний импульс когда надо}
If i=cmp+91 then begin {если прошло 5 сек т.е 91 импульс то значит надо}
cmp:=i; 
addimp:=1; {сделали один лишний импульс}
End;
If i>ctime+18+addimp then begin {добавили лишний импульс если прошло 5 сек, или не добавили если не прошло}
ctime:=i;
inc(s);
End;
If s=60 then begin {ну а это сами часы тут все просто секунды минуты часы}
inc(m);
s:=0;
End;
If m=60 then begin
inc(h);
m:=0
End;
If h>23 then h:=0;
write(#13,h,':',m,':',s,'[',ms,'] ',addimp); {вывели на экран после каждого тика обновляем показания}
Inline ($9C);
OldVect;
End;
{F-}

begin
repeat
h:=0; m:=0; s:=0; ms:=0;
cmp:=i;
GetTime(h,m,s,ms);
until ms=0;
GetIntVec ($8, @OldVect);
SetIntVec ($8, Addr (myTimer));
Keep(0);



вроде бы теоретически все должно работать но. Почему же часы все равно через некоторое время начинают отставать?  Я сверяю с часами в нортоне т.е с ситемными часами из под дос. Может прога просто тормозит? Помогите разобраться в ситуации. 

Автор: Snowy 3.9.2008, 13:57
Цитата(ausar @  27.8.2008,  07:53 Найти цитируемый пост)
Да нет мне нужно точно
Так вот я тебе и говорю - если нужно точно, то забудь число 18.2
Точное число - 55
Каждый тик таймера = 55мс
А, если будешь использовать число 18.2, то со временем погрешность будет накапливаться, ибо, как видим, в одной секунде тиков не 18.2, а 1000мс / 55мс = 18.181818181818181818181818181818..... и т.д.
Если округлить, то получим пресловутые 18.2, но это число теоретическое. Использовать его нельзя, ибо погрешность.

Автор: ausar 3.9.2008, 15:20
Так вот в этом то и смысл. Т.е действительно тиков реально 18 но в 1 сек их 18.2. Если мы будем отрезать эти 2 десятых доли тика то получим погрешность. Вот в я и бьюсь над тем чтобы погрешность ликвидировать. Если в сек 18.2 тиков то в минуте их 1092. Если мы будем считать каждую секунду только по 18 тиков то в нашей минуте у нас будет 1080 т.е на 12 меньше чем надо. Так вот идея и состоит чтобы вставить эти 12 тиков и добиться ровно счета не на секундах (все равно не заметно) а на минутах. На каждой 5 сек мы можем добавить 1 лишний тик чтобы в конце минуты у нас получилось ровно 1092 тика. 
Почему нельзя так? Почему нельзя просто постепенно компенсировать погрешность? Я вроде бы правильно все сделал в коде. Каждые 5 сек я добавляю лишний тик за счет того что в 6й секунде не 18 тиков а 19.

Автор: Snowy 3.9.2008, 15:43
Ты читаешь, что я пишу?

В СЕКУНДЕ НЕ 18.2 ТИКА!

И не 18 и не 19 и не 548 тиков.
Тик неделим. Длина одного тика 55 милисекунд.
Под секунду его не подогнать. И 0.2 тика перекидывать бессмысленно, ибо остаток меньше, чем 0.2
Цитата(ausar @  3.9.2008,  15:20 Найти цитируемый пост)
Если в сек 18.2 тиков то в минуте их 1092.
Вот именно. Если.
В секунде 1000/55 тиков, а не 18.2. Что равно 18.(18) тика.
Если ты считаешь, что в секунде 18.2 тика, то за минуту твои расчёты будут спешить более, чем на 1 секунду.
(18.2 - 18.(18) ) * 60 = 1.(09) секунды.
Кстати, в минуте не 1092 тика, а 1090.(90), или, если округлить, то 1090.91
Поэтому ещё раз говорю. Используй длину тика, а не количество тиков в секунде.
Я же написал, как измерить количество секунд.
(текущий тик - начальный тик) * 55 div 1000
Точное число - 55. А 18.2 - это приблизительное число, с помощью которого просто пытаются объяснить в учебнике.
Утверждать, что в секунде 18.2 тика, то же самое, что утверждать,что число Пи = 3.14
Да. Число Пи приблизительно равно 3.14. Но для расчётов такой точности мало.
Просто возьми калькулятор и раздели 1000 миллисекунд (то есть секунду) на длину одного тика (55 миллисекунд). 18.2 ты никак не получишь.

Автор: ausar 3.9.2008, 17:03
Уж было закрыл тему но опять вот!

Автор: ausar 4.9.2008, 04:09
Я перестал считать по 18.2 и по 18 и по 19 и... А как посоветовал Snowy передал код и начал считать по 55. Получилось вот так

Код

 {$M $1000,0,0}
Program q3;
Uses Crt,Dos;
Var OldVect:Procedure;
    i:longint absolute $0040:$006C;
    h,m,s,ms: word;
    cmp,ctime:longint;
    addimp:integer;

Procedure PrintTime;
begin
write(#13,h,':',m,':',s,'[',ms,'] ');
End;

{F+}
Procedure MyTimer; interrupt; {процедура перехвата прерывания}
begin
If  (i-ctime)*55>1000 then begin {вот собственно и коррекция по сравнению с верхним кодом}
ctime:=i;
inc(s);
End;
If s=60 then begin {ну а это сами часы тут все просто секунды минуты часы}
inc(m);
s:=0;
End;
If m=60 then begin
inc(h);
m:=0
End;
If h>23 then h:=0;
write(#13,h,':',m,':',s,'[',ms,'] ',addimp); {вывели на экран после каждого тика обновляем показания}
Inline ($9C);
OldVect;
End;
{F-}
begin
repeat
h:=0; m:=0; s:=0; ms:=0;
cmp:=i;
GetTime(h,m,s,ms);
until ms=0;
GetIntVec ($8, @OldVect);
SetIntVec ($8, Addr (myTimer));
Keep(0);


Но это проблему не решило все равно показания моих часов постепенно начинают отличаться от системных. Что же это? Или это действительно порога так тормозит что показания начинают прыгать? Я заметил что при таком раскладе время время начинает отставать каждые 23 сек на 1 сек.

Автор: volvo877 4.9.2008, 10:06
ausar, Вот так не хочешь попробовать:
Код

{$M $1000,0,0}

Uses Crt,Dos;
Var
  OldVect: pointer;
  TimerVect: Procedure;

  hr, min, sec, hund: word;
  second_call: boolean;

Procedure PrintTime;
begin
  write(#13,hr,':',min,':',sec,'[',hund,'] ');
End;

{$F+}
Procedure MyTimer; interrupt;
begin
  if second_call then begin { <--- пропускаем каждый второй тик }

    inc(hund, 11); { 2 * 55 = 110 ms => 11 сотых, а не 5.5 }
    if hund >= 100 then begin
      dec(hund, 100); inc(sec); { <--- секунды сменились ... }

      if sec >= 60 then begin
        dec(sec, 60); inc(min);

        if min >= 60 then begin
          dec(min, 60); inc(hr);

          if hr >= 24 then dec(hr, 24);
        end;
      end;

      printtime; { ... секунды сменились, печатаем }
    end;

  end;
  Inline ($9C);
  TimerVect;

  second_call := not second_call;
end;
{$F-}

begin
  GetTime(hr,min,sec,hund);
  second_call := false; { <--- первый тик - пропускаем, второй - обрабатываем, и т.д. }

  GetIntVec ($8, @TimerVect);
  GetIntVec ($8, OldVect);
  SetIntVec ($8, Addr (myTimer));

  {
    С резидентом экспериментировать не буду, проверял обычным циклом
    Вроде все нормально...
  }

  repeat until keypressed;
  while keypressed do readkey;

  SetIntVec ($8, OldVect);
  {
    Keep(0);
  }
end.

Автор: ausar 28.11.2008, 15:49
И снова! Volvo877 твой код работает ровно. Но не пойму по какой причине примерно за 20 минут работы опять набирается погрешность примерно в 1 сек. Даже не знаю в чем причина. Пробовал запускать под голым досом, думал под виндой комп тормозит. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)