关于倒计时秒表程序的一些问题(中断服务程序编制)

yx2042 2016-06-28 06:02:42
下面这段代码 求大神告知他是怎么实现对输入的一个两位十进制数进行倒计时功能,就是怎么实现对其进行一秒减一的功能!



CODE SEGMENT
ASSUME CS:CODE,DS:CODE
START: JMP BEGIN
KEEPCS DW 0
KEEPIP DW 0
BEGIN:
MOV AH,01H
INT 21H
CMP AL,'0'
JB BEGIN
CMP AL,'9'
JA BEGIN
MOV CH,AL
SUB AL,30H
MOV CL,10
MUL CL
MOV DL,AL
MOV AH,01H
INT 21H
CMP AL,'0'
JB BEGIN
CMP AL,'9'
JA BEGIN
MOV CL,AL
SUB AL,30H
ADD DL,AL

MOV AX,CS
MOV DS,AX
CLI
MOV AH,35H
MOV AL,1CH
INT 21H
MOV KEEPIP,BX
MOV KEEPCS,ES
PUSH DS
MOV DX,OFFSET NINT
MOV AX,SEG NINT
MOV DS,AX
MOV AH,25H
MOV AL,1CH
INT 21H
POP DS
MOV BL,DL
MOV BH,18


STI
LOP: CMP BL,0
JG LOP
DONE: CLI
PUSH DS
MOV DX,KEEPIP
MOV AX,KEEPCS
MOV DS,AX
MOV AH,25H
MOV AL,1CH
INT 21H
POP DS
STI


NEXT4: MOV DL,'0'
MOV AH,2
INT 21H
INT 21H
MOV AH,4CH
INT 21H
NINT PROC FAR
CLI
DEC BH
JNZ NEXT2
MOV BH,18
DEC CL
CMP CL,2FH
JNZ NEXT1
DEC CH
MOV CL,39H
NEXT1: MOV DL,CH
CMP CH,'0'
JA NEXT3
CMP CL,'0'
JE NEXT4


NEXT3: MOV AH,2
INT 21H
MOV DL,CL
INT 21H
MOV DL,20H
INT 21H
DEC BL
JNZ NEXT2
JMP DONE
NEXT2: STI
IRET
NINT ENDP
CODE ENDS
END START
...全文
1372 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
baidu_29183065 2016-10-02
  • 打赏
  • 举报
回复
楼主的贴的只能说是一堆烂代码,俺在这里分析烂在那里......

CODE	SEGMENT
ASSUME	CS:CODE,DS:CODE
START:  JMP	BEGIN
KEEPCS	DW	0
KEEPIP	DW	0	
BEGIN:  
MOV	AH,01H
INT	21H
CMP	AL,'0'
JB	BEGIN
CMP	AL,'9'
JA	BEGIN
MOV	CH,AL  ;这里放入ch,保存使用者输入的[十位数]的[字符]
SUB	AL,30H ;字符ascii转作实值
MOV	CL,10  ;将十位数 x 10
MUL	CL
MOV	DL,AL  ;保存在dl
MOV	AH,01H
INT	21H
CMP	AL,'0'
JB	BEGIN
CMP	AL,'9'
JA	BEGIN
MOV	CL,AL  ;这里放入cl,保存使用者输入的[个位数]的[字符]
SUB	AL,30H ;字符ascii转作实值
ADD	DL,AL  ;乘了10的十位数加上个位数,就是使用者输入的迟延值
停下来看一看,代码用了二次int21,ah=1读取使用者输入的两个字符,但若输入单一数值呢? 假若我们输入9,按回车,程式不接受,它就是死懒不活的要我们输入两个数字,不可以只输入个数按回车! 又假若我们输入了9,然后发觉错了,想按退位改为回8,对不起不可以,没有编辑功能啊兄弟! 好吧,你终于输入了两个字符,它把输入的迟延值做成两个变数.... 变数1是 dl,下面会再放入bl 是个实值,比如输入12,dl=0ch ,用做倒数的初始值,每次到约1秒就减1 变数2是 cx 分别是两个字符ch=十位数,cl=个位数,用做显示,每次到约1秒cl减1,到零就回到9,并ch减1 cpu每18.2秒会触动时脉中断08h,而08中断代码中会再呼叫1ch中断,原1ch中断里只有一条iret, iret意思是不做任何事返回,一般做定时工作的程式就利用修改1ch,每1/18.2秒被触动一次,检查是否条件合适才做事 若拿来做计时的话,就设定每18次作一次累加或累减,楼主的代码就是干这码子事,每18次就减bl(迟延值),直到0为止 但,这坨烂代码却衍生两个问题.. 1.纯粹做倒数,用得着劳师动众去修改时脉中断吗?(当然可以是题目要求!) 2.不精准,18和18.2毕竟有误差,这里的每次减1秒,实际上是少于1秒,假若要倒数180秒,就有2秒的偏差 以下是修改中断向量1ch,指向自己的代码....

MOV	AX,CS 
MOV	DS,AX  ;cs和ds对齐
        CLI    ;不必要
