1. 使用INT 21H功能调用实现每隔一秒显示A~Z共26个大写字母
思路:
- 调用子程序的格式
CALL <过程名>
<过程名> PROC
...
...
RET
<过程名> ENDP
- 实现延时1s操作,需要用到内外2个循环,3个寄存器BX和CX和AL,内循环设置参数为325,BX计数,相当于1ms,外循环设置循环次数为1000,CX计数,相当于循环1000次1ms,即为1s,AL存1,代表延时的秒数。
- 若需要延时n秒,则设置AL的次数为n,然后把延时1s的循环操作再循环n次即可,相当于3重循环。
- 在子程序中用到的CX,主程序中存了其他值,所以需要先PUSH CX的值保存下来,子程序中用完CX后再POP出来。
代码 :
没有用到数据段,不用定义DATA SEGMENT
CODE SEGMENT
ASSUME CS:CODE
N1MS = 325 ;建立延时1ms系数循环计数次数,325是定时常数,经验值
START: MOV CX,26 ;26个字母
MOV DL,41H ;"A"的ASCII码值
A1: MOV AH,02H
INT 21H ;功能调用
MOV AL, 1 ;延时1秒
CALL DT1S ;调用延时1S子程序
INC DL ;切换下一个字母
LOOP A1
MOV AH,4CH
INT 21H ;程序终止
DT1S PROC ;使用的工作寄存器为:CX、DX,入口参数为AL寄存器,AL的数值为需要延时的秒数。
PUSH CX
D0: MOV CX, 1000 ;内循环延时约1ms,外循环为1000次,则内外循环一轮为1秒。
D1: MOV BX, N1MS ;建立延时1ms系数循环计数次数
D2: DEC BX
JNZ D2
DEC CX
JNZ D1
DEC AL
JNZ D0
POP CX
RET
DT1S ENDP
CODE ENDS
END START
2. 延时练习
- 输出数字间的空格,需要在输出每一个数字之后使用2号功能单独输出空格,注意需要先PUSH一下DL的值,因为DL在前面输出数字时一直保存的是数字的ASCII码值,而且后面在输出下一个数字时还需要该值,所以在输出空格的时候需要把DL的值保存下来,输出完空格之后再POP出来,以免影响后续数字输出的工作
- 在输出“time's up”字符串过程中,在数据段定义字符串的时候,字符'会被当做字符串的分隔符号,因此需要先输出字符串time,再使用2号功能单独输出 ' ('字符的ASCII码值是21H),最后输出字符串s up
;在屏幕第一行显示倒计时3 2 1 go,每隔一秒显示一个数字。
;在屏幕第二行显示倒计时5 4 3 2 1,每隔一秒显示一个数字。
;在屏幕第三行显示字符串 'TIME'S UP!'
DATA SEGMENT
STR1 DB 'GO!', 0DH, 0AH, '$' ;0DH, 0AH为回车, 换行的ASCII码
STR2 DB 0DH, 0AH, 'TIME',27H,'S UP!','$' ;27H为单引号的ASCII码
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
N1MS = 275 ;建立延时1ms系数循环计数次数
START: MOV AX,DATA
MOV DS,AX
MOV CX,3 ;倒计时3个数
MOV DL,33H ;'3'的ASCII码值
CALL COUNTDOWN ;显示倒计时321
MOV DX,OFFSET STR1 ; 显示GO!
MOV AH,9
INT 21H
MOV CX,5 ;倒计时5个数
MOV DL,35H ;'5'的ASCII码值
CALL COUNTDOWN ;显示倒计时54321
MOV DX,OFFSET STR2 ; 显示TIME'S UP!
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
;延时显示倒计时数字子程序
COUNTDOWN PROC
A1: MOV AH,02H
INT 21H ;功能调用
PUSH DX ;因为下一步会用到DL寄存器,所以此时的子程序的DL要提前压入堆栈区保护起来。堆栈操作以字为单位,所以要压入DX。
MOV DL,20H ;空格的ASCII码值为20H
MOV AH,02H
INT 21H
POP DX
PUSH CX ;因为下一步调用的子延时程序DT1S中会用到CX和DX寄存器,所以此子程序的CX和DX要提前压入堆栈区保护起来。
PUSH DX
MOV AL, 1 ;延时1秒
CALL DT1S ;调用延时1S子程序
POP DX ;恢复压入堆栈区的CX和DX的值
POP CX
DEC DL ;切换下一个字母
LOOP A1
RET
COUNTDOWN ENDP
;延时1S子程序
DT1S PROC ;使用的工作寄存器为:CX、DX,入口参数为AL寄存器,AL的数值为需要延时的秒数。
D0: MOV CX, 1000 ;内循环延时约1ms,外循环为1000次,则内外循环一轮为1秒。
D1: MOV DX, N1MS ;建立延时1ms系数循环计数次数
D2: DEC DX
JNZ D2
DEC CX
JNZ D1
DEC AL
JNZ D0
RET
DT1S ENDP
CODE ENDS
END START
3.编程统计AX寄存器中1的个数,并将结果存入SUM单元。
思路:将AX寄存器的各位依次移入CF标志位,通过检测CF的值来判断该位是否为1,依此统计AX所含1的个数。可以利用计数办法总共检测16次,还可以通过判断移位后二进制数是否变为0作为循环结束的条件。当二进制数的后几位全部为0时,可以提前结束循环,提高程序运行效率。
- 使用SHL指令来向左移动,使用AND/OR指令来判断AX中的内容是否为0
- 在使用2号输出功能的时候,mov的DL的值必须是ASCII码或者一个特定字符才行,比如输出SUM变量中存储的数字,需要把SUM变量中数字的ASCII码值传给DL,而不能直接MOV DL,SUM
- 要想在屏幕输出的话,源操作数必须是阿斯克码或者是字符
程序段:
MOV BL, 0 ;计数单元BL清零
AGAIN: OR AX, AX ;测试AX是否为0,也可以用AND指令
JZ EXIT ;若AX=0,则转移到结束点
SHL AX, 1 ;若AX不为0,则将AX最高位移动到CF
JNC NEXT ;如果CF=0,则转去AGAIN继续
INC BL ;如果CF不为0,则BL加1
NEXT: JMP AGAIN
EXIT: MOV SUM, BL
完整代码段:定义AX的值,最后输出SUM的值
;编程统计AX寄存器中1的个数,并将结果存入SUM单元,输出SUM的个数
DATA SEGMENT
D1 DW 000FH
SUM DB 0
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:MOV AX,DATA
MOV DS,AX
MOV BL,0
MOV AX,D1
FOR:AND AX,AX
JZ EXIT
SHL AX,1
JNC BB
INC BL
BB:JMP FOR
EXIT:MOV SUM,BL;移进SUM单元
MOV DL,SUM;输出准备,移进DL
CMP DL,0AH;判断是数字还是字母
JNC LETTER
JMP NUMBER
LETTER:SUB DL,09H
ADD DL,40H
JMP OUTPUT
NUMBER:ADD DL,30H
OUTPUT:MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END START