中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » 一直存在的疑问:PC上8253计时器的精确频率到底是多少?
作者:
标题: 一直存在的疑问:PC上8253计时器的精确频率到底是多少? 上一主题 | 下一主题
zyl910
中级用户





积分 282
发帖 126
注册 2006-5-17
状态 离线
『楼 主』:  一直存在的疑问:PC上8253计时器的精确频率到底是多少?

PC机上8253计时器芯片的精确的输入频率到底是多少?


  很多书上说PC机的8253的计时器#0的输出频率是每秒18.2次(每隔55ms触发一次),但都说这个只是约值,精确值有很长一串小数。计算机应该是靠整数运算的,那些小数值应该只是换算成现实时间的结果。所以我想知道精确的频率,于是查找了大量的资料,结果发现都有一点出入:
1.许多书上所说的(计数器#0)精确值:
  F: 每秒18.2064819336次
  T: 每隔54.925ms。
2.Terrv Dettmann《DOS Programmer's Reference》:
  H: 由系统时钟每秒大约调用18.2次(每小时65536次)。
  D: int 1Ah的00h功能: 该中断获取系统时钟计数器,该计数器从零点开始,每秒计数18.2065次。从零点(midnight)开始的一整天共需计86400秒,这段时间内的计数次数(时钟计数1573040次,经过的时间为86399.9129秒)。
3.Mazid《汇编语言、设计与接口技术》:8284芯片连接到一个14.31818MHz的晶振源,输出的Clr引脚是(8088中)CPU、内存(系统总线)的主频,1/3分频,4.772776MHz。PClk接8253/54计时器,1/6分频,2.386383MHz。在8284与8253之间存在一个72LS175的D触发器,所以频率又除以了2,1.1931817MHz。
4.在某些接口技术的书上说晶振源的频率周期是70ns,与内存速度匹配。
5.在很多计算机上,QueryPerformanceFrequency(Win32 API)的返回值是3579545。3579545 * 4 = 14318180,与3一致。



常数分析
~~~~~~~~

  现在对这些常数进行计算分析:

[1F]第1种,根据频率(每秒18.2064819336次)

晶振源频率:18.2064819336Hz * 65536 * 12 = 14,318,160.0000049152Hz
周期:1s / 14,318,160.0000049152Hz = 0.000000069841376266200176256402804053989s = 69.841376266200176256402804053989ns

8253输入频率:18.2064819336Hz * 65536 = 1,193,180.0000004096Hz
周期:1s / 1,193,180.0000004096Hz = 0.00000083809651519440211507683364864787s = 838.09651519440211507683364864787ns

计时器#0输出频率:18.2064819336Hz
周期:1s / 18.2064819336Hz = 0.054925493219780337013675369997787s = 54.925493219780337013675369997787ms

计时器#0触发65536次:(1s / 18.2064819336Hz) * 65536 = 65536s / 18.2064819336Hz = 3599.597123651524166528229048175s
计时器#0触发1573040次:(1s / 18.2064819336Hz) * 1573040 = 1573040s / 18.2064819336Hz = 86399.997854443261335991904021318s


[1T]第1种,根据周期(每隔54.925ms)

晶振源频率:(1s / 54.925ms) * 65536 * 12 = (65536 * 12)s / 0.054925s = 14,318,288.575329995448338643604916Hz
周期:54.925ms / (65536 * 12) = 0.000000069840749104817708333333333333333s = 69.840749104817708333333333333333ns

8253输入频率:(1s / 54.925ms) * 65536 = 65536s / 0.054925s = 1,193,190.7146108329540282203004096Hz
周期:54.925ms / 65536 = 0.0000008380889892578125s = 838.0889892578125ns

计时器#0输出频率:1s / 54.925ms = 18.206645425580336822940373236231Hz
周期:54.925ms

计时器#0触发65536次:54.925ms * 65536 = 3599.5648s
计时器#0触发1573040次:54.925ms * 1573040 = 86399.222s



[2H]第2种,根据小时(每小时65536次)

晶振源频率:1s / (3600s / 65536 / 65536 / 12) = (65536 * 65536 * 12)s / 3600s = 14,316,557.653333333333333333333333Hz
周期:3600s / 65536 / 65536 / 12 = 3600s / (65536 * 65536 * 12) = 0.000000069849193096160888671875s = 69.849193096160888671875ns

8253输入频率:1s / (3600s / 65536 / 65536) = (65536*65536)s / 3600s = 1,193,046.4711111111111111111111111Hz
周期:3600s / 65536 / 65536 = 3600s / (65536 * 65536) = 0.0000008381903171539306640625s = 838.1903171539306640625ns

计时器#0输出频率:1s / (3600s / 65536) = 65536s / 3600s = 18.204444444444444444444444444444Hz
周期:3600s / 65536 = 0.054931640625s = 54.931640625ms

计时器#0触发65536次:3600s
计时器#0触发1573040次:(3600s / 65536) * 1573040 = (3600s * 1573040) / 65536 = 86409.66796875s


[2D]第2种,根据天(时钟计数1573040次,经过的时间为86399.9129秒)

晶振源频率:1s / (86399.9129s / 1573040 / 65536 / 12) = (1573040 * 65536 * 12)s / 86399.9129s = 14,318,174.078622248240715529702808Hz
周期:86399.9129s / 1573040 / 65536 / 12 = 86399.9129s / (1573040 * 65536 * 12) = 0.000000069841307593336928084579328349353s = 69.841307593336928084579328349353ns

8253输入频率:1s / (86399.9129s / 1573040 / 65536) = (1573040 * 65536)s / 86399.9129s = 1,193,181.1732185206867262941419007Hz
周期:86399.9129s / 1573040 / 65536 = 86399.9129s / (1573040 * 65536) = 0.00000083809569112004313701495194019224s = 838.09569112004313701495194019224ns

计时器#0输出频率:1s / (86399.9129s / 1573040) = 1573040s / 86399.9129s = 18.206499835487681377049165983592Hz
周期:86399.9129s / 1573040 = 0.054925439213243147027411890352439s = 54.925439213243147027411890352439ms

计时器#0触发65536次:(86399.9129s / 1573040) * 65536Hz = (86399.9129s * 65536) / 1573040 = 3599.5935842791028835884656461374s
计时器#0触发1573040次:86399.9129s



[3]第3种(8284芯片连接到一个14.31818MHz的晶振源)

晶振源频率:14.31818MHz = 14,318,180Hz
周期:1s / 14,318,180Hz = 0.000000069841278710003645714748662190306s = 69.841278710003645714748662190306ns

8253输入频率:14,318,180Hz / 12 = 1,193,181.6666666666666666666666667Hz
周期:1s / (14,318,180Hz / 12) = 12s / 14,318,180Hz = 0.00000083809534452004374857698394628368s = 838.09534452004374857698394628368ns

计时器#0输出频率:14,318,180Hz / 12 / 65536 = 14,318,180Hz / (12 * 65536) = 18.206507364908854166666666666667Hz
周期:1s / (14,318,180Hz / 12 / 65536) = (12 * 65536)s / 14,318,180Hz = 0.054925416498465587106741219903647s = 54.925416498465587106741219903647ms

计时器#0触发65536次:(1s / (14,318,180Hz / 12 / 65536)) * 65536 = (12 * 65536 * 65536)s / 14,318,180Hz = 3599.5920956434407166273925876054s
计时器#0触发1573040次:(1s / (14,318,180Hz / 12 / 65536)) * 1573040 = (12 * 65536 * 1573040)s / 14,318,180Hz = 86399.877168746307142388208557233s


[4]第4种(晶振源的频率周期是70ns,与内存速度匹配)

晶振源频率:1s / 0.00000007s = 14,285,714.285714285714285714285714Hz
周期:70ns = 0.00000007s

8253输入频率:1s / (0.00000007s * 12) = 1,190,476.1904761904761904761904762Hz
周期:0.00000007s * 12 = 0.00000084s = 840ns

计时器#0输出频率:1s / (0.00000007s * 12 * 65536) = 18.165225074404761904761904761905Hz
周期:0.00000007s * 12 * 65536 = 0.05505024s = 55.05024ms

计时器#0触发65536次:(0.00000007s * 12 * 65536) * 65536 = 3607.77252864s
计时器#0触发1573040次:(0.00000007s * 12 * 65536) * 1573040 = 86596.2295296s



总表
~~~~

  晶振源频率(Hz):
1F: 14,318,160.0000049152
1T: 14,318,288.575329995448338643604916
2H: 14,316,557.653333333333333333333333
2D: 14,318,174.078622248240715529702808
3 : 14,318,180
4 : 14,285,714.285714285714285714285714

  晶振源周期(ns):
1F: 69.841376266200176256402804053989
1T: 69.840749104817708333333333333333
2H: 69.849193096160888671875
2D: 69.841307593336928084579328349353
3 : 69.841278710003645714748662190306
4 : 70

  8253输入频率(Hz):
1F: 1,193,180.0000004096
1T: 1,193,190.7146108329540282203004096
2H: 1,193,046.4711111111111111111111111
2D: 1,193,181.1732185206867262941419007
3 : 1,193,181.6666666666666666666666667
4 : 1,190,476.1904761904761904761904762

  8253输入周期(ns):
1F: 838.09651519440211507683364864787
1T: 838.0889892578125
2H: 838.1903171539306640625
2D: 838.09569112004313701495194019224
3 : 838.09534452004374857698394628368
4 : 840

  计时器#0输出频率(Hz):
1F: 18.2064819336
1T: 18.206645425580336822940373236231
2H: 18.204444444444444444444444444444
2D: 18.206499835487681377049165983592
3 : 18.206507364908854166666666666667
4 : 18.165225074404761904761904761905

  计时器#0输出周期(ms):
1F: 54.925493219780337013675369997787
1T: 54.925
2H: 54.931640625
2D: 54.925439213243147027411890352439
3 : 54.925416498465587106741219903647
4 : 55.05024

  计时器#0触发65536次(s):
1F: 3599.597123651524166528229048175
1T: 3599.5648
2H: 3600
2D: 3599.5935842791028835884656461374
3 : 3599.5920956434407166273925876054
4 : 3607.77252864

  计时器#0触发1573040次(s):
1F: 86399.997854443261335991904021318
1T: 86399.222
2H: 86409.66796875
2D: 86399.9129
3 : 86399.877168746307142388208557233
4 : 86596.2295296



结论
~~~~

  个人认为最可信的是《汇编语言、设计与接口技术》上的说法,晶振源频率为14,318,180Hz,因为它跟许多数字吻合。



PS: 我一直存在这个疑问,但是一直没有去研究。直到前两天看到风云的一篇文章《不太精准的时钟》(http://blog.codingnow.com/2006/05/iaeeoeo.html)后,才认识到这个问题的严重性,引起我关注这个问题。

[ Last edited by zyl910 on 2006-6-3 at 12:44 ]



人类存在的目的就是试图理解人类为何存在
2006-6-3 12:40
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
Scott0902
中级用户





积分 466
发帖 237
注册 2005-10-12
状态 离线
『第 2 楼』:  

深奥……

2006-6-3 14:03
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
zyl910
中级用户





积分 282
发帖 126
注册 2006-5-17
状态 离线
『第 3 楼』:  

刚才又翻了一下《图形程序开发人员指南(Michael Abrash's Graphics Programming Black Book Special Editior)》的“Zen timer”,发现该代码采用的(输入频率周期)是0.8381ms(ZTimerReport函数):
;
; *** Listing 3-1 ***
;
; The precision Zen timer (PZTIMER.ASM)
;
; Uses the 8253 timer to time the performance of code that takes
; less than about 54 milliseconds to execute, with a resolution
; of better than 10 microseconds.
;
; By Michael Abrash
;
; Externally callable routines:
;
;  ZTimerOn: Starts the Zen timer, with interrupts disabled.
;
;  ZTimerOff: Stops the Zen timer, saves the timer count,
;        times the overhead code, and restores interrupts to the
;        state they were in when ZTimerOn was called.
;
;  ZTimerReport: Prints the net time that passed between starting
;        and stopping the timer.
;
; Note: If longer than about 54 ms passes between ZTimerOn and
;        ZTimerOff calls, the timer turns over and the count is
;        inaccurate. When this happens, an error message is displayed
;        instead of a count. The long-period Zen timer should be used
;        in such cases.
;
; Note: Interrupts *MUST* be left off between calls to ZTimerOn
;        and ZTimerOff for accurate timing and for detection of
;        timer overflow.
;
; Note: These routines can introduce slight inaccuracies into the
;        system clock count for each code section timed even if
;        timer 0 doesn't overflow. If timer 0 does overflow, the
;        system clock can become slow by virtually any amount of
;        time, since the system clock can't advance while the
;        precison timer is timing. Consequently, it's a good idea
;        to reboot at the end of each timing session. (The
;        battery-backed clock, if any, is not affected by the Zen
;        timer.)
;
; All registers, and all flags except the interrupt flag, are
; preserved by all routines. Interrupts are enabled and then disabled
; by ZTimerOn, and are restored by ZTimerOff to the state they were
; in when ZTimerOn was called.
;

Code        segment word public 'CODE'
        assume        cs:Code, ds:nothing
        public        ZTimerOn, ZTimerOff, ZTimerReport

;
; Base address of the 8253 timer chip.
;
BASE_8253                equ        40h
;
; The address of the timer 0 count registers in the 8253.
;
TIMER_0_8253                equ        BASE_8253 + 0
;
; The address of the mode register in the 8253.
;
MODE_8253                equ        BASE_8253 + 3
;
; The address of Operation Command Word 3 in the 8259 Programmable
; Interrupt Controller (PIC) (write only, and writable only when
; bit 4 of the byte written to this address is 0 and bit 3 is 1).
;
OCW3                        equ        20h
;
; The address of the Interrupt Request register in the 8259 PIC
; (read only, and readable only when bit 1 of OCW3 = 1 and bit 0
; of OCW3 = 0).
;
IRR                        equ        20h
;
; Macro to emulate a POPF instruction in order to fix the bug in some
; 80286 chips which allows interrupts to occur during a POPF even when
; interrupts remain disabled.
;
MPOPF macro
        local        p1, p2
        jmp short p2
p1:        iret                        ;jump to pushed address & pop flags
p2:        push        cs                ;construct far return address to
        call        p1                ; the next instruction
        endm

;
; Macro to delay briefly to ensure that enough time has elapsed
; between successive I/O accesses so that the device being accessed
; can respond to both accesses even on a very fast PC.
;
DELAY        macro
        jmp        $+2
        jmp        $+2
        jmp        $+2
        endm

OriginalFlags                db        ?        ;storage for upper byte of
                                        ; FLAGS register when
                                        ; ZTimerOn called
TimedCount                dw        ?        ;timer 0 count when the timer
                                        ; is stopped
ReferenceCount                dw        ?        ;number of counts required to
                                        ; execute timer overhead code
OverflowFlag                db        ?        ;used to indicate whether the
                                        ; timer overflowed during the
                                        ; timing interval
;
; String printed to report results.
;
OutputStr        label        byte
                db        0dh, 0ah, 'Timed count: ', 5 dup (?)
ASCIICountEnd        label        byte
                db        ' microseconds', 0dh, 0ah
                db        '$'
;
; String printed to report timer overflow.
;
OverflowStr        label        byte
        db        0dh, 0ah
        db        '****************************************************'
        db        0dh, 0ah
        db        '* The timer overflowed, so the interval timed was  *'
        db        0dh, 0ah
        db        '* too long for the precision timer to measure.     *'
        db        0dh, 0ah
        db        '* Please perform the timing test again with the    *'
        db        0dh, 0ah
        db        '* long-period timer.                               *'
        db        0dh, 0ah
        db        '****************************************************'
        db        0dh, 0ah
        db        '$'

;********************************************************************
;* Routine called to start timing.                                    *
;********************************************************************

ZTimerOn        proc        near

;
; Save the context of the program being timed.
;
        push        ax
        pushf
        pop        ax                        ;get flags so we can keep
                                        ; interrupts off when leaving
                                        ; this routine
        mov        cs:[OriginalFlags],ah        ;remember the state of the
                                        ; Interrupt flag
        and        ah,0fdh                 ;set pushed interrupt flag
                                        ; to 0
        push        ax
;
; Turn on interrupts, so the timer interrupt can occur if it's
; pending.
;
        sti
;
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
; linear counting rather than count-by-two counting. Also
; leaves the 8253 waiting for the initial timer 0 count to
; be loaded.
;
        mov        al,00110100b                ;mode 2
        out        MODE_8253,al
;
; Set the timer count to 0, so we know we won't get another
; timer interrupt right away.
; Note: this introduces an inaccuracy of up to 54 ms in the system
; clock count each time it is executed.
;
        DELAY
        sub        al,al
        out        TIMER_0_8253,al                ;lsb
        DELAY
        out        TIMER_0_8253,al                ;msb
;
; Wait before clearing interrupts to allow the interrupt generated
; when switching from mode 3 to mode 2 to be recognized. The delay
; must be at least 210 ns long to allow time for that interrupt to
; occur. Here, 10 jumps are used for the delay to ensure that the
; delay time will be more than long enough even on a very fast PC.
;
        rept 10
        jmp        $+2
        endm
;
; Disable interrupts to get an accurate count.
;
        cli
;
; Set the timer count to 0 again to start the timing interval.
;
        mov        al,00110100b                ;set up to load initial
        out        MODE_8253,al                ; timer count
        DELAY
        sub        al,al
        out        TIMER_0_8253,al                ;load count lsb
        DELAY
        out        TIMER_0_8253,al                ;load count msb
;
; Restore the context and return.
;
        MPOPF                                ;keeps interrupts off
        pop        ax
        ret

ZTimerOn        endp

;********************************************************************
;* Routine called to stop timing and get count.                            *
;********************************************************************

ZTimerOff proc        near

;
; Save the context of the program being timed.
;
        push        ax
        push        cx
        pushf
;
; Latch the count.
;
        mov        al,00000000b                ;latch timer 0
        out        MODE_8253,al
;
; See if the timer has overflowed by checking the 8259 for a pending
; timer interrupt.
;
        mov        al,00001010b                ;OCW3, set up to read
        out        OCW3,al                        ; Interrupt Request register
        DELAY
        in        al,IRR                        ;read Interrupt Request
                                        ; register
        and        al,1                        ;set AL to 1 if IRQ0 (the
                                        ; timer interrupt) is pending
        mov        cs:[OverflowFlag],al        ;store the timer overflow
                                        ; status
;
; Allow interrupts to happen again.
;
        sti
;
; Read out the count we latched earlier.
;
        in        al,TIMER_0_8253                ;least significant byte
        DELAY
        mov        ah,al
        in        al,TIMER_0_8253                ;most significant byte
        xchg        ah,al
        neg        ax                        ;convert from countdown
                                        ; remaining to elapsed
                                        ; count
        mov        cs:[TimedCount],ax
; Time a zero-length code fragment, to get a reference for how
; much overhead this routine has. Time it 16 times and average it,
; for accuracy, rounding the result.
;
        mov        cs:[ReferenceCount],0
        mov        cx,16
        cli                                ;interrupts off to allow a
                                        ; precise reference count
RefLoop:
        call        ReferenceZTimerOn
        call        ReferenceZTimerOff
        loop        RefLoop
        sti
        add        cs:[ReferenceCount],8        ;total + (0.5 * 16)
        mov        cl,4
        shr        cs:[ReferenceCount],cl        ;(total) / 16 + 0.5
;
; Restore original interrupt state.
;
        pop        ax                        ;retrieve flags when called
        mov        ch,cs:[OriginalFlags]        ;get back the original upper
                                        ; byte of the FLAGS register
        and        ch,not 0fdh                ;only care about original
                                        ; interrupt flag...
        and        ah,0fdh                        ;...keep all other flags in
                                        ; their current condition
        or        ah,ch                        ;make flags word with original
                                        ; interrupt flag
        push        ax                        ;prepare flags to be popped
;
; Restore the context of the program being timed and return to it.
;
        MPOPF                                ;restore the flags with the
                                        ; original interrupt state
        pop        cx
        pop        ax
        ret

ZTimerOff endp

;
; Called by ZTimerOff to start timer for overhead measurements.
;

ReferenceZTimerOn        proc        near
;
; Save the context of the program being timed.
;
        push        ax
        pushf                ;interrupts are already off
;
; Set timer 0 of the 8253 to mode 2 (divide-by-N), to cause
; linear counting rather than count-by-two counting.
;
        mov        al,00110100b        ;set up to load
        out        MODE_8253,al        ; initial timer count
        DELAY
;
; Set the timer count to 0.
;
        sub        al,al
        out        TIMER_0_8253,al        ;load count lsb
        DELAY
        out        TIMER_0_8253,al        ;load count msb
;
; Restore the context of the program being timed and return to it.
;
        MPOPF
        pop        ax
        ret

ReferenceZTimerOn        endp

;
; Called by ZTimerOff to stop timer and add result to ReferenceCount
; for overhead measurements.
;

ReferenceZTimerOff proc        near
;
; Save the context of the program being timed.
;
        push        ax
        push        cx
        pushf
;
; Latch the count and read it.
;
        mov        al,00000000b                ;latch timer 0
        out        MODE_8253,al
        DELAY
        in        al,TIMER_0_8253                ;lsb
        DELAY
        mov        ah,al
        in        al,TIMER_0_8253                ;msb
        xchg        ah,al
        neg        ax                        ;convert from countdown
                                        ; remaining to amount
                                        ; counted down
        add        cs:[ReferenceCount],ax
;
; Restore the context of the program being timed and return to it.
;
        MPOPF
        pop        cx
        pop        ax
        ret

ReferenceZTimerOff endp

;********************************************************************
;* Routine called to report timing results.                            *
;********************************************************************

ZTimerReport        proc        near

        pushf
        push        ax
        push        bx
        push        cx
        push        dx
        push        si
        push        ds
;
        push        cs        ;DOS functions require that DS point
        pop        ds        ; to text to be displayed on the screen
        assume        ds:Code
;
; Check for timer 0 overflow.
;
        cmp        [OverflowFlag],0
        jz        PrintGoodCount
        mov        dx,offset OverflowStr
        mov        ah,9
        int        21h
        jmp        short EndZTimerReport
;
; Convert net count to decimal ASCII in microseconds.
;
PrintGoodCount:
        mov        ax,[TimedCount]
        sub        ax,[ReferenceCount]
        mov        si,offset ASCIICountEnd - 1
;
; Convert count to microseconds by multiplying by .8381.
;
        mov        dx,8381
        mul        dx
        mov        bx,10000
        div        bx                ;* .8381 = * 8381 / 10000
;
; Convert time in microseconds to 5 decimal ASCII digits.
;
        mov        bx,10
        mov        cx,5
CTSLoop:
        sub        dx,dx
        div        bx
        add        dl,'0'
        mov        [si],dl
        dec        si
        loop        CTSLoop
;
; Print the results.
;
        mov        ah,9
        mov        dx,offset OutputStr
        int        21h
;
EndZTimerReport:
        pop        ds
        pop        si
        pop        dx
        pop        cx
        pop        bx
        pop        ax
        MPOPF
        ret

ZTimerReport        endp

Code        ends
        end
以下是《图形程序开发人员指南》对8253的说明,与《汇编语言、设计与接口技术》一致:

  Quote:
The 8253 actually contains three timers, as shown in Figure 3.1. All three timers are driven by the system board’s 14.31818 MHz crystal, divided by 12 to yield a 1.19318 MHz clock to the timers, so the timers count once every 838.1 ns. Each of the three timers counts down in a programmable way, generating a signal on its output pin when it counts down to 0. Each timer is capable of being halted at any time via a 0 level on its gate inputw; hen a timer’s gate input is 1, that timer counts constantly. All in all, the 8253’s timers are inherently very flexible timing devices; unfortunately, much of that flexibility depends on how the timers are connected to external circuitry, and in the PC the timers are connected with specific purposes in mind.





人类存在的目的就是试图理解人类为何存在
2006-6-3 14:27
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
jawbin
高级用户




积分 994
发帖 444
注册 2005-1-29
状态 离线
『第 4 楼』:  

在通常的使用中,我就当是 18 次,没要求那么精密过. 可以设置成更高频率的( UCOS/II 好象就更改了),但是好象影响性能.

2006-6-8 19:29
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
fqljwdyq
新手上路





积分 14
发帖 7
注册 2006-2-18
来自 江苏
状态 离线
『第 5 楼』:  

其实在实际应用当中,精确定时从来不用系统提供的8253,一般用扩展卡中的定时,对系统的这个18.2秒不是太关心

2006-6-9 08:15
查看资料  发短消息 网志   编辑帖子  回复  引用回复
zyl910
中级用户





积分 282
发帖 126
注册 2006-5-17
状态 离线
『第 6 楼』:  

但是我想在DOS下实现毫秒级定时啊!
是为了编动画、游戏程序
不可能希望别人装扩展卡



人类存在的目的就是试图理解人类为何存在
2006-6-9 09:02
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
zyl910
中级用户





积分 282
发帖 126
注册 2006-5-17
状态 离线
『第 7 楼』:  

我的目的是:编写类似Win32 API——QueryPerformanceFrequency、QueryPerformanceCounter——那样的函数来实现高精度计时



人类存在的目的就是试图理解人类为何存在
2006-6-9 09:08
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
zyl910
中级用户





积分 282
发帖 126
注册 2006-5-17
状态 离线
『第 8 楼』:  

菜菜的问一下:
TSC、ACPI是什么东西?
怎么利用它们来计时?
ACPI貌似是那个高级电源管理,它也有计时功能?昏,现在硬件接口资料真的好难找

  Quote:
http://blog.codingnow.com/2006/05/iaeeoeo.html

另外,Windows 下 QueryPerformanceCounter 是不可用的,这个根据 MSDN 的文档猜测,有可能是用 TSC 实现的。在多核和变频时代,TSC 几乎不可能取到准确的时间。

freebsd 上,使用 TSC 获取时间的优先级最低,现在一般使用 ACPI 获取时钟。在 Windows 上没有找到对应的手段。





人类存在的目的就是试图理解人类为何存在
2006-6-9 09:14
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
asbai
高级用户




积分 653
发帖 252
注册 2006-4-16
状态 离线
『第 9 楼』:  

TSC是奔腾及以上处理器新增的一个64bit的register,在每个CPU基础时钟,该计数器会自动增一(基础时钟是指:流水的stage)。TSC可以使用RDTSC指令读取。

Win32API 中的 QueryPerformanceCounter 确实应该是使用了 TSC,一是它的精度很高,二是MSDN也说了这个API使用了某些硬件相关的特性,在一些CPU上可能不支持。

TSC主要的设计用意是 profiling,在大多数情况下,用它做计时是不合适的,主要是开销较高。

大多数情况下,8253本身最高可以工作在纳秒级的精度上。这个精度对于绝大部分应用来说应该是足够了,但是包括Windows在内的任何操作系统通常不可能让自己的工作粒度保持在这个频率,这会使操作系统本身的维护性开销过大。

再加上Windows处理中断的时候,为了进一步降低开销,还专门使用了DPC机制,所以NT系列的Windows客户端产品的Timer粒度一般在10ms~15ms,服务器产品的粒度一般在15ms~30ms。

通过Windows Native API(不是Win32 API):NtSetTimerResolution,可以改变系统的工作粒度。不过,这个改变会影响当前系统的所有进程,而且不恰当的设置可能会增加系统的管理负担。

更为不爽的是,有迹向表明这个设置很可能也影响系统内核的工作状态,例如:线程调度、阻塞事件和异步IO状态查询等等,调整这个值也相应的增加了这些工作的频率,导致系统性能进一步下滑。

2006-6-9 13:05
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
asbai
高级用户




积分 653
发帖 252
注册 2006-4-16
状态 离线
『第 10 楼』:  

ACPI?

zyl910兄是想说Advanced Programmable Interrupt Controller (APIC) Timer?
至于一般说的ACPI Timer,就是RTC在ACPI兼容的系统中引发的周期性计时中断。

Microsoft的硬件开发中心有一篇专门介绍各种硬件Timer和计时问题的文章:
http://www.microsoft.com/whdc/system/CEC/mm-timer.mspx

2006-6-9 13:14
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
zyl910
中级用户





积分 282
发帖 126
注册 2006-5-17
状态 离线
『第 11 楼』:  


原来TSC是指RDTSC
平时没注意其缩写


非常感谢asbai兄
现在硬件接口编程资料真的好难找
想在DOS下编写一个精确点的计时函数都好麻烦



人类存在的目的就是试图理解人类为何存在
2006-6-10 12:56
查看资料  发送邮件  访问主页  发短消息 网志   编辑帖子  回复  引用回复
asbai
高级用户




积分 653
发帖 252
注册 2006-4-16
状态 离线
『第 12 楼』:  



  Quote:
Originally posted by zyl910 at 2006-6-10 12:56:

原来TSC是指RDTSC
平时没注意其缩写


非常感谢asbai兄
现在硬件接口编程资料真的好难找
想在DOS下编写一个精确点的计时函数都好麻烦

zyl910兄太客气了,现在硬件资料确实不好找,Intel和AMD发布的x86开发者手册既权威又详细(特别是AMD的),应该是首选资料来源。其它的还有一个网站:http://www.powernet.co.za/info/index.htm,速度虽然慢点,但是资料蛮全的。

俺就知道这么多了,各位兄台有什么好去处,拿出来share一下。

2006-6-10 14:16
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: