汇编语言——实验2:分支与循环程序设计

实验二:分支与循环程序设计

一、实验目的

        1、掌握程序设计中的3种基本结构(顺序结构、选择程序、循环程序)。

        2、熟练使用汇编语言的指令:数据传送类指令、数据运算类指令、逻辑判断类指令与转移指令、循环指令等。

        3、初步了解系统功能调用的使用方法,尝试使用01H号功能调用进行字符输入的方法及使用02H号功能调用进行字符输出(显示)的方法。

二、实验内容

        1、计算1+2+3+…+10,将结果显示在屏幕上。

        2、利用01H号功能调用输入10个一位数字,并将其由ASCII码转换为二进制数,依此保存到变量BUF的10个字节中,变量BUF的形式为BUF  DB  10  DUP(?)。编程求出这10个数中的最大数和最小数,将最大数存入MAX单元、最小数存入MIN单元,并将其在屏幕上显示出来。

        3、对于第2题,怎样修改程序可以同时实现将10个数字的累加功能。

        4、对于第2题,若要求输入的是两位数,又该怎么办?

三、设计思想

3.1 实验内容一

我们需要先对1到10进行循环求和,再将计算结果显示在屏幕上。

对于求和,我们先对用于存放累加和的寄存器AX进行初始化,并将10赋值给CX寄存器(设定赋值操作循环次数为10次);然后设置循环,在next循环下进行AL和CL的ADD操作,每循环一次CX-1的同时都会在AL中进行累加,直到CX=0时完成循环。

对于在屏幕上显示结果,由于1-10相加结果为两位数,我们需要依次按位输出。首先,初始化被除数AX(补充AH为0)、除数BL为10,然后利用div BL指令计算出累加和的十位数字和个位数字,其中商(十位数字)在AL中,余数(个位数字)在AH中,再进行套路式转化:分别通过add AH,30H指令将两个数字变为字符形式,再利用mov DL,AL、mov AH,02h、int 21H实现打印输出,至此完成求和并以十进制显示结果。需要注意的是,在十位数字输出后AH内容进行更改,所以需要提前存储好AX中的内容。

其具体流程图见下图1 所示:

图1  实验内容一流程图

3.2 实验内容二

我们需要获取用户的输入并比较大小最后输出最大值和最小值。

由于数据需要保存在BUF中,且需要输出max和min,故先在DATA数据段内设置相关变量。其后,在代码段内对后续需要的DS、AX、CX计数器和SI变址器进行初始化。

对于所有的用户交互信息提示,我们均可先利用 变量名 DB '提示内容',0DH,0AH,'$'指令进行初始化,再利用 mov DX,offset 变量名、mov AH,9、int 21H来实现提示输出。

输入指令MOV AH,01H、INT 21H完成一位字符的输入,由于输入是16进制,所以需要通过and  AL,0fH指令将ASCII码转换为二进制数,并通过MOV BUF[SI],AL指令将二进制数存入到变量BUF中。

与高级语言类似。若为第一个数据输入,则暂时将最大值和最小值设为该数据。若不是第一个数据输入,则需对该数据进行大小判断:先将该数据与当前最小值min进行比较,若该值比min小,则将min替换为该值;若该值大于或等于min,则跳入ifGreater框架,将该数据与当前最大值max进行比较,若该值比max大,则将max替换为该值。

随着数据的每一次输入,我们都比较一次输入值和最大值、最小值的相对关系。通过10次循环,就可以在完成数据的存入的同时,求解出最大值和最小值。

最后,将max和min分别赋值给DL寄存器,通过add DL,30H将数值转换为字符,利用MOV AH,02H和INT 21H指令对它们进行屏幕输出,至此完成所有操作。

其具体流程见下图2所示:

图2  实验内容二流程图

3.3 实验内容三

实验内容三是在实验内容二的基础上进行拓展,所有的流程同第二部分一致,只是增加了累加求和。累加求和可以在一个循环下完成,原理同实验内容一一致。最后将累加和赋值给DL寄存器,通过add DL,30H将数值转换为字符,利用MOV AH,02H和INT 21H指令对进行输出。

其具体流程见下图3 所示:

图3  实验内容三流程图

3.4 实验内容四

