注:此文发表在1993年《电脑》第一期上
时代背景:关于这篇文章的诞生,有些细节我还记得,回忆起来也算是有趣,写出来大家共享。X86架构的机器经历了这许多许多年的发展,现在已经不是什么稀罕玩意了,现在说当年的PC机不能记录时间,每次开机都需要自己输入时间、日期,然后一关机就丢掉,恐怕很多人都会觉得不可思议,那样的机器可怎么用呀!但那时确实是这样,正是由于这个原因,后来才出现了本文所说的“多功能卡”,才有了使用MM58167做的实时时钟,记得在90年完成民航32路自动转报系统的项目后,受北京某单位委托开发民航电报终端,我计划找一个廉价的PC配上相应的软件完成,这上面必须要有这个实时时钟,而当时,只能用MM58167,记得是在中关村白颐路马路东边麦当劳旁边的一个门市里选的测试样机,在对样机做测试的过程中,发现它的实时时钟有时会丢失时钟数据,当时还没有互联网。找MM58167芯片的资料十分困难,我把那块多功能版琢磨了很久,终于发现是上电时顺序不精确造成的,于是简单改了些电路,这块板子就好了,之所以记得这么清楚,是因为那是很年轻(20多岁吧),每次去那家公司,人家都很尊敬我,员工、老板吃盒饭,把我一个人请到边上的麦当劳用餐,当时由于找芯片资料困难,公司老板是一位海归,他说以前他的一篇论文中涉及到了这个芯片,于是专门找到这篇论文拿给我,这篇文章中的很多资料应该就出自这篇论文,可惜这篇论文我现在已经找不到了,文章结尾处说的那个程序也已经找不到了,之所以把这篇文章又拿出来,是最近发现这个芯片现在在某些场合还在使用,或者对他们能有点帮助。
PC的实时时钟在经历了MM58167后,才出现了使用MC146818的CMOS,既有实时时钟,又可以记录其它很多信息,现在146818这个芯片也见不到了,但现在CMOS的寄存器结构和使用方式还是和当年使用MC146818时一样,可能还有人记得这个芯片,但恐怕记得MM58167曾经做过PC实时时钟的人已经不多了。
目前,市面上出手的简易PC机,多数要配有一块多功能卡,该卡除具备软驱接口、串行口和并行口外,还有一篇实时时钟芯片MM58167A,该芯片使PC机具备了实时时钟功能,但关于该芯片的资料及其应用方法的介绍却很少,尽管有应用程序timer.com支持该芯片的设置及使其和系统时钟相连,但用户在开发应用时仍不免感到不便,现将本人在使用该芯片的过程中的体会介绍给大家,希望能对广大PC用户有所帮助。
一、MM58167A的功能及特点
MM58167A是一个双列直插式的24脚CMOS大规模集成电路芯片,其引脚图见图1,正常情况下,该芯片由+5V供电,一旦电源掉电,23脚POWER DOWN将出现逻辑0,此时,MM58167A将切断和外界的信号通讯,使其出于高阻抗状态,工作在低功耗状态,使其内部计数器继续计时,此时,只需一3V电池供电即可。
图 1
MM58167A有5条地址线,可选择32个寄存器,但实际上MM58167A仅使用了24个寄存器,其地址及功能如下:
地址 功能
00h 计数器——1/1000秒
01h 计数器——1/100秒和1/10秒
02h 计数器——秒
03h 计数器——分
04h 计数器——时
05h 计数器——星期几
06h 计数器——日
07h 计数器——月
08h 锁存器——1/1000秒
09h 锁存器——1/100秒和1/10秒
0ah 锁存器——秒
0bh 锁存器——分
0ch 锁存器——时
0dh 锁存器——星期几
0eh 锁存器——日
0fh 锁存器——月
10h 中断状态寄存器
11h 中断控制寄存器
12h 计数器复位
13h 锁存器复位
14h 状态位
15h “GO”命令
16h 等待中断
中断控制寄存器和中断状态寄存器为一对寄存器,前者为只写寄存器,后者为只读寄存器,中断状态寄存器的每一位对应一种中断方式,同样,中断控制寄存器的每一位控制一种中断方式,其意义见图2:
图 2
二、MM58167A的应用
1、在PC机上查找MM58167A的端口地址
MM58167A常用的端口地址为:0240h、02c0h、0340h
我们可以用这个方法查找:相对于基地址的第二个位置为秒计数器,读该地址应返回一个0--59之间的BCD码,如返回一0ffh,一般表明该地址与硬件无关,若读出值符合以上规律,多次读值此值还在向前走,则通常可以确定该地址为MM58167A的基地址。
目前市面上的多功能卡大多地址为240h和340h可变。
2、使用实时时钟
MM58167A的所有计数器和锁存器均以BCD码计数,以下程序将MM58167A的计数器设定成3月12日11:32
mov dx, 252h
mov al, 0ffh
out dx, al ;计数器复位
mov dx, 243h
mov al, 32h
out dx, al ;分计数器
inc dx
mov al, 11h
out dx, al ;小时计数器
inc dx
inc dx
mov al, 12h
out dx, al ;日计数器
inc dx
mov al, 3
out dx, al ;月计数器
MM58167A的有些计数器是不检查数据的合法性的,读者可以将其设为13月40日30:59,然后用debug观察其走时,当分计数器变为0后,时间将变为13月41日31:00,所以在给MM58167A设初始值时,一定要用软件检查其合法性。
MM58167A的另一个问题是本身不会计算星期,其星期计数器只会从1--7循环技术,计算星期是比较繁琐的,最简单的办法是利用DOS的功能调用,如下面一段程序:
假定子程序bcdbin可将al中的BCD码换算成二进制码。
mov dx, 246h
in al, dx ;MM58167A中的日
call bcdbin
push ax
inc dx
in al, dx ;MM58167A中的月
call bcdbin
mov dh, al
pop ax
mov dl, al
mov cx, 1992 ;1992年
mov ah, 2bh
int 21h ;设定DOS日期
mov ah, 2ah
int 21h ;读DOS日期
;DOS返回的星期正好也为一个1--7的数字
mov dx, 245h
out dx, al ;AL为DOS返回的星期
MM58167A本身有中断功能,遗憾的是多功能卡上均未使用该中断功能,由于无法使用中断功能因而该芯片上的锁存器也就没有作用,正巧该芯片上缺少一个年计数器,我们可以利用锁存器模拟一个年计数器。
下面这段程序,把年放在1/100秒锁存器中,把上次调用改程序时的月放在1/1000秒锁存器中,每次调用该程序是,若现在月小于上次月,则认为已走过一年,将年加1.
mov dx, 247h
in al, dx
mov bl, al
inc dx
in al, dx
cmp bl, al
ja cont1
inc dx
in al, dx
add al, 1
daa
out dx, al
cont1:
mov dx, 248h
mov al, bl
out dx, al
要使用实时时钟,最简单的办法是编一段程序,该程序读出MM58167A的数据,然后用此数据设定DOS的日历时钟,但仅仅这样做,则使用DOS的time和date命令并不能修改MM58167A的时间,因此还应适当修改DOS有关功能调用并使其常驻内存;还有一种方法就是编一个设备驱动程序,每次启动DOS时将其安装,也可达到同样的目的。
三、其它功能
MM58167A有一个“GO”命令寄存器,该寄存器为只写寄存器,起同步作用,当对频率较低的计数器,如月、日、星期、时、分设置了初值以后,可以用“GO”命令来启动MM58167A,“GO”命令可同时对1/1000秒、1/100秒、1/10秒和秒寄存器进行清0,从而使MM58167A在预置的精确时间下开始计数,请看下面程序:
mov dx, 255h ;“GO”命令寄存器
mov al, 0ffh
out dx, al
mov dx, 240h ;1/1000秒寄存器
in al, dx
mov cl, al
inc dx ;1/100秒寄存器
in al, dx
inc dx
in al, dx
mov ch, al
inc dx ;秒寄存器
in al, dx
在debug下运行此程序会看到cl(1/1000秒寄存器),ch(1/100秒寄存器和1/10秒寄存器),al(秒寄存器)都为0
四、结束语
以上介绍了MM58167A的基本使用方法,用作一般的实时时钟,这些只是已经足够了;根据需要读者还可开发出一些特殊的用途,如在其锁存器中存一些特定信息用于加密等。特别是MM58167A本身有很强的中断功能,如把他的标准中断输出和PC总线的某一未使用的IRQ相连,使其具有中断能力,将使该芯片的使用更加方便,最后给出一个完整的实用程序(编者:为节省篇幅,该程序不刊出,拷在本期程序盘中,文件名为zk13g),该程序修改了DOS的有关功能调用,使DOS的DATE和TIME命令与MM58167A相连,供读者参考。
评论