MOV	AH,35H  ;读取中断向量
MOV	AL,1CH  ;1ch中断    
INT	21H
MOV 	KEEPIP,BX ;保存原中断向量cs:ip
MOV	KEEPCS,ES
PUSH	DS
MOV 	DX,OFFSET NINT ;指向自己的新中断代码
MOV	AX,SEG	NINT
 	MOV	DS,AX
MOV	AH,25H ;修改中断向量
MOV	AL,1CH
INT 	21H
POP	DS
MOV	BL,DL  ;保存迟延值
MOV	BH,18  ;被始化bh = 18


STI    ;不必要
LOP:	CMP	BL,0  ;迟延值是否减到0? 
JG	LOP  ;未,再回lop...这时1ch已被修改,所以回圈虽然是2条指令,但新1ch中断己在背后运作,每1/18.2秒一次
DONE:	CLI ;不必要
PUSH	DS ;至此,倒数已终正  
MOV	DX,KEEPIP ;取回原1ch中断的cs:ip 
MOV	AX,KEEPCS
MOV	DS,AX
MOV	AH,25H ;修改回原中断
MOV	AL,1CH
INT	21H
POP	DS
STI ;不必要
        

NEXT4:  MOV	DL,'0' ;最后印出双0
MOV	AH,2
INT 	21H
INT	21H
MOV	AH,4CH
INT	21H

NINT	PROC	FAR   ;新1ch中断
CLI
DEC	BH  ;第一次运行时这个初值是18
JNZ	NEXT2
MOV	BH,18 ;重置
DEC	CL ;减迟延字符的[个位]
CMP	CL,2FH;因0的ascii是30h,所以若减到2fh,则须借位
JNZ	NEXT1
DEC	CH ;减迟延字符的[十位],即借位
MOV	CL,39H ;重置迟延字符的[个位]为字符9,即39h
NEXT1:	MOV	DL,CH ;至此,ch和cl就是将要显示的倒数值,以下以int21h,ah=2的方式显示
CMP	CH,'0'
JA	NEXT3
CMP	CL,'0'
JE	NEXT4

NEXT3:	MOV	AH,2
INT	21H
MOV	DL,CL
INT	21H
MOV	DL,20H
INT	21H
DEC	BL ;显示完毕,迟延值 bl减1
JNZ	NEXT2 ;未减完,返回
JMP	DONE ;减完,直接跳回主程式!真的无语了,好歹设定一个flag,由主程式那个loop决定要不要终止回圈好不好!
NEXT2:	STI
IRET
NINT	ENDP
CODE	ENDS
END	START
老实说,这坨烂代码写得既冗长又不规范,我是老师只会给10分,若100为满分的话.... 下面的代码是一个不用中断,且比较优雅和精简的方式做倒数,楼主可以参考一下

.286
DATA SEGMENT
 in_msg db 'Input delay seconds(1-99):$'
 in_buf db 3,0,3 dup (0)
 disp_msg db 0,0,0dh,'$'
DATA ENDS
CODE SEGMENT
  ASSUME CS:CODE,DS:DATA
START:
 mov ax,data
 mov ds,ax
 mov ah,9
 mov dx,offset in_msg
 int 21h
 mov dx,offset in_buf
 mov ah,0ah  ;读取使用者输入字符串
 int 21h
 mov dl,0dh  ;以下输出回车
 mov ah,2
 int 21h
 mov dl,0ah
 int 21h
 mov si,offset in_buf + 2 ;指向输入缓冲
 xor cx,cx
 mov cl,in_buf + 1 ;取实际输入个数
 jcxz quit  ;若无输入,离开
 xor bx,bx
next:
 lodsb  ;取字符
 cmp al,0dh ;回车?
 jz next1  
 sub al,'0'  ;ascii -> 值
 cmp al,9   ;是否数字0-9
 ja quit  ;不是,则离开
 xchg al,bl ;交换前值
 mov ah,10 
 mul ah ;  前值 x 10
 add al,bl ;加上个位
 mov bl,al ;保存
 jmp short next ;读下一字符
next1:
 xor al,al
 out 70h,al ;利用port70h的cmos时脉索引0
 in al,71h  ;读取当前的秒值
 cmp cl,al  ;是否到了下一秒值
 jz next1   ;仍未转秒值
 mov cl,al  ;保存新秒值
 dec bl     ;减倒数
 js quit    ;倒数到负则离开
 mov al,bl  ;取倒数值
 aam        ;bcd调整,若al=0c, aam后 ax=0102
 or ax,3030h ;转ascii
 xchg ah,al  ;交换
 mov word ptr disp_msg,ax ;送到字符串
 mov dx,offset disp_msg   
 mov ah,9   ;印出倒数字串
 int 21h
 jmp short next1 ;回圈
quit:
 mov ah,4ch
 int 21h
CODE	ENDS
END	START
Areslee 2016-10-01
  • 打赏
  • 举报
回复
本版不欢迎作业贴 给你个提示,从int 21H的几个功能调用着手 另外int 1ch是时针中断的服务功能

21,459

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