51汇编第三章第四章部分题目的参考答案

更新时间:2024-06-09 19:52:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第三部分 MCS-51汇编语言程序设计

3-1 对下述程序进行人工汇编。

ORG 2000H

CLR C MOV R2,#3 LOOP: MOV A,@RO ADDC A,@R1 MOV @R0,A INC R0 INC R1

DJNZ R2,LOOP JNC NEXT MOV @RO,#01H SJMP $ NEXT: DEC R0

SJMP $

解:首先可查出各指令的机器码,确定每条指令的起始地址。然后,再计算出相对转移指令的偏移量。结果如下:

2000H:C3 CLR C 2001H:7A 03 MOV R2,#3 2003H:E6 LOOP: MOV A,@RO 2004H:37 ADDC A,@R1 2005H:F6 MOV @R0,A 2006H:08 INC R0 2007H:09 INC R1 2008H:DA F9 DJNZ R2,LOOP 200AH:50 04 JNC NEXT 200CH:76 01 MOV @RO,#01H 200EH:80 FE SJMP $ 2010H:18 NEXT: DEC R0 2011H:80 FE SJMP $

(1)设R0=20H,R1=25H。若(20H)=80H,(21H)=90H,(22H)=A0H,(25H)=A0H,(26H)=6FH,(27H)=30H,则程序执行后,结果如何?

解:此程序执行三次加法,被加数存在以20H为首地址的单元,加数则存在以25H为首地址的单元。每次相加的结果如下:

(20H)=(20H)+(25H)+Cy=80H+A0H+0 =20H,Cy=1 (21H)=(21H)+(26H)+Cy=90H+6FH+1 =00H,Cy=1 (22H)=(22H)+(27H)+Cy=A0H+30H+1=D1H,Cy=0

程序将两个三字节相加,执行结果存在22H, 21H和20H中,结果为D1 00 20H。 (2)若27H单元内容改为6FH,则结果有何不同? 解:此时,第三次相加的结果有变化:

(22H)=A0H+6FH+01H=0IH,Cy=1。

由于最后相加后Cy=1,所以还使得(23H) =01,R0指向23H。表示两个3字节数相加后,和为4字

节数。结果等于01010020H。

3-2 试用除法指令编程,将两个存于20H单元内的BCD数变成ASCII码后存入21H和22H单元。并计算程序所占用的内存字节数和所需的机器周期数。

解:将20H内两个BCD数送到A,再将A的内容除以16,就相当于把A的内容右移4位,结果使A中保留一个BCD数,B中存入另一个BCD数,并且都是在低4位。然后使高4位分别变为3,就可变成ASCII码。程序如下:

字节数 机器周期数 MOV A,20H 2 1 MOV B,#10H 3 2 DIV AB 1 4 ORL A,#30H 2 1 MOV 21H,A 2 1 ORL B,#30H 3 2 MOV 22H,B 3 2 SJMP $ END

所以,程序所占内存为16字节,执行程序需13个机器周期。最后一条短转移指令只用来表示程序结束,真正执行时又是一条无限循环语句。所以,一般不计算这条指令的字节数和机器周期数。

3-3 将20H单元内两个BCD数相乘,要求积亦应为BCD数,并把积存入21H单元。 解:MCS-51系统中有乘法指令,但所完成的是两个8位二进制数的相乘,也就是积不是BCD数。因此相乘以后还要进行二进制数—BCD数的转换。由于两个BCD数相乘,积不会超过100。因此只须将乘积除以10,其商就是积的十位数,余数就是积的个位数。程序如下: MOV A,20H ; 两个BCD数送A

MOV B,#16 ; 准备A内容右移4位 DIV AB ;两个BCD数分别存入A,B MUL AB ;两个BCD数相乘,积为二进制数 MOV B,#10 ;准备除以10

DIV AB ;A中为十位数,B中为个位数 SWAP A ;十位数移至高4位 ORL A,B ;并入个位数 MOV 21H,A ;存结果 SJMP $ END

此题也可以不用乘法指令,而通过加法来完成。这也是完成BCD数乘法的一般方法。每次相加以后,通过十进制调整指令把和变为BCD数。这样经过多次循环,就可以得到所求的积,并且已经变成为BCD数了。程序如下:

