解:因为是求最小值,所以初始化时应将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