实验内容四也是在实验内容二的基础上进行拓展,流程同实验二,但是需要输入两位数据,且最后显示输出也需要进行合理的数值转换。

对于两位数据的获取:我们首先通过一次MOV AH,01H INT 21H输入一位后,通过SUB AL,30H指令转换进制,同时赋值给BL数值10,让其与AL进行相乘反制得到高位10进制,而后将AL赋值给DL进行高位数据保存。再次输入一位低位数据,转换为10进制后,与DL进行相加得到两位数据。通过循环十次得到一个数组内全是两位数。

对于两位数据的输出:我们需要将这两位数转换为ASCII码后进行高低位分别计算,然后依次输出至屏幕。其具体流程见下图4所示:

图4  实验内容四流程图

四、程序代码

4.1 实验内容一

code segment
	assume CS:code
start:      ;程序入口
	;计算1+2+3+…+10,累加和=AL
	mov 	AL,0
	mov		CX,10	    ;循环次数
next:		 ;循环入口
	add		AL,CL
	loop	next
	
	;将累加和AL显示在屏幕上,AL=55----->'5' '5'
	;1.求十位数字
	mov		AH,0
	mov		BL,10		;除数
	div		BL 			;商=AL,余数=AH
	add		AL,30H		;把AL中的数转为相应字符,如5-->‘5’
	;2.求个位数字
	add		AH,30H		;个位数字字符
	;输出十位数字与个位数字
	mov		DL,AL
	push	AX
	mov		AH,2
	int		21H
	pop		AX
	mov		DL,AH
	mov		AH,2
	int		21H
	
	;程序退出
	mov		AH,4cH
	int		21H
code ends
end start

4.2 实验内容二

data segment
	buf  DB 10 DUP(?)
	max	 DB ? 		;最大值
	min  DB ?		;最小值
	inputMessage DB 'Input 10 1-digit number:',0DH,0AH,'$'
	maxMessage DB 0DH,0AH,'The max integer is:','$'
	minMessage DB 0DH,0AH,'The min integer is:','$'
data ends

code segment
	assume  cs:code,ds:data	 ;关联段地址寄存器与具体段
start:
	;把data段地址赋值给ds
	mov  AX,data		;data段名表示data段的段地址,常量
	mov  DS,AX
	
	;输出提示
	mov  DX,offset inputMessage
	mov  AH,9
	int 21H
	
	;输入10个一位数字,由ASCII码转换为二进制数,保存到变量BUF,同时找最大值、最小值
	mov  CX,10
	mov  si,0
next:
	;输入一个字符
	mov  AH,1
	int  21H
	;由ASCII码转换为二进制数,保存到变量BUF
	and  AL,0fH
	mov  BUF[si],AL
	cmp  CX,10		;是否第一次循环
	je	 firstNumber
	cmp  AL,min
	jnl  ifGreater	;不小于跳转,判断是否更大
	mov  min,AL		;发现更小的值,更换min
	jmp  L1
ifGreater:	
	cmp  AL,max
	jng	 L1
	mov	 max,AL		;发现更大的值,更换max
	jmp  L1
firstNumber:
	mov  min,AL
	mov  max,AL
L1:
	;准备下一次循环
	;输出空格
	mov  DL," "
	mov  AH,2
	int  21H
	inc  si
	loop  next
	
	;输出最大值、最小值
	;输出最大值提示字符串
	mov  dx,offset maxMessage
	mov  AH,9
	int  21H
	mov  DL,max
	add  DL,30H    ;最大值转为字符
	mov  AH,2	   ;显示DL中的字符
	int  21H
	;输出最小值提示字符串
	mov  dx,offset minMessage
	mov  AH,9
	int  21H
	mov  DL,min
	add  DL,30H    ;最小值转为字符
	mov  AH,2	   ;显示DL中的字符
	int  21H
	
	;程序退出
	mov	 AH,4cH
	int	 21H
code ends
end start

 4.3 实验内容三

;对于第2题,修改程序同时实现将10个数字的累加功能
data segment
	buf  DB 10 DUP(?)
	max	 DB ? 		;最大值
	min  DB ?		;最小值
	sum  DB ?       ;累加和
	inputMessage DB 'Input 10 1-digit number:',0DH,0AH,'$'
	maxMessage DB 0DH,0AH,'The max integer is:','$'
	minMessage DB 0DH,0AH,'The min integer is:','$'
	sumMessage DB 0DH,0AH,'The sum is:','$'
data ends

code segment
	assume  cs:code,ds:data	 ;关联段地址寄存器与具体段
start:
	;把data段地址赋值给ds
	mov  AX,data		;data段名表示data段的段地址,常量
	mov  DS,AX
	
	;输出提示
	mov  DX,offset inputMessage
	mov  AH,9
	int 21H
	
	;输入10个一位数字,由ASCII码转换为二进制数,保存到变量BUF,同时找最大值、最小值
	mov  CX,10
	mov  si,0
	mov  sum,0		;累加和初始化
next:
	;输入一个字符
	mov  AH,1
	int  21H

	;由ASCII码转换为二进制数,保存到变量BUF
	and  AL,0fH
	;累加AL到sum
	add  sum,AL
	;AL保存数组BUF
	mov  BUF[si],AL
	cmp  CX,10		;是否第一次循环
	je	 firstNumber
	cmp  AL,min
	jnl  ifGreater
	mov  min,AL		;发现更小的值
	jmp  L1
ifGreater:	
	cmp  AL,max
	jng	 L1
	mov	 max,AL		;发现更大的值
	jmp  L1
firstNumber:
	mov  min,AL
	mov  max,AL
L1:
	;准备下一次循环
	;输出空格
	mov  DL," "
	mov  AH,2
	int  21H
	inc  si
	loop  next
	
	;输出最大值、最小值
	;输出最大值提示字符串
	mov  dx,offset maxMessage
	mov  AH,9
	int  21H
	mov  DL,max
	add  DL,30H    ;最大值转为字符
	mov  AH,2	   ;显示DL中的字符
	int  21H
	
	;输出最小值提示字符串
	mov  dx,offset minMessage
	mov  AH,9
	int  21H
	mov  DL,min
	add  DL,30H    ;最小值转为字符
	mov  AH,2	   ;显示DL中的字符
	int  21H
	
	;输出累加和提示字符串
	mov  dx,offset sumMessage
	mov  AH,9
	int  21H
	;1.求十位数字
	mov  AL,sum
	mov	 AH,0
	mov	 BL,10		;除数
	div	 BL 			;商=AL,余数=AH
	add	 AL,30H		;把AL中的数转为相应字符
	;2.求个位数字
	add	 AH,30H		;个位数字字符
	;输出十位数字与个位数字
	mov	 DL,AL
	push AX
	mov	 AH,2
	int	 21H
	pop	 AX
	mov	 DL,AH
	mov	 AH,2
	int	 21H
	
	;程序退出
	mov	 AH,4cH
	int	 21H
code ends
end start

4.4 实验内容四

data segment
	buf  DB 10 DUP(?)
	max	 DB ? 		;最大值
	min  DB ?		;最小值
	inputMessage DB 'Input 10 2-digit number:',0DH,0AH,'$'
	maxMessage DB 0DH,0AH,'The max integer is:','$'
	minMessage DB 0DH,0AH,'The min integer is:','$'
data ends


code segment
	assume  cs:code,ds:data	 ;关联段地址寄存器与具体段
start:
	;把data段地址赋值给ds
	mov  AX,data		;data段名表示data段的段地址,常量
	mov  DS,AX
	
	;输出提示
	mov  DX,offset inputMessage
	mov  AH,9
	int  21H
	
	;输入10个两位数字,由ASCII码转换为二进制数,保存到变量BUF,同时找最大值、最小值
	mov  CX,10
	mov  BX,0
	mov  SI,0
input:	
	;两位数的十位数的处理
	;输入
	mov  AH,01H
	int  21H
	;由ASCII码转换为二进制数
	sub  AL,30H
	mov  AH,0
	;将两位数的十位数字*10
	mov  BL,10
	mul  BL		;将AL与BL相乘
	mov  DL,AL
	
	;两位数的个位数的处理
	;输入
	mov  AH,01H
	int  21H
	;由ASCII码转换为二进制数
	sub  AL,30H
	mov  AH,0
	
	;求得两位数数值,并保存到变量BUF
	add  AL,DL
	mov  BUF[SI],AL
	
	;判断是否第一次循环
	cmp  CX,10		
	je	 firstNumber
	;比较当前值与最小值
	cmp  AL,min
	jnl  ifGreater	;当前值更大实现跳转
	mov  min,AL		;当前值更小,更换min
	jmp  L1
firstNumber:
	mov  min,AL
	mov  max,AL
ifGreater:
	;比较当前值与最大值
	cmp  AL,max
	jng	 L1			;当前值更小实现跳转(无需替换最大值、最小值)
	mov	 max,AL		;当前值更大,更换max
	jmp  L1
L1:
	;准备下一次循环
	;输出空格
	mov  DL," "
	mov  AH,2
	int  21H
	inc  SI
	loop input

	;输出最大值、最小值
	;输出最大值提示字符串
	mov  dx,offset maxMessage
	mov  AH,9
	int  21H
	;1.求十位数字
	mov  AL,max
	mov	 AH,0
	mov	 BL,10		;除数
	div	 BL 		;商=AL,余数=AH
	add	 AL,30H		;把AL中的数转为相应字符
	;2.求个位数字
	add	 AH,30H		;个位数字字符
	;输出十位数字与个位数字
	mov	 DL,AL
	push AX
	mov	 AH,2
	int	 21H
	pop	 AX
	mov	 DL,AH
	mov	 AH,2
	int	 21H
	
	;输出最小值提示字符串
	mov  dx,offset minMessage
	mov  AH,9
	int  21H
	;1.求十位数字
	mov  AL,min
	mov	 AH,0
	mov	 BL,10		;除数
	div	 BL 		;商=AL,余数=AH
	add	 AL,30H		;把AL中的数转为相应字符
	;2.求个位数字
	add	 AH,30H		;个位数字字符
	;输出十位数字与个位数字
	mov	 DL,AL
	push AX
	mov	 AH,2
	int	 21H
	pop	 AX
	mov	 DL,AH
	mov	 AH,2
	int	 21H
	
	;程序退出
	mov	 AH,4cH
	int	 21H
code ends
end start

五、结果分析

5.1 实验结果

5.1.1 内容一运行结果

5.1.2 内容二运行结果

5.1.3 内容三运行结果

5.1.4 内容四运行结果

5.2 实验心得

这次是汇编语言的第二次实验。在上一次实验中,我已经熟练掌握了汇编语言的上机步骤以及DEBUG调试方法,因此这次实验的重点在于分支循环的设计、输入输出指令以及通过寄存器进行相关的数制转换。

对于分支循环的设计,因为与高级语言中的for、while思想类似,因此在理解和操作上并不困难。

对于输入输出指令,由于理论课上还没有介绍这方面的内容,所以在实验的前一天晚上我在网上查阅相关的输入、输出等指令操作进行自学。后来,在实验课上付峰老师又进行了非常细致地讲解,让我更加熟悉与掌握这块内容。其中,可以用mov AH,1、int 21H输入一个字符;用mov DL,AH、mov AH,2、int 21H输出一个字符;用变量名 DB '内容',0DH,0AH,'$'指令进行初始化,再利用 mov DX,offset 变量名、mov AH,9、int 21H来输出字符串。

对于数制转换中断指令,只有一位数据是非常方便的,转换成16进制既可以用加上30H的方法,又可以用and AL,0fH的方法。而对于多位数据转换则有些复杂,需要将数据保存至一个寄存器中进行高八位、低八位的计算,且高八位还需要进行相应的乘10操作,充当十进制中的十位数。四个实验内容下来,我发现这其中的数制转换存在相应的套路,通过上述程序,让我对于汇编语言进行数制转换也有一定熟悉。

而在这个实验中,中断指令以及数值转换都是为了用户更好交互,比如无提示信息,用户将不知道这里需要做什么,或者说如果输出的是ASCII码或者16进制,可能让我们程序员通过结果DEBUG也有点困难。

当然我对于汇编语言的指令:传送类、数据运算类、逻辑判断类、转移、循环等指令都有了更深入的了解。同时,我了解了系统功能调用的使用方法,如:使用01H功能号输入,使用02H功能号进行字符输出显示,使用09H功能号进行字符串输出显示。

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阮阮的阮阮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值