MOV A,20H ; 两个BCD数送A MOV B,#16 ; 准备将两个BCD数分开 DIV AB ;两个BCD数分别存入A,B JZ NEXT ;若A=0,积为0 MOV R0,0 ;R0中存乘数 MOV R1,B ;R1中存被乘数 CLR A

LOOP:ADD A,R1 ;做循环加法

DA A ;对部分积作十进制调整 DJNZ R0,LOOP

NEXT:MOV 21H,A ;存结果

SJMP $ END

若仅从这个题目而言,当然是第一种解法效率高,执行时间短。但第二种解法提供了完成BCD数乘法的一般思路。

3-4 求16位带符号二进制补码的绝对值。16位数放在NUM和NUM + 1单元。求出的绝对值亦放在原数的单元内,低位先存。

解:只需先取出16位补码数的高8位,判别其符号位以确定正负。若为正数,则绝对值就是原数。若为负数,则求补以后可得绝对值。当然,这里应该是对16位数求补。有关程序如下:

NUM DATA 21H

MOV R0,#NUM+1 ;取高8位地址 MOV A,@R0 ;取高8位到A

JNB ACC.7,NEXT ;若为正数,绝对值即原数 CPL A ;若为负数,高8位求反 MOV @R0, A ;存入原单元 DEC R0 ;地址指向NUM单元 MOV A,@R0 ;取出低8位数 CPL A ;低8位求反 ADD A,#01H ;加1 MOV @R0, A ;存入原单元

JNC NEXT ;低8位加1无进位,则结束 INC R0 ;指向高8位地址 INC @R0 ;高8位加1 END

NEXT: SJMP $

3-5 求16位补码数所对应的原码。16位补码存放在COMP和COMP + 1单元。转换后的原码亦存于这两个单元。低8位先存。

解:此题的解法与上一题相似。只是对负数补码求原码时,符号位应仍保持为1,而将其余各位求反加一。具体做法当然有很多种,以下程序中是用异或指令来实现的。另外,求反加1的实现方法也用了与上题略有不同的方法。程序如下:

COMP DATA 21H

MOV R0,#COMP+1 ;指向高8位地址 MOV A,@R0 ;取出高8位数

JNB ACC.7,NEXT ;正数不用变换

XRL A,#7FH ;符号位不变,其余各位求反 MOV @R0, A ;送回COMP+1单元 DEC R0 ;指向COMP单元 MOV A,@R0 ;取出低8位数 CPL A ;求反 ADD A,#01H ;加1

MOV @R0, A ;送回COMP单元

INC R0 ;指向高8位地址 CLR A

ADDC A,@R0 ;高8位加进位 MOV @R0,A ;送回COMP+1单元

NEXT: SJMP $

END

3 -6从20H单元开始存放一组带符号数,其数目已存在1FH单元。要求统计出其中大于0、等于0和小于0的数的数目,并将结果分别存入ONE,TWO,THREE三个单元。

解:这是一个多分支程序。利用累加器判零条件转移指令以及位地址内容判1条件转移指令,就可以完成>0,=0或<0的判别。再编程时要注意不同分支之间不要发生交叉。程序如下:

ONE DATA 1CH TWO DATA 1DH THREE DATA 1EH

MOV R0,#20H ;数据块首地址 MOV R1,1FH ;取数据块长度到R1 MOV A,R1

JZ FINISH ;长度为0则结束 CLR A

MOV ONE,A ;计数单元清0 MOV TWO,A MOV THREE,A

LOOP: MOV A,@R0 ;取数 INC R0 ;修改地址指针 JZ NEXT2 ;A=0,转向NEXT2 JB ACC.7,NEXT3 ; A<0,转向NEXT3 INC ONE ;A>0,ONE单元加1 SJMP NEXT1

NEXT3: INC THREE ; A<0,THREE单元加1 SJMP NEXT1

NEXT2: INC TWO ;A=0,TWO单元加1 NEXT1: DJNZ R1,LOOP ;长度减1不为0则返回 FINISH:SJMP $ END

也可以用三个工作寄存器(如用R2,R3,R4)作为计数单元存放并统计A>O,A=0,A<0的数目。最后待循环结束统计完成后,把结果送入ONE,TWO, THREE单元即可。这样虽然多用一些寄存器,但一般而言,执行程序的速度可加快。

3-7 在内部数据存贮器中的X和Y单元各有一个带符号数,要求按照以下条件来进行运算,结果送入Z单元。(注:0算正偶数。)

