子程序:定时器时间数据转换子程序分析

  进日我在看时钟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
  片段实现原理是把BIOSINT 1CH时钟控制中断在BIOS数据区建立0040:006CH(低字) 和0040:006EH(高字)单元32位时间数字计数器中数值用种比较简明方式转换成HH:MM:SS时间格式(为ASCII)再用另显示子把转换好传显示在屏幕上

  INT1CH中断每55毫秒发生次中断每发出次中断就把0040:006CH--0040:006EH32位时间数字计数器中内容加天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(216次方为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和3ASCII值.

  (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.第 3次执行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中断执行过程本人还没有不清楚也没有相应参考文档有几个疑问还解不开特向各位超级大虾(龙虾?)请教谢谢!



Tags:  子程序通常分为两类 宏与子程序的区别 延时子程序 子程序

延伸阅读

最新评论

发表评论