管理员
|
阅读:2679回复:0
定时器时间数据转换子程序分析
楼主#
更多
发布于:2011-12-14 00:28
 | |  |  | 进日,我在看一时钟TSR程序,分析其中一个把Bios数据区中的定时器数据转换成HH:MM:SS时间格式的数据(ASCII)的程序片段时,既学到一点东西,又发现了一写自己弄不明白的问题。现在我把自己学到的好东西写出来与大家分享,同时向各路高手请教请教。 程序片段如下:(汇编语言程序) ... (省略) HMS db 8 dup(':') ... time proc lea di,position ;(1) --行号 mov ax,0 ;(2) mov ds,ax ;(3) mov al,ds:[46eh] ;(4) call clk1 ;(5) mov ax,ds:[46ch] ;(6) mov dx,0 ;(7) mov bx,444h ;(8) call clk0 ;(9) mov ax,dx ;(10) mov cx,3ch ;(11) mul cx ;(12)
clk0: add di,3 ;(13) div bx ;(14) clk1: aam ;(15) add ax,3030h ;(16) xchg ah,al ;(17) mov cs:[di],ax ;(18) ret ;(19) time endp
程序片段实现的原理是把BIOS的INT 1CH时钟控制中断在BIOS数据区建立的0040:006CH(低字) 和0040:006EH(高字)单元32位时间数字计数器中的数值用一种比较简明的方式转换成HH:MM:SS时间格式(为ASCII字符),再用另一显示子程序把转换好的字符传显示在屏幕上。 INT1CH中断每55毫秒发生一次中断,每发出一次中断就把0040:006CH--0040:006EH的32位时间数字计数器中的内容加一,一天24小时,最大的计数值为001800B0H,达到最大值,INT1CH把这个计数器复位为0,然后重新计数,新的一天又开始。 我搞不明白的是为什么计数器的最大值会是1800B0H(1573040),1573040*55/1000=86517.2(秒)而24小时是86400秒,计数器的值比实际值大。INT1CH每55毫秒中断一次,也就是说1秒钟中断18.1818181818...(无数个18)次,若按每秒中断18.2次的话,一天24小时计数器的数值应为1572480,比1573040少了560(为30.8秒) 。一个小时3600秒中断次数为65520(以18.2计算),比65535(2的16次方为65536)少15次(不足一秒)。一天少360次,与前面少560次又不同。真令我费解。
现假设一个时间计数器的数值,分析上述程序片段的执行过程。假设[0040:006EH]=0017H,[0040:006EH]=1AA3H。程序片段的执行过程为: {(1)->(4)}->{(15)->(19)}->{(6)->(8)}->{(13)->(19)}->{(10)->(19)} (小括号中的数字为行号,大括号中的箭头为顺序指令序列,大括号外的箭头为指令跳转)
(1)->(3): DS=AX=0,DI=HMS的位移,HMS是用以存储转换后的时间值(ASCII)的内存单元。 (4): MOV AL,DS:[46EH]即AL=17H (5): CALL CLK1 ;调用CLK1
CLK1的执行过程如下: ((15)->(19),此时转换小时值) (15): AAM指令,乘法的ASCII调整指令,把AL中的值调整为非压缩的BCD格式,即把AL除以0AH(10),商放在AH中,余数放在AL中.执行后,AX=0203H. (16): ADD AX,3030H 令AX=3233H,就是2和3的ASCII值. (17): XCHG AH,AL 令AX=3332H. (18): MOV CS:[DI],AX 把转换后的数值(ASCII)存在HMS中. (19): RET 返回. (返回执行第6条指令)
此时,HMS为 (高字) ':',':',':',':',':',':','3','2'(低字)
(6): MOV AX,DS:[46CH] AX=1AA3H (7),(8): BX=444H,DX=0 (9): CALL CLK0 ;调用CLK0
CLK0的执行过程如下: ((13)->(19),此时转换分钟值) (12): ADD DI,3 把DI加3,即指向HMS的指针加3. (14): DIV BX 把1AA3H除以444H. 444H=1092,1092/18.2=60(秒).指令执行完后AX=06H(商),DX=10BH(余数) (15)...(19): 即执行CLK1,执行过程与以上描述相同,把AX=06H(分钟)转换成能显示的ASCII值.(19)句 RET 返回到第(10)句.
此时,HMS为(高字) ':',':',':','6','0',':','3','2'(低字)
开始转换秒数值:
(10),(11):AX=10BH,CX=3CH.(3CH=60) (12): 10BH*3CH=3E94,AX=3E94H (13)...(19): 即再次执行CLK0. (14) DIV BX ;3E94H/444H AX=0EH,DX=2DCH.第三次执行CLK1,把AX=0EH(14)转换成可显示的ASCII字符.过程同上.(19) RET 返回调用TIME 子程序处.从(10)到(14) 267*60/1092=267/18.2,(10BH=267)意思是中断267次相当于多少秒.
最后,HMS为(高字) '4','1',':','6','0',':','3','2'(低字),时间为23:06:14。
由上可以看出,高字[0040:006EH]为时间值,低字[0040:006CH]为一小时发生中断次数65520次。上述的转换过程已经很清楚了。0040:006EH-0040:006CH中,高字直接调用CLK1转换成可视字符。低字除以444H(次/分)得分钟数值(商),再调用CLK1转换成可视字符。然后把余数(不足一分钟的中断次数)乘3CH,再除以444H,即把余数除以18.2(次/秒)得秒数值(商),最后一次调用CLK1转换成可视字符。所转换得字符存在HMS内存单元中。 子程序TIME的算法是很易懂的,但INT1CH中断的执行的过程本人还没有不清楚,也没有相应的参考文档,有几个疑问还解不开,特向各位超级大虾(龙虾?)请教。谢谢!
| |  | |  |
|