解:一个8位带符号数的正负和奇偶都可以通过位检测指令来实现:正负可通过检测符号位

D7来决定:0为正数,1为负数;奇偶可通过检测最低位D0来决定:0为偶数,1为奇数。程序如下:

X DATA 20H Y DATA 21H Z DATA 22H MOV A,X

JNB ACC.0,EVEN ;偶数转EVEN JB ACC.7,NEG1 ;负奇数转NEG1 ADD A,Y ;正奇数则X+Y SJMP NEXT

NEG1: ORL A,Y ;负奇数则X∨Y SJMP NEXT

EVEN: JB ACC.7,NEG2 ;负偶数转NEG2 ANL A,Y ;正偶数则X∧Y SJMP NEXT

NEG2: XRL A,Y ;负偶数则X⊕Y NEXT: MOV Z,A

SJMP $

END

上述程序中,判断的顺序(奇偶、正负)可以有多种,因此程序的操作顺序(加、与、或等)也要变化。

3-8 在128分支程序中是用AJMP指令实现分支转移的。若用长转移指令LJMP来代替AJMP指令,以便子程序入口地址可在64KB范围内安排。试修改原来的程序,使之能适应新的要求。修改后的程序最多能有几个分支?

解:由于LJMP指令是3字节指令,所以在转移到分支表之前要对分支号(存于R3中)做一次乘3的操作。而用AJMP指令时是先执行一次乘2的操作。修改后的程序如下: MOV A,R3

RL A ;A←A×2 ADD A,R3 ; A←3×R3 MOV DPTR,#BRTAB ;分支表首地址送DPTR JMP @A+DPTR ;第一次转移

BRTAB: LJMP ROUT00 ;转移到第一个分支入口 LJMP ROUT01 ;转移到第二个分支入口 ┆

这样修改以后,分支的数目将有所变化。由千A中是8位无符号数,最大值为255,除以3以后的整数值为:255/3 = 85。所以最多只能有85个分支。而分支入口可以在64 kB范围内安排。 3-9 如果在上题的情况下,85个分支入口不够用,仍要求有128个分支,则应如何修改程序?

解:为了实现128个分支,R3中存放的分支号为0-127。R3的值乘以3以后可以分为两种情况,当R3≤85时,乘以3以后不产生进位,而当R3>85时,乘以3以后就会产生进位。因此可以安排两个分支转移表,即分支0到分支85为一个分支表,分支86到分支127为一个表。分别有各自的入口地址BRTAB1和BRTAB2。按照R3×3以后是否有进位来转移到不同的分支表。还应该注意的是当R3>85以后,乘以3以后的值(不计进位)不是0,3,6,?,而是2,5,8,?,因此,还要做一些调整。修改以后的程序如下:

MOV A,R3

解:因为是求最小值,所以初始化时应将MINI单元送入8位最大值0FFH。然后与数据区中的数据逐一比较,选出最小值。程序如下:

MINI DATA 20H LEN DATA 21H BLOCK DATA 22H

MOV R0,#BLOCK ;R0为地址指针 MOV R1,LEN ;长度置R1

MOV MINI,#0FFH ;MINI单元先置最大值 MOV A,RI ;检测长度 JZ FINI ;为零则结束 LOOP:MOV A,@R0 ;取一个数 INC R0 ;修改指针 CJNE A,MINI,00H ;A与(MINI)比较 JNC NEXT ;A≥(MINI),不代换 MOV MINI,A ;A<(MINI),(MINI)←A NEXT: DJNZ R1,IOOP FINI: SJMP $ END

3-18 在内部RAM的BLOCK单元的数据块内存放着若干带符号数,数据块长度存于LEN单元。要求对数据块内的正数和负数分别相加,相加的结果分别存入SUM1和SUM2单元。设相加的结果不超过8位二进制数。

解:只需用位条件转移指令判别数的正负后,分别相加。加法可以直接在SUM1和SUM2单元上进行,也可以用两个工作寄存器作为工作单元来进行。两者只是相令字节数有点差别,执行时间没有多少差别。程序如下:

SUM1 DATA 20H SUM2 DATA 21H LEN DATA 22H BLOCK DATA 23H

MOV R0,#BLOCK ;R0为地址指针 MOV R1,LEN ;R1为长度 MOV SUM1,#00H ;正数和先清0 MOV SUM2,#00H ;负数和先清0 MOV A,R1 ;检测长度 JZ FINI ;为零则结束 LOOP: MOV A,@R0 ;取一个数

