中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --
联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum
游客 | 登录 | 注册 | 会员 | 搜索 | 中国DOS联盟
中国DOS联盟论坛
现在时间是 2026-10-31 22:00
共 47,815 主题排行 / 349,930 发帖 / 今日 0 篇 / 48,290 会员排行
DOS开发编程 & 发展交流 (开发室) » 一直存在的疑问:PC上8253计时器的精确频率到底是多少?
可打印版本  1,848 / 11
第1楼 zyl910 发表于 2006-06-03 12:40
中级用户 发帖 126 积分 282
一直存在的疑问: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一致。



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

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

第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


第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



第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


第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种(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种(晶振源的频率周期是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 ]
第2楼 Scott0902 发表于 2006-06-03 14:03
中级用户 发帖 237 积分 466
深奥……
第3楼 zyl910 发表于 2006-06-03 14:27
中级用户 发帖 126 积分 282
刚才又翻了一下《图形程序开发人员指南(Michael Abrash's Graphics Programming Black Book Special Editior)》的“Zen timer”,发现该代码采用的(输入频率周期)是0.8381ms(ZTimerReport函数):



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

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.
第4楼 jawbin 发表于 2006-06-08 19:29
高级用户 发帖 444 积分 994
在通常的使用中,我就当是 18 次,没要求那么精密过. 可以设置成更高频率的( UCOS/II 好象就更改了),但是好象影响性能.
第5楼 fqljwdyq 发表于 2006-06-09 08:15
新手上路 发帖 7 积分 14 来自 江苏
其实在实际应用当中,精确定时从来不用系统提供的8253,一般用扩展卡中的定时,对系统的这个18.2秒不是太关心
第6楼 zyl910 发表于 2006-06-09 09:02
中级用户 发帖 126 积分 282
但是我想在DOS下实现毫秒级定时啊!
是为了编动画、游戏程序
不可能希望别人装扩展卡
第7楼 zyl910 发表于 2006-06-09 09:08
中级用户 发帖 126 积分 282
我的目的是:编写类似Win32 API——QueryPerformanceFrequency、QueryPerformanceCounter——那样的函数来实现高精度计时
第8楼 zyl910 发表于 2006-06-09 09:14
中级用户 发帖 126 积分 282
菜菜的问一下:
TSC、ACPI是什么东西?
怎么利用它们来计时?
ACPI貌似是那个高级电源管理,它也有计时功能?昏,现在硬件接口资料真的好难找


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

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

freebsd 上,使用 TSC 获取时间的优先级最低,现在一般使用 ACPI 获取时钟。在 Windows 上没有找到对应的手段。
第9楼 asbai 发表于 2006-06-09 13:05
高级用户 发帖 252 积分 653
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状态查询等等,调整这个值也相应的增加了这些工作的频率,导致系统性能进一步下滑。
第10楼 asbai 发表于 2006-06-09 13:14
高级用户 发帖 252 积分 653
ACPI?

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

Microsoft的硬件开发中心有一篇专门介绍各种硬件Timer和计时问题的文章:
http://www.microsoft.com/whdc/system/CEC/mm-timer.mspx
第11楼 zyl910 发表于 2006-06-10 12:56
中级用户 发帖 126 积分 282
昏
原来TSC是指RDTSC
平时没注意其缩写


非常感谢asbai兄
现在硬件接口编程资料真的好难找
想在DOS下编写一个精确点的计时函数都好麻烦
第12楼 asbai 发表于 2006-06-10 14:16
高级用户 发帖 252 积分 653
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一下。
[ 联系联盟系统管理团队 - 中国DOS联盟 - 标准版 ]
Sponsored by ifanr Inc | © 2001–2023