一、 实验要求
- 用汇编实现冒泡排序算法。
- 在实验三的代码基础上,利用冒泡排序将DEST中数据从小到大重新排序 。
- 将冒泡排序算法写成子程序。
- 在主程序中,通过设置参数,使用同一个子程序实现从大到小,从小到大排序的自由选择。
二、 实验设计
1. 整体思路
(a)先将片外(DEST)的数据转到片内
(b)在片内进行冒泡函数操作,然后重新将值复制到片外
3.流程图
图2-1 ;流程图
3.主要模块设计思路及分析
(1)INSET模块(复制到片内)
将DEST的值正序复制进来,复制一轮之后,分别递增片内和片外的指针,通过DJNZ操作递减判断(执行NUM次结束),此时片内的值和片外一样,我们就可以在片内进行冒泡函数操作
(2)OUTSET(复制到片外展示结果)
调用完冒泡函数之后,片内的值就是相应要求的顺序。依次将片内的值复制出去,然后分别递增片内和片外的指针,通过DJNZ操作递减判断(执行NUM次结束),此时片外的值和片内一样,结果就再次展示到片外了
(3)ORDERS
a)通过标志位(7AH)的值判断进行从小到大还是从大到小排列
b)以从小到大举例:
i.初始化排序过程:
- MOV A, #30H:将常数0x30存储到累加寄存器A中。
- MOV R1, A:将A中的值加载到寄存器R1中,R1现在包含要排序的数据的地址。
- MOV A, R2:将寄存器R2中的值加载到A中,通常这是数据集的大小。这个值减1将在后续的比较中使用。
- DEC A:将A中的值减1,将结果存储在A中,这是后续比较的次数。
- MOV R5, A:将A中的值加载到寄存器R5中,R5现在包含了剩余比较的次数。
- CLR 8AH:清除标志位F0,用于标记是否发生了交换。
ii.进入排序循环(LOOP):
- MOV A, @R1:将R1指向的内存地址的值加载到A中,即加载当前位置的元素值。
iii.比较和交换:
- MOV R3, A:将A中的值复制到寄存器R3,这是当前轮次的最大值。
- INC R1:将R1的值加1,将指针指向下一个元素。
- CLR C:清除进位标志。
- MOV A, @R1:将R1指向的内存地址的值加载到A中,即加载下一个位置的元素值。
- SUBB A, R3:用R3的值减去A,结果存储在A中。这一步的目的是比较两个元素的大小,如果A > R3,没有借位,跳转到LOOP1;如果A < R3,发生了借位,需要交换元素。
iiii.借位发生,即需要交换元素:
- SETB 8AH:设置标志位F0,表示发生了交换。
- MOV A, R3:将R3的值加载到A中,即将大的值放到A中。
- XCH A, @R1:交换A和R1指向的内存地址的值,将大的值放到后一个位置。
- DEC R1:将R1的值减1,将指针回到原来的位置。
- XCH A, @R1:再次交换A和R1指向的内存地址的值,将小的值放到前一个位置。
- INC R1:将R1的值加1,指针回到原来的位置。
iiiii.继续循环(LOOP1):
- MOV A, @R1:将R1指向的内存地址的值加载到A中,即加载当前轮次最大的值。
- DJNZ R5, LOOP:如果R5不等于0,继续下一轮循环,否则执行下一步。
iiiiii.排序完成或需要重新开始:
- JB 8AH, SORT:检查标志位F0,如果它被设置,表示发生了交换,需要重新开始排序,跳转到SORT标签。
- RET:如果没有设置F0,表示排序已完成,返回。
c)从大到小同理
三、实现效果
图3-1 从大到小排列
图3-2 从小到大排列
四、总结
在进行冒泡操作时,我想直接在片外通过DPTR数据指针操作,但是执行到一些需要指针后移的时候,我发现并没有这样的指针,所以我将数据全部复制到片内之后,通过寄存器指针来进行操做。最后再将结果又复制到外面。
附录代码:
ORG 0000H
LJMP MAIN
ORG 2000H
MAIN:
SRC DATA 30H
DEST XDATA 2000H
NUM DATA 20H
MOV A,#01H ;将累加器里面设置默认值1
MOV R0,#SRC ;保存SRC起始地址
MOV DPTR,#DEST ;保存DEST起始地址
MOV R2,#NUM ;保存字节数量
MOV R3,#NUM ;存入片内或者片外RAM都要用,所以保存两次
ACALL IN
DEC R0 ;IN子程序中R0最后多加了一次,要减一。即最后一位的地址是49
ACALL OUT
MOV DPTR,#DEST ;进行复制片内操作,因为DPYR没有递减操作
MOV R0,#SRC
MOV R2,#NUM
ACALL INSET
MOV R2,#NUM ;调用冒泡函数
SETB 7AH ;将7AH标志位置1,从大到小排列
ACALL ORDERS
MOV DPTR,#DEST ;进行复制到片外操作,展示出来
MOV R0,#SRC
MOV R2,#NUM
ACALL OUTSET
MOV R2,#NUM
CLR 7AH ;将7AH标志位置0,从小到大排列
ACALL ORDERS ;调用冒泡函数
MOV DPTR,#DEST ;进行复制到片外操作
MOV R0,#SRC
MOV R2,#NUM
ACALL OUTSET
SJMP $
IN: ;向片内RAM存储
MOV @R0,A ;将A的值'01H'给到R0地址处
INC R0 ;递增R0地址
ADD A,#01H ;依次递增A的数据
DJNZ R2,IN ;重复循环,当NUM字节的数被写完了,就不在循环
RET
OUT: ;逆序向片外RAM存储
MOV A,@R0 ;将R0地址处的数据给到A
DEC R0 ;依次递减R0
MOVX @DPTR,A ;把A里面的值给到外部RAM里面,它的起始地址是2000H
INC DPTR ;依次递增扩展地址
DJNZ R3,OUT ;当所有值复制完了之后,就不在循环
RET
//把片外的内容给进片内操作
INSET:
MOVX A,@DPTR ;把2000H的值给A
MOV @R0, A ;把片外的值给进来R0
INC DPTR
INC R0
DJNZ R2,INSET
RET
//把片内的内容给进片外操作
OUTSET:
MOV A,@R0
MOVX @DPTR, A
INC DPTR
INC R0
DJNZ R2,OUTSET
RET
ORDERS:
JNB 7AH,SORT ;标志位为0,执行从小到大的排列
JB 7AH,SORT2 ;标志位为1,执行从大到小的排列
RET
SORT:
; 初始化排序过程
MOV A, #30H ;R1里面存放第一个地址
MOV R1, A ;R1=30H
MOV A, R2 ; A=R2-1,一个数在一个轮回需要比较R2-1次
DEC A
MOV R5, A ; 将A的值给R5
CLR 8AH ; 清除标志位F0
MOV A, @R1 ; 将30H地址处的值给A
LOOP:
MOV R3, A ; 初始时将30H地址处的值给R3。后面把当前的最大值给R3
INC R1 ; R1加一,地址向后移
CLR C ; 清除进位标志
MOV A, @R1 ; A存放后面一个地址的值
SUBB A, R3 ; A = A - R3
JNC LOOP1 ; 如果没有借位(即第二数大于第一个数),跳转到LOOP1
//借位发生了,前面的数大于后面的数,执行以下操作
SETB 8AH ; 设置标志位F0,
MOV A, R3 ; 把R3的值给A(即将大值给A)
XCH A, @R1 ; 交换A和内存[R1]的值,即把大的值向后移
DEC R1 ; R1 = R1 - 1,将指针前移
XCH A, @R1 ; 再次交换A(此时A里面的值被换成小的值了)和内存[R1]的值,将较小的值放到前面
INC R1 ; R1 = R1 + 1,指针回到原来的位置
LOOP1:
MOV A, @R1 ; 没有借位时R1地址处的值时最大的,把大的值给A
DJNZ R5, LOOP ; 如果R5不等于0,跳转到LOOP
JB 8AH, SORT ; 如果标志位F0被设置,跳转到排序函数的重新开始
RET ; 返回
SORT2:
; 初始化排序过程
MOV A, #30H ;R1里面存放第一个地址
MOV R1, A ;R1=30H
MOV A, R2 ; A=8,一个数在一个轮回需要比较8次
DEC A
MOV R5, A ; 将A的值给R5
CLR 8AH ; 清除标志位F0
MOV A, @R1 ; 将30H地址处的值给A
LOOPA:
MOV R3, A ; 初始时将30H地址处的值给R3。后面是把当前较小的值给R3
INC R1 ; R1加一,地址向后移
CLR C ; 清除进位标g志
MOV A, @R1 ; A存放后面一个地址的值
SUBB A, R3 ; A = A - R3
JNC LOOPB ; 如果没有借位(即第二数大于第一个数),跳转到LOOP1
//借位发生了,前面的数大于后面的数,执行以下操作
MOV A, @R1 ;重新把R1地址的值给A,因为减法操作把之前的值覆盖了
DJNZ R5, LOOPA
JB 8AH, SORT2
RET
LOOPB:
SETB 8AH ; 设置标志位F0,
MOV A, @R1 ;重新把R1地址的值给A,因为减法操作把之前的值覆盖了
DEC R1 ;R1指针前移
XCH A,@R1 ;把较大值前移,此时A里面存放较小值
INC R1 ;R1指针加一,回到刚才的位置
XCH A,@R1 ;再次交换,把较小值覆盖当前R1地址处的值,此时A变成了那个较大的值了
XCH A,R3 ;把A与R3交换,即把之前前面的值挪到后面了,A也要存放这个值,以免影响后续操作
DJNZ R5, LOOPA ; 如果R5不等于0,跳转到LOOP
JB 8AH, SORT2 ; 如果标志位F0被设置,跳转到排序函数的重新开始
END