INC R0 ;修改指针 JB ACC.7,NEXT1 ;负数转NEXT1 ADD A,SUM1 ;正数求和 MOV SUM1,A ;存部分和 SJMP NEXT2

NEXT1: ADD A,SUM2 ;负数求和

MOV SUM2,A ;存部分和

NEXT2: DJNZ R1,LOOP FINI: SJMP $

END

3-19 在3-18中,若相加结果超过8位二进制数,程序又该如何编写?

解:设正数和存于SUM1和SUM1+1两个单元,负数和存于SUM2和SUM2+1两个单元,都是低8位先存。相加时也要按16位相加:加正数时,高8位为全0;加负数时,高8位为全1。加高8位时当然要用ADDC指令。程序如下:

SUM1 DATA 20H SUM2 DATA 22H LEN DATA 24H BLOCK DATA 25H

MOV R0,#BLOCK ;R0为地址指针 MOV R1,LEN ;R1为长度 CLR A

MOV SUM1,A ;各个和单元清0 MOV SUM1+1,A MOV SUM2,A MOV SUM2+1,A

MOV A,R1 ;检测长度 JZ FINI ;为零则结束 LOOP: MOV A,@R0 ;取一个数

INC R0 ;修改指针 JB ACC.7,NEXT1 ;负数转NEXT1 ADD A,SUM1 ;正数低8位求和 MOV SUM1,A CLR A ADDC A,SUM1+1 MOV SUM1+1,A SJMP NEXT2

NEXT1: ADD A,SUM2 ;负数低8位和

MOV SUM2,A MOV A,SUM2+1

ADDC A,#0FFH ;负数高8位和 MOV SUM2+1,A

NEXT2: DJNZ R1,LOOP FINI: SJMP $ END

3-20 有10组三字节的被加数和加数,分别存放于从FIRST和SECOND开始的区域中。求这10组数的和,并将和存入以SUM开始的单元,低位先存。设和仍为三字节。

解:10组数有10组和。这样也需要3个地址指针分别指向被加数、加数以及和,设分别用R0, R1和R2。但R2是不能用来寄存器间接寻址的。以下程序中采用R1和R2交换内容的方法来解决这个问题。这样做不需要占用其它内存单元,可节省资源。当然,程序的指令数有所增加。如果内存资源不太紧张,则不一定采用这个方法。程序如下:

FIRST DATA 20H SECOND DATA 40H SUM DATA 60H

MOV R0,#FIRST ;被加数地址指针 MOV R1,#SECOND ;加数地址指针 MOV R2,#SUM ;和地址指针 MOV R4,#10 ;10组数 LOOP:MOV R3,#3 ;每组3字节 CLR C

LOOP1:MOV A,@R0 ;取被加数 ADDC A,@R1 ;加一个字节 XCH A,R1 ;开始R1与R2交换 XCH A,R2

XCH A,R1 ;完成R1与R2交换 MOV @R1,A ;存部分和 XCH A,R1 ;R1与R2再次交换 XCH A,R2

XCH A,R1 ;完成交换

INC R0 INC R1 INC R2

DJNZ R3,LOOP1 ;组内循环 DJNZ R4,LOOP ;10组数循环 SJMP $ END

3-21 在3-20题中,将求10组数的和变为求10组数的总和,试编写有关程序。设总和亦为三字节数。

解:由于是求10组数的总和,所以加完一组数以后,还要与以前的结果求和。这样也需要3个地址指针。只是被加数和加数的指针是连续修改的,和的指针移动2次以后又回到原来的位里。程序如下:

SUM DATA 20H FIRST DATA 23H SECOND DATA 43H CLR A

MOV SUM,A ;和单元清0 MOV SUM+1,A MOV SUM+2,A

MOV R1,#FIRST ;被加数地址指针 MOV R2,#SECOND ;加数地址指针 MOV R3,#10 ;10组数 LOOP:MOV R0,#SUM ;和的指针

MOV R4,#3 ;3个字节

CLR C

LOOP1:MOV A,@R0 ;取部分和

ADDC A,@R1 ;加倍加数一个字节 MOV @R0,A ;送回 INC R0

INC R1

DJNZ R4,LOOP ;加3个字节 MOV R0,#SUM MOV R4,#3 CLR C

PUSH 01H ;保存R1的值 PUSH 02H

POP 01H ;R2的值送入R1

LOOP2: MOV A,@R0 ;取部分和

ADDC A,@R1 ;加加数一个字节 MOV @R0,A ;送回 INC R0 ;修改指针

INC R1

DJNZ R4,LOOP2 ;加3个字节 PUSH 01H ; R1的值入栈 POP 02H ;送回R2 POP 01H ;恢复R1

DJNZ R3,LOOP ;加10组数 SJMP $ END

3-22 在3-21题中,若和超过三个字节,应如何编写程序。

解:按题意,和单元需4个字节。加完3个字节后,取决于有无进位,安排第4个和单元是否进行加1操作。程序如下:

SUM DATA 20H FIRST DATA 24H SECOND DATA 44H CLR A

MOV SUM,A ;和单元清0 MOV SUM+1,A MOV SUM+2,A MOV SUM+3,A

MOV R1,#FIRST ;被加数地址指针 MOV R2,#SECOND ;加数地址指针 MOV R3,#10 ;10组数 LOOP:MOV R0,#SUM ;和的指针

MOV R4,#3 ;3个字节

CLR C

LOOP1:MOV A,@R0 ;取部分和

ADDC A,@R1 ;加被加数一个字节 MOV @R0,A ;送回 INC R0

INC R1

DJNZ R4,LOOP1 ;加3个字节 JNC NEXT1 ;无进位转NEXT1

INC SUM+3 ;有进位SUM+3单元加1

NEXT1: MOV R0,#SUM

MOV R4,#3 CLR C

PUSH 01H ; R1进栈 PUSH 02H ;R2进栈 POP 01H ;R2的值送入R1

LOOP2: MOV A,@R0 ;取部分和

ADDC A,@R1 ;加上加数一个字节 MOV @R0,A

INC R0 ;修改指针

INC R1

DJNZ R4,LOOP2 ;加3个字节 JNC NEXT2 ;无进位则转移 INC SUM+3 ;有进位SUM+3单元加1

NEXT2: PUSH 01H ; R1的值入栈,实际为R2值

POP 02H ;送回给R2 POP 01H ;恢复R1

DJNZ R3,LOOP ;加10组数 SJMP $ END

3-23 若累加器A中存放的是一个16进制数,将它转换为相应的ASCII码,并将结果存入RAM的20H单元。若A中不是16进制数,则将20H单元置为FFH。试编写有关程序。

解:用查表程序来完成此转换,编程最为简单。设A中存放的16进制数放在低4位。

CJNE A,#10H,00H

JNC NEXT1 ;A≥10H,不是16进制数 ADD A,#8 ;是16进制数,准备查表 MOVC A,@A+PC ;查表 SJMP NEXT2

NEXT1: MOV A,#0FFH NEXT2: MOV 20H,A

SJMP $

ASCTAB: DB ‘0,1,2,3,4’ DB ‘5,6,7,8,9’ DB ‘A,B,C,D,E,F’ END

3-24 在内部RAM的DATAD开始的区域存放有10个单字节十进制数(内含两位BCD数),试编一程序求其累加和,设和将超过2位BCD数,即可能为3位BCD数。结果存入SUM和SUM+1单元(低位先存)。

解:此题可直接进行十进制相加:执行加法指令以后作一次十进制调整。而百位数不需作十进制调整,因为总和不会大于990。程序如下:

SUM DATA 20H DATAD DATA 22H MOV R0,#DATAD

MOV R1,#10

MOV SUM,#00H

MOV SUM+1, #00H LOOP:MOV A,@R0 INC R0 ADD A,SUM

DA A ;十进制调整 MOV SUM,A JNC NEXT

INC SUM+1

NEXT: DJNZ R1,LOOP SJMP $ END

3-25 若题3-24中改为对10个双字节十进制数(4个十进数)求和,结果仍存入以SUM开始的单元,低位先存。试编写相应的程序。

解:此题程序与上一题相似。只是多嵌套一次字节循环。若是十进制数的字节数再增加,也只需修改一下字节循环的次数(以下程序中R2的值)。程序如下:

SUM DATA 20H DATAD DATA 23H MOV R0,#DATAD CLR A

MOV SUM,A ;和单元清零

MOV SUM+1, A MOV SUM+2,A

MOV R3,#10 ;10个数 LOOP:MOV R1,#SUM

MOV R2,#2 ;2个字节 CLR C LOOP1:MOV A,@R0 ADDC A,@R1

DA A ;十进制调整 JNC R0

INC R1

DJNZ R2,LOOP1 JNC NEXT INC @R1

NEXT: DJNZ R3,LOOP SJMP $ END

3-26 编写一段程序,模拟如图3-1所示逻辑电路的逻辑功能。要求将4输入与非门的功能模拟先写成一个子程序,然后多次调用以得到整个的电路的功能模拟。设X,Y,Z和W都已定义为位地址,若程序中还需要其他位地址,也可以另行定义。

解:除了用伪指令BIT定义输入X,Y,Z,W和输出F之外,还定义F1和F2为两个中间结果。子程序中4个输入端定义为A1,A2,A3和A4。调用时,只需将相应的输入值存入这4个位地

址即可。程序如下:

X BIT 20.0H

Y BIT 20.1H Z BIT 20.2H W BIT 20.3H F BIT 20.4H A1 BIT 21.0H A2 BIT 21.1H A3 BIT 21.2H A4 BIT 21.3H F1 BIT 21.4H F2 BIT 21.5H

START: MOV C,X

MOV A1,C ;A1=Y MOV C,Y

MOV A2,C ;A2=Y MOV C,Z CPL C MOV A3,C ;A3=MOV C,W

MOV A4,C ;A4=W ACALL NAND

MOV F1,C ;F1=CPL A3 ;A3=Z SETB A4 ;A4=1 ACALL NAND MOV F2,C ;F2=CPL A2 ;A2=MOV C,W

MOV A3,C ;A3=2 ACALL NAND ;C=MOV A1,C MOV C,F1 MOV A2,C MOV C,F2 MOV A3,C ACALL NAND

MOV F,C ;F=

SJMP $ NAND:MOV C,A1 ANL C,A2 ANL C,A3 ANL C,A4 CPL C ;C= RET END

3-27 编写模拟与非门构成的

由P1.0和P1.1输入,输出Q和否则P1.4置0。

触发器的程序。设,

分别为P1.2和P1.3。若出现输出不定的情祝,则置位P1.4,

触发器的逻辑图如图3-2所示。

==0时输出不定。实际上,当

==0

解:根据一般书籍上的逻辑功能,都认为当时,输出Q和=0变为

都为1,并非不定,只是不符合输出应该互补的输出特征。只有当输入由

==1时,才真正出现输出状态的不确定,即不能确定是Q=1,=0还是Q=0,

=1。编程时要注意符合以上特点。假定模拟是连续的。程序如下:

LOOP: ORL P1,#03H ; P1.0,P1.1为输入状态

MOV A,P1 ;输入ANL A,#03H ;输出JZ IN00 ; MOV R2,A ;暂存 XRL A,#03H ;判断JZ IN11 ;

,

==0,转移

,是否都为1 ==1,转移

CLR P1.4 ;不定标志置0 MOV A,R2 ;恢复A值 RRC A ;取JNC IN01 ;

值到Cy =0,转移

SETB P1.2 ; =0,Q=1 CLR P1.3 ;

=0

SJMP LOOP ;转下一次读入

IN01: CLR P1.2 ;

SETB P1.3 ;

=0,Q=0 =1

SJMP LOOP ;转下一次读入

IN00: CLR P1.4 ;不定标志清0

SETB P1.2 ;

=0,=0,Q=1

SETB P1.3 ;也为1 SJMP LOOP

IN11: MOV A,P1

ANL A,#OCH ;取出Q,

=1

XRL A,#0CH ;判断是否Q=

JZ NEXT ;都为1,转移 SJMP LOOP ;不都为1,Q,

NEXT: SETB P1.4 ;置位不定标志 SJMP LOOP END

3-28 用查表法求1.0-9.9的平方值。原数存在DAT单元,高4位为整数部分,低4位为小数

不变

部分。查表结果存入RESU和RESU+1两个单元,RESU单元存整数部分,RESU + 1单元存小数部分。试编写有关程序。

解:1.0-9.9的平方数构成一张二维的表格,共有10行20列共200个元素。因为每个平方数都有整数和小数部分,分别应用两个单元(表中的两个相邻元素)来存放,整数先存。在查这种二维表时,要先经过简单计算得出查表的位置,然后再去查表,比查一维表要稍复杂一些。有关程序如下:

DAT DATA 20H RESU DATA 21H

MOV R0,#DAT ; 原数的地址存R0 CLR A

XCHD A,@R0 ; 取出小数部分 MOV R2,A ;R2存小数 MOV A,@R0 ;再取整数 SWAP A

ANL A,#0FH ;只要低4位整数 DEC A

MOV B,#20 ;每行20个元素 MUL AB MOV R3,A ;暂存 MOV A,R2 ;取出小数 RL A ;乘以2 ADD A,R3 ;求出查表位置 MOV R3,A ;暂存 MOV DPTR,#TAB ;表首地址 MOVC A,@A+DPTR ;查得整数部分 MOV RESU,A ;存入 MOV A,R3

INC A ;下一个查表位置 MOVC A,@A+DPTR MOV RESU+1,A SJMP $

TAB: DB 1,0,1,21,?,3,61 DB 4,0,4,41,?,8,41 DB 9,0,9,61,?,15,21 ?

DB 81,0,82,81,?,98,1 END

3-29 大学某班有学生NUM人,已经学过了COURSE门课程,有一个成绩单为NUM行,COURSE列。设每门课程都用一个序号来代表,如数学、物理、化学、?,其代号分别为0,1,2,?。编制一个程序可以累计任何一门课程的总成绩,被统计课程代号存放在寄存器R2中,统计结果存入寄存器R4和R5中。设学生数小于100,所以单科成绩总分小于10000。

解:这时,成绩单中的项数可以超过256,所以不能简单地设定DPTR为表格首地址,只改变A的数值,再用MOVC A,@A+DPTR指令来查表。因为A的值只能为0-255,需要根据R2中给定的科目代号以及学生的序号来算出查表的位置,然后迭加在表格首地址上,再来进行查表。当然,

因为没有16位加法指令,DPTR要分为高低两个8位来相加。程序中用R2存查表项的列号,R3存查表项得行号。程序如下:

TERM EQU 10 ;被统计课程代号 NUM EQU 50 COURDE EQU 15

MOV R2,#TERM ;R2存列号 CLR A

MOV R3,A ;R3存行号 MOV R4,A ;总成绩先为0 MOV R5,A

MOV R6, #NUM ;循环NUM次

LOOP: ACALL PICK ;调用查表子程序 CLR C

ADD A,R4 ;累加成绩低位 DA A MOV R4,A CLR A

ADDC A,R5 ;累加成绩高位 DA A MOV R5,A

INC R3 ;到下一行再查表

DJNZ R6,LOOP

SJMP $

PICK: MOV DPTR,#TAB ;表格首地址 MOV A,R3 MOV B,#COURSE MUL AB ADD A,DPL MOV DPL,A MOV A,B ADDC A,DPH MOV DPH

MOV A,R2 ;再加上列号 MOVC A,@A+DPTR ;查表 RET

3-30 编写16位无符号数除以8位无符号数的除法程序。被除数存于R1R0中,R1为高8位,除数存于R2中。运算后,商存于R0中,余数存于R1中。除数为0则置OVER单元为1。

解:按照题意,商为8位,故只需执行8次循环比较,也意味着被除数的高8位一定小于除数。然后就可以按照“左移相减”方法来进行比较。即将被除数左移一位以后,取出高9位来与除数相减(比较),若够减则商为1,并将差值(余数)代替被除数高8位。若不够减则商为0,被除数高8位不修改。然后左移一位进行下一次比较,直到得到8位商为止。程序如下:

OVER DATA 20H

MOV OVER,#00H ;复位溢出标志 MOV A,R2 ;取除数

JNZ START ;除数不为0则开始 MOV OVER,#01H ;置位溢出标志 SJMP $ ;结束 START:MOV R3,#08H ;8次循环 LOOP: CLR C

MOV A,R0 ;被除数低8位 RLC A MOV R0,A

MOV A,R1 ;被除数高8位

RLC A MOV R1 MOV F0 CLR C SUBB A JNC NEXT ; JNB F0NEXT1: MOV R1 INC R0NEXT: DJNZ R3 SJMP $ END

,A ,C

,R2 ;,NEXT

,A ;

,LOOP ; 与除数比较 大于等于除数转移 余数送回 不够8次,返回

本文来源:https://www.bwwdw.com/article/e4w6.html

Top