hoo
hoo
驱动牛犊
驱动牛犊
  • 注册日期2002-06-08
  • 最后登录2003-06-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2384回复:5

系统主板上有个8254可编程计时芯片,查到它的地址为0x40-43,欲对其读写,可是……

楼主#
更多 发布于:2002-06-09 10:45
我的主要目的是为了取得<1ms的时间间隔,这个问题我曾经在多个网站提问过多次,可是没有得到好的答案,现在终于有所发现。

根据这本1993年学苑出版社出版的《Programmer\'s Bible》一书所介绍,并且查阅《微机接口原理》的书,我们可以对系统时钟芯片8254的状态口地址0x43读写状态,对计时器T0,T1,T2的端口地址0x40,0x41,0x42读写计数值,那么就可得到最小单位为1/1193180秒的时间间隔。

这样我如果要取得<1ms的时间间隔,只需算出计数值,然后取得中断信号。

现在我想在DOS下实现第一步:往0x43写状态,用的是TC,
outport (0x43,0xXX);
rc=inport(0x43);
结果rc=255,并非我给它们的数值,说明该状态口不能写值。试过几遍皆如此。

是否存在打开这个端口的开关呢? 在哪儿呢?


[编辑 -  6/9/02 by  hoo]
qizhi
驱动小牛
驱动小牛
  • 注册日期2001-10-18
  • 最后登录2017-07-31
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望41点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
  • 社区居民
沙发#
发布于:2002-06-10 09:22
关于PC机系统的82C54/53的使用有几个问题需要考虑:
1:标准PC的82C54的定时/计数器0用于向系统的日时钟发出定时中断。所以,如果你的机器是标准配置的PC机,该82C54你肯定不能用,否则会危急系统;同时,也不能修改其定时计数初值。其标准的输出为18.2Hz.如果其它的PC机配置我还不直到。
2:标准PC的82C54的定时/计数器1用于系统的RAM刷新。但是新的PC中该通道似乎不用了,或许可以考虑此通道。
3:标准PC的82C54的定时/计数器2用于给扬声器提供发声控制。

另外,你回读8254控制字(非状态字!)的方法不对,且在我的记忆中,控制字似乎也不是每位都可读的。另外,8253、8254、82C53、82C54等还可能有细微的区别,详细的需要仔细查找其DATASHEET(PDF格式)来分析。另外,对控制口(0x43)操作时需要注意,该口同时操作3个定时/计数器,所以其数据非常关键。你的提问中数据以0xXX示出,说明你可能对此问题有所忽视。
  判断8254是否可用/程序是否对,可以在DOS下,对其2号通道操作,因为结果可以直接从扬声器得到。确认了82C54可操作后,再确认是否可以借助其通道1/0(假如可用)来产生1mS以下的中断。
  如有问题可继续联系。

附件名称/大小 下载次数 最后更新
2002-06-10_82c54.pdf (240KB)  7
hoo
hoo
驱动牛犊
驱动牛犊
  • 注册日期2002-06-08
  • 最后登录2003-06-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-06-10 11:07
 运行以下程序
   unsigned rc,r0,r1,r2;
   unsigned r0l,r0h,r1l,r1h,r2l,r2h;
   unsigned lo,hi;
   unsigned long count,k;
  
   clrscr();
   outportb(0x43,0x70); //写T1,先低后高,以方式0工作
   outportb(0x41,0xF);  //写低字节
   outportb(0x41,0x0);  //写高字节

   outportb(0x43, 0x40); //锁存T1
   r0l=inportb(0x41);     //读T1低字节
   r0h=inportb(0x41);     //读T1高字节


   for(k=1;k<1000001;k++);//延时;

   outportb(0x43, 0x40); //锁存T1
   r1l=inportb(0x41);     //读T1低字节
   r1h=inportb(0x41);     //读T1高字节

   printf(\"T1L --before delay  :%xH\\n\",(r0l));
   printf(\"T1H --before delay  :%xH\\n\",(r0h));
   printf(\"T1 --before delay  :%xH\\n\",(r0l ^ (r0h<<8)));

   printf(\"T1L --after delay  :%xH\\n\",(r1l));
   printf(\"T1H --after delay  :%xH\\n\",(r1h));
   printf(\"T1 --after delay  :%xH\\n\",(r1l ^ (r1h<<8)));

结果是:
T0 before delay :fh
T0 after delay:随机的
按照方式0的原理,其计数初值是自动不断装入寄存器的,所以数值应不超过我预设的初值000f,但在delay之前是这样的,之后却不是这样的。WHY?
qizhi
驱动小牛
驱动小牛
  • 注册日期2001-10-18
  • 最后登录2017-07-31
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望41点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
  • 社区居民
地板#
发布于:2002-06-10 12:23
按照我的理解,方式0的计数初值不是(!)自动装入寄存器的,其计数值减到0后,输出一直保持高电平,而此高电平一直保持到计数器被置入新的计数初值或者选定其它工作方式。
你的程序的其它部分没有看出错误,不过显示计数值的计算
r0l ^ (r0h<<8))似乎不对,是否应该改为:r0l + (r0h<<8))

按照理解,如果计数器正常工作,在方式0下,应该减计数到0后停止,所以出现随机数是不对的。需要检查:是否程序实际被执行?建议你按照上一条说的,先测试扬声器后,在测试你的程序。
hoo
hoo
驱动牛犊
驱动牛犊
  • 注册日期2002-06-08
  • 最后登录2003-06-23
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-06-10 16:26
我已经试过测试扬声器,程序如下:
unsigned lo,hi;
 unsigned n_port,o_port;
 unsigned long count;
 //double *h;

count=1193180/1000;
lo=count & 0xFF;
//modf(count/256,h);
hi=(count & 0xFF00)>>8;
cout<<\"count=\"<<count<<\"\\n\";
cout<<\"lo=\"<<lo<<\"\\n\";
cout<<\"hi=\"<<hi<<\"\\n\";
/*cout<<\"count/256=\"<<count/256<<\"\\n\";  */
//outportb (0x43,0x38);
o_port=inportb(0x61);  
n_port=o_port | 0x03;
outportb(0x61,n_port);
printf(\"the old port is :%xH\\n\",o_port);
printf(\"the new port is :%xH\\n\",n_port);
//rc=inportb(0x43);
do{
outportb(0x43,0xb6);      //write T2
outportb(0x42,lo);
outportb(0x42,hi);
}while(!kbhit());
o_port=inportb(0x61);     //#1
n_port=o_port & 0x0;      //#2
outportb(0x61,n_port);    //#3


但是若不加#1,#2,#3这几句,当程序执行完了之后,声音才出来。这是为何?

我的QQ号为11992745,若有时间QQ联系!

[编辑 -  6/10/02 by  hoo]
qizhi
驱动小牛
驱动小牛
  • 注册日期2001-10-18
  • 最后登录2017-07-31
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望41点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
  • 社区居民
5楼#
发布于:2002-06-11 09:33
你的发声程序对8254的TC2的程序没错,但是,似乎应该修改o_port=inportb(0x61); //#1
n_port=o_port & 0x0; //#2
outportb(0x61,n_port); //#3
三局为如下:
o_port=inportb(0x61); //#1
n_port=o_port | 0x3; //#2(或操作)
outportb(0x61,n_port); //#3
这样,扬声器就可以立即发声了。上述3句的作用在于,打开TC2的门控、允许OUT2输出到扬声器。
游客

返回顶部