unit Delay;
{-----------------------------------------------------------------}
{ Definovane spozdeni, ktere funguje i na }
{ vykonnejsich pocitacich }
{ }
{ Verze 1.0 portovano by miho 96 }
{ 1.1 popora kratkych casu miho 98 }
{ 1.2 podpora rychlych CPU ( rozsireni DelayCnt1 na DWORD ) }
{-----------------------------------------------------------------}
{$I-,S-}
interface
procedure xDelay(MS: Word);
{-- cas uveden v milisekundach --}
procedure xDelayMicro(MicroS: Word);
{-- cas uveden v mikrosekundach --}
{ POZOR: Casy jsou vzdy o neco delsi a za normalnich podminek }
{ je cas delsi radove o nekolik mikrosekund }
{ ( na PC Pentium 75 to dela cca 6us ). }
implementation
var DelayCnt1:longint; { kalibrace casu po 1 ms }
DelayCnt55:longint; { totez pred vydelenim 55 }
procedure DelayLoop;
begin
asm
@@Loop: SUB AX,1 { DX:AX - pocitadlo DWORD }
SBB DX,0 { dekrement }
JC @@End { doteklo }
CMP BL,ES:[DI] { pri uplynuti tiku ( 55ms ) }
JE @@Loop { taky koncim }
@@End:
end;
end;
procedure Initialize;
{-- inicializace - kalibrace casu --}
begin
asm
MOV AX,40H { adresa bunky BIOS DATA s tiky }
MOV ES,AX { po 55 ms aktualizuje BIOS }
MOV DI,6CH
MOV BL,ES:[DI]
@@Wait: CMP BL,ES:[DI]
JE @@Wait { pockej na cely tik }
MOV BL,ES:[DI] { schovej si tik do BL }
MOV AX,-28 { piskvorcova konstanta ? asi }
CWD
CALL DelayLoop { pockej na konec tiku BL }
NOT AX { a pocitej cas v DS:AX}
NOT DX
MOV word ptr [DelayCnt55],AX { uschovej kalibraci }
MOV word ptr [DelayCnt55+2],DX
end; {asm}
DelayCnt1:=DelayCnt55 div 55; { uschovej kalibraci 1 ms }
end; {Initialize}
procedure xDelay(MS: Word);
{-- proved standardni spozdeni merene v milisekundach --}
begin
asm
MOV CX,MS { pocet milisekund }
JCXZ @@End { nulova hodnota - hned konci }
MOV AX,40H { adresa BIOS COM port - to je }
MOV ES,AX { jakakoli bunka, ktera se v }
XOR DI,DI { v provozu nemeni aby se netestoval }
MOV BL,ES:[DI] { casovac a presto mohla byt }
@@Loop: MOV AX,word ptr [DelayCnt1] { procedura DelayLoop stejna }
MOV DX,word ptr [DelayCnt1+2] { DX:AX kalibracni konsatnta }
CALL DelayLoop { pro spozdeni 1 ms }
LOOP @@Loop
@@End:
end; {asm}
end; {xDelay}
procedure xDelayMicro(MicroS: Word);
{-- procedura pro spozdeni zadavane v mikrosekundach --}
label Error;
begin {-- prepocitej zadany cas na pocet cyklu --}
asm
{-- DWORD * WORD / WORD -> DWORD --}
SUB DX,DX
MOV AX,WORD PTR[DelayCnt55+2]
MOV BX,55000
MOV CX,MicroS
DIV BX
PUSH DX
MUL CX
MOV DI,DX
AND DX,DX
POP DX
JNZ Error
MOV AX,WORD PTR[DelayCnt55]
DIV BX
PUSH DX
MUL CX
MOV SI,AX
ADD DI,DX
POP AX
JC Error
MUL CX
DIV BX
ADD SI,AX
ADC DI,0
PUSH SI
PUSH DI
{-- vlastni spozdeni --}
MOV AX,40H { opet konstantni bunka }
MOV ES,AX
XOR DI,DI
MOV BL,ES:[DI]
POP DX { DX:AX cas v poctech cyklu }
POP AX
CALL DelayLoop
end; {asm}
exit;
asm
Error: MOV AX,0FFFFH
MOV DX,AX
CALL DelayLoop
end; {asm}
end;
begin Initialize; { udelej kalibraci